我需要帮助将XML路径通过变量传递给nodes()方法。我查看了几个不同的帖子,发现可以使用local-name
和sql:variable
传递节点。以下示例按预期工作:
DECLARE @XML_Path VARCHAR(MAX)
, @XML_In XML
SET @XML_Path = 'GetData'
SET @XML_In =
'
<GetData>
<test>234</test>
</GetData>
'
--THIS WORKS
SELECT Item_Idx = Nodes.value('(test)[1]' ,'INT')
FROM @XML_In.nodes('/*[local-name()=sql:variable("@XML_Path")]') Results(Nodes)
但是,当我尝试传递路径而不是单个节点时,它不起作用:
SET @XML_Path = 'GetData/Hello'
SET @XML_In =
'
<GetData>
<Hello>
<test>234</test>
</Hello>
</GetData>
'
--THIS DOES NOT WORK
SELECT Item_Idx = Nodes.value('(test)[1]' ,'INT')
FROM @XML_In.nodes('/*[local-name()=sql:variable("@XML_Path")]') Results(Nodes)
我需要能够在路径的另一部分之前传递路径,该路径始终是常量。所以,在我的例子中,&#34;测试&#34;部分总是相同的,但它上面的路径会有所不同。
我怀疑local-name
不是这样做的方法。但是我有不同的方法吗?
任何帮助都将不胜感激。
我考虑过使用动态SQL,但此代码将在UDF中使用,返回结果表。
修改:
我相信我不清楚自己要做什么。我需要能够将不同的XML路径传递给使用它们来粉碎XML的函数。
示例1
DECLARE @XML_In XML
SELECT @XML_In =
'
<RootNode1>
<ExtraNode1>
<Items>
<ExampleItem>
<SomeNode>100</SomeNode>
<Attributes>
<ID>1</ID>
<Name>a</Name>
<Value>123a</Value>
</Attributes>
</ExampleItem>
<ExampleItem>
<SomeNode>200</SomeNode>
<Attributes>
<ID>2</ID>
<Name>b</Name>
<Value>234</Value>
</Attributes>
</ExampleItem>
<ExampleItem>
<SomeNode>300</SomeNode>
<Attributes>
<ID>3</ID>
<Name>c</Name>
<Value>345</Value>
</Attributes>
</ExampleItem>
</Items>
</ExtraNode1>
</RootNode1>
'
SELECT SomeNode = Nodes.value('(../SomeNode)[1]' ,'INT')
, ID = Nodes.value('(ID)[1]' ,'INT')
, Name = Nodes.value('(Name)[1]' ,'VARCHAR(100)')
, Value = Nodes.value('(Value)[1]' ,'NVARCHAR(MAX)')
FROM @XML_In.nodes('/RootNode1/ExtraNode1/Items/ExampleItem/Attributes') Results(Nodes)
示例2
DECLARE @XML_In XML
SELECT @XML_In =
'
<Example2Root>
<Entries>
<Entry>
<SomeNode>100</SomeNode>
<Fields>
<ID>1</ID>
<Name>a</Name>
<Value>123a</Value>
</Fields>
</Entry>
<Entry>
<SomeNode>200</SomeNode>
<Fields>
<ID>2</ID>
<Name>b</Name>
<Value>234</Value>
</Fields>
</Entry>
<Entry>
<SomeNode>300</SomeNode>
<Fields>
<ID>3</ID>
<Name>c</Name>
<Value>345</Value>
</Fields>
</Entry>
</Entries>
</Example2Root>
'
SELECT SomeNode = Nodes.value('(../SomeNode)[1]' ,'INT')
, ID = Nodes.value('(ID)[1]' ,'INT')
, Name = Nodes.value('(Name)[1]' ,'VARCHAR(100)')
, Value = Nodes.value('(Value)[1]' ,'NVARCHAR(MAX)')
FROM @XML_In.nodes('/Example2Root/Entries/Entry/Fields') Results(Nodes)
我希望能够将路径传递给函数,以便它可以执行此操作并将其作为表返回:
SELECT SomeNode = Nodes.value('(../SomeNode)[1]' ,'INT')
, ID = Nodes.value('(ID)[1]' ,'INT')
, Name = Nodes.value('(Name)[1]' ,'VARCHAR(100)')
, Value = Nodes.value('(Value)[1]' ,'NVARCHAR(MAX)')
FROM @XML_In.nodes('SOME_PATH') Results(Nodes)
但我不知道如何使用路径参数。路径大多数时候会不同。
答案 0 :(得分:1)
您不想更改整个函数,只需更改XQuery中的路径。这是 - 如你所知 - 不可能。
但是:您似乎在不同的结构中找到相同的数据。至少您似乎知道,您会在节点ID
下方找到名为Name
,Value
和SomeNode
的节点...
因此,这种方法可能会以完全不同的方式解决您的问题...它至少可以用您的两个给定示例...
SELECT p.*
FROM
(
SELECT Nd.value('.','int') AS SomeNode
,Deeper.value('local-name(.)','nvarchar(max)') AS NodeName
,Deeper.value('.','nvarchar(max)') AS NodeValue
FROM @XML_In.nodes('//SomeNode') AS Sm(Nd)
OUTER APPLY Nd.nodes('parent::*/*[local-name(.)!="SomeNode"]/*') AS TwoLevels(Deeper)
) AS tbl
PIVOT
(
MIN(NodeValue) FOR NodeName IN(ID,Name,Value)
) AS p
在此解决方案中,您的第一个工作示例显示了如何将SomeNode
用作变量...
答案 1 :(得分:0)
添加第二个正斜杠以表示深度搜索,并仅在@XML_Path
变量中查找您所追求的值的父节点:
DECLARE @XML_Path VARCHAR(MAX)
, @XML_In XML
SET @XML_Path = 'Hello'
SET @XML_In =
'
<GetData>
<Hello>
<test>234</test>
<test>567</test>
</Hello>
</GetData>
'
SELECT Item_Idx = Nodes.value('(test)[1]' ,'INT')
FROM @XML_In.nodes('//*[local-name()=sql:variable("@XML_Path")]') Results(Nodes)
SELECT Item_Idx = Nodes.value('(test)[2]' ,'INT')
FROM @XML_In.nodes('//*[local-name()=sql:variable("@XML_Path")]') Results(Nodes)
或者,您可以指定多个级别并返回所有值:
declare @Node varchar(max)
declare @Attribute varchar(max)
set @Attribute = 'World'
set @Node = 'Hello'
select @XML_In.value('(/GetData
/*[local-name() = sql:variable("@Node")]
/*[local-name() = sql:variable("@Attribute")])[1]', 'int')