用于Xpath查询的SQL Xml

时间:2019-05-20 15:34:54

标签: sql sql-server xml xpath

尝试通过Xpath查询返回XML字段的值。

这是XML快照中的样子。

<?xml version="1.0" encoding="utf-16"?>  
<ArrayOfCustomProperty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    
<CustomProperty>      
    <DeveloperId>Test123</DeveloperId>      
    <Key>AgreedToTerms</Key>      
    <Value>True</Value>    
</CustomProperty>    
<CustomProperty>      
    <DeveloperId>Test456</DeveloperId>      
    <Key>ValidForLoyaltyPoints</Key>      
    <Value>False</Value>    
</CustomProperty>  
</ArrayOfCustomProperty>

(抱歉,XML格式不正确... StackOverflows RCE呈现它时出现问题。ArrayOfCustomProperty最后关闭,由于某种原因而没有显示)

此查询对我有用。...

  SET @return = CAST(CAST(@xmlData AS xml).query('ArrayOfCustomProperty/CustomProperty/Key[text()=sql:variable("@key")]/../Value/text()') AS nvarchar(255))

它使我可以使用一个函数,其中的参数分别是@xmlData和@key以供需要搜索的内容使用。我需要有另一个函数(或可能会修改它),在这里我也可以搜索[DeveloperId]节点,因此第三个参数将作为@devId传递。我已经尝试了很多不同的东西,但是对我来说还没有任何作用。我想要一个查询,当使用相同的结构(如果可能)显示[DeveloperId]和[Key]时,可以获取[Value],该结构与当前Xpath查询的工作方式相同。

在此先感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

您可以将xml数据转换为表格,然后处理该表格。像这样的东西。

declare @xml xml=N'<?xml version="1.0" encoding="utf-16"?>  
<ArrayOfCustomProperty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    
<CustomProperty>      
    <DeveloperId>Test123</DeveloperId>      
    <Key>AgreedToTerms</Key>      
    <Value>True</Value>    
</CustomProperty>    
<CustomProperty>      
    <DeveloperId>Test456</DeveloperId>      
    <Key>ValidForLoyaltyPoints</Key>      
    <Value>False</Value>    
</CustomProperty>  
</ArrayOfCustomProperty>',
@key varchar(50)

;with cte as (
select t.v.value('DeveloperId[1]','varchar(50)') DeveloperId,
    t.v.value('Key[1]','varchar(50)') [Key],
    t.v.value('Value[1]','varchar(50)') [Value]
from @xml.nodes('ArrayOfCustomProperty/CustomProperty') t(v)
)
select * from cte
where [Key] = @key

答案 1 :(得分:1)

您应该尝试尽可能少地从XML返回。
最好的办法是将引擎必须解析的数量减少到所需的最小值。
并且您应该避免使用../向后导航。这是一个众所周知的性能杀手。

尝试一下:

DECLARE @tbl TABLE(YourXml XML);
INSERT INTO @tbl VALUES
(N'<?xml version="1.0" encoding="utf-16"?>  
<ArrayOfCustomProperty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    
<CustomProperty>      
    <DeveloperId>Test123</DeveloperId>      
    <Key>AgreedToTerms</Key>      
    <Value>True</Value>    
</CustomProperty>    
<CustomProperty>      
    <DeveloperId>Test456</DeveloperId>      
    <Key>ValidForLoyaltyPoints</Key>      
    <Value>False</Value>    
</CustomProperty>  
</ArrayOfCustomProperty>');

-您的键变量

DECLARE @key VARCHAR(100)='ValidForLoyaltyPoints' ;

-查询

SELECT cp.value('(DeveloperId/text())[1]','nvarchar(250)') AS DeveloperId
      ,cp.value('(Value/text())[1]','nvarchar(250)') AS Value
FROM @tbl t
CROSS APPLY t.YourXml.nodes('/ArrayOfCustomProperty/CustomProperty[(Key/text())[1]=sql:variable("@key")]') A(cp);

XPath/XQuery中的.nodes()将跳至<CustomProperty>,并返回带有<Key>的那个,其中键的文本类似于给定的过滤器。返回找到的<CustomProperty>。使用.value(),我们可以读取此给定属性下的元素。

更新

看起来,好像您试图根据<Value><DeveloperId>来获取<Key>作为标量值一样。您可以使用简单的谓词一次查询两者:

DECLARE @key VARCHAR(100)='ValidForLoyaltyPoints' ;
DECLARE @devId VARCHAR(100)='Test456';
--the Query

SELECT t.YourXml.value(N'(/ArrayOfCustomProperty
                          /CustomProperty[(DeveloperId/text())[1]=sql:variable("@devId") 
                                      and (Key/text())[1]=sql:variable("@key")]
                          /Value/text())[1]',N'nvarchar(100)')
FROM @tbl t;

您读为

  • 潜入数组
  • 深入了解CustomProperty
  • 在过滤器匹配的地方找到一个元素...
  • ...并返回其值

答案 2 :(得分:0)

@Shnugo

这是您最后一次评论的意思吗?

DECLARE @tbl TABLE(YourXml XML);
INSERT INTO @tbl VALUES (@xmlData)

SELECT t.YourXml.value('(/ArrayOfCustomProperty/CustomProperty/Value/text())[1]','nvarchar(250)') AS Value 
FROM @tbl t
WHERE t.YourXml.value('(/ArrayOfCustomProperty/CustomProperty/Key/text())[1]','nvarchar(250)') = @key 
AND
t.YourXml.value('(/ArrayOfCustomProperty/CustomProperty/DeveloperId/text())[1]','nvarchar(250)') = @devId