在 T-SQL XML value() 中使用属性变量的问题
Issue using attribute variable in T-SQL XML value()
DECLARE @NodePath VARCHAR(20) = 'C',
@NodeVariable VARCHAR(20) = '@name',
@result XML;
SET @result = '
<A>
<B>
<C name="Name01"/>
</B>
<B>
<C name = "Name02"/>
</B>
</A>
'
SELECT T.c.value('sql:variable("@NodeVariable")', 'VARCHAR(20)')
FROM @result.nodes('//*[local-name()=sql:variable("@NodePath")]') T(c)
我想获取XML的属性,比如:
|Name|
|Name01|
|Name02|
但结果是:
|Name|
|@name|
|@name|
如何解决这个问题?由于我想创建一个将路径和属性名称作为参数的函数,因此 OPENXML
函数是不允许的。
在 value()
函数中,您需要使用 @*[local-name()=...]
语法,例如:
declare @NodePath nvarchar(20) = 'C';
declare @NodeVariable nvarchar(20) = 'name';
declare @result xml =
N'<A>
<B>
<C name="Name01"/>
</B>
<B>
<C name = "Name02"/>
</B>
</A>'
select x.n.value('(@*[local-name()=sql:variable("@NodeVariable")])[1]', 'nvarchar(20)') as 'Name'
from @result.nodes('//*[local-name()=sql:variable("@NodePath")]') x(n)
产生:
Name
------
Name01
Name02
更简单一点的可能是:
SELECT x.n.value('.', 'nvarchar(20)') as 'Name'
FROM @result.nodes('/A
/B
/*[local-name() =sql:variable("@NodePath")]
/@*[local-name()=sql:variable("@NodeVariable")]') x(n)
简而言之:
- 深入
<B>
(或者使用 深度搜索 和 //
如果你能确定,不会有 <C>
在任何其他地方)
- 查找任何具有给定名称的元素
- 选择具有给定名称的属性(每个元素每个定义的属性都是单例的)
- 在当前节点上使用
value()
到return内容。
什么可能会干扰此:<C>
多次出现在 <B>
以下
更新 XPath 和 local-name()
的一些补充
试试这个:
declare @result xml =
N'<A>
<B>
<C name="Name01"/>
</B>
<TheSecondInA />
<B>
<C name = "Name02"/>
</B>
<OneMore someAttr="x" oneMoreAttr="y" theLastAttr="z" >SomeText</OneMore>
</A>';
SELECT @result.value('local-name((//TheSecondInA)[1])','varchar(100)')
,@result.value('local-name((/A/*[2])[1])','varchar(100)')
,@result.value('local-name(/A[1]/*[2])','varchar(100)')
,@result.value('local-name((//*[@someAttr]/@*[2])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/@*[3])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/@*[last()])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/text())[1])','varchar(100)')
,@result.value('local-name((/DoesNotExist)[1])','varchar(100)')
如您所见,函数 local-name()
必须获得 单例 XPath.
- 深度搜索 深入到命名节点的第一次出现
- 同样是由
<A>
下面的第二个元素编辑的return
- 如果路径本身保证 return 一个单例,我们不需要这个
(SomeXpath)[1]
。
- 这里我们深入到第一个元素,其中有一个名为
someAttr
的属性,并根据其位置选择第二个属性。
- 同样,我们可以在给定路径上选择第三个属性
- 要获取最后一个属性(或元素),我们可以使用
last()
- 如果当前节点是一个
text()
节点,或者如果该元素不存在,我们返回一个空字符串。
提示:使用类似的 XPath 表达式,您可以使用 .value()
检索本地内容,.exist()
测试是否存在(或不存在)并修改给定位置...
DECLARE @NodePath VARCHAR(20) = 'C',
@NodeVariable VARCHAR(20) = '@name',
@result XML;
SET @result = '
<A>
<B>
<C name="Name01"/>
</B>
<B>
<C name = "Name02"/>
</B>
</A>
'
SELECT T.c.value('sql:variable("@NodeVariable")', 'VARCHAR(20)')
FROM @result.nodes('//*[local-name()=sql:variable("@NodePath")]') T(c)
我想获取XML的属性,比如:
|Name|
|Name01|
|Name02|
但结果是:
|Name|
|@name|
|@name|
如何解决这个问题?由于我想创建一个将路径和属性名称作为参数的函数,因此 OPENXML
函数是不允许的。
在 value()
函数中,您需要使用 @*[local-name()=...]
语法,例如:
declare @NodePath nvarchar(20) = 'C';
declare @NodeVariable nvarchar(20) = 'name';
declare @result xml =
N'<A>
<B>
<C name="Name01"/>
</B>
<B>
<C name = "Name02"/>
</B>
</A>'
select x.n.value('(@*[local-name()=sql:variable("@NodeVariable")])[1]', 'nvarchar(20)') as 'Name'
from @result.nodes('//*[local-name()=sql:variable("@NodePath")]') x(n)
产生:
Name
------
Name01
Name02
更简单一点的可能是:
SELECT x.n.value('.', 'nvarchar(20)') as 'Name'
FROM @result.nodes('/A
/B
/*[local-name() =sql:variable("@NodePath")]
/@*[local-name()=sql:variable("@NodeVariable")]') x(n)
简而言之:
- 深入
<B>
(或者使用 深度搜索 和//
如果你能确定,不会有<C>
在任何其他地方) - 查找任何具有给定名称的元素
- 选择具有给定名称的属性(每个元素每个定义的属性都是单例的)
- 在当前节点上使用
value()
到return内容。
什么可能会干扰此:<C>
多次出现在 <B>
更新 XPath 和 local-name()
的一些补充
试试这个:
declare @result xml =
N'<A>
<B>
<C name="Name01"/>
</B>
<TheSecondInA />
<B>
<C name = "Name02"/>
</B>
<OneMore someAttr="x" oneMoreAttr="y" theLastAttr="z" >SomeText</OneMore>
</A>';
SELECT @result.value('local-name((//TheSecondInA)[1])','varchar(100)')
,@result.value('local-name((/A/*[2])[1])','varchar(100)')
,@result.value('local-name(/A[1]/*[2])','varchar(100)')
,@result.value('local-name((//*[@someAttr]/@*[2])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/@*[3])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/@*[last()])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/text())[1])','varchar(100)')
,@result.value('local-name((/DoesNotExist)[1])','varchar(100)')
如您所见,函数 local-name()
必须获得 单例 XPath.
- 深度搜索 深入到命名节点的第一次出现
- 同样是由
<A>
下面的第二个元素编辑的return
- 如果路径本身保证 return 一个单例,我们不需要这个
(SomeXpath)[1]
。 - 这里我们深入到第一个元素,其中有一个名为
someAttr
的属性,并根据其位置选择第二个属性。 - 同样,我们可以在给定路径上选择第三个属性
- 要获取最后一个属性(或元素),我们可以使用
last()
- 如果当前节点是一个
text()
节点,或者如果该元素不存在,我们返回一个空字符串。
提示:使用类似的 XPath 表达式,您可以使用 .value()
检索本地内容,.exist()
测试是否存在(或不存在)并修改给定位置...