如何从sql中的给定xml获取'/'分隔的节点/标签名称

问题描述 投票:0回答:1

我想从给定的xml中获取用'/'分隔的节点名称,以便仅获取节点/标记名称,而不是从给定的xml中获取节点/标记值。

假设我在xml以下:

<ns:manageWorkItemRequest>
    <ns:wiFocus>
        <act:orderDate>2020-03-16T10:30:56.000Z</act:orderDate>
        <act:orderItem>
            <agr:instance>
                <spec1:customerServiceIdentifier>ETHA15302121</spec1:customerServiceIdentifier>
                <spec1:instanceCharacteristic>
                    <spec1:action>
                        <spec1:code>Modify</spec1:code>
                    </spec1:action>
                    <spec1:instanceIdentifier>
                        <spec1:value>OS014-AHEFV5T9</spec1:value>
                </spec1:instanceIdentifier>
             </agr:instance>
        </act:orderItem>
        <act:orderVersion>1</act:orderVersion>
    </ns:wiFocus>
    <ns:wiAction>Create</ns:wiAction>
    <ns:wiVersion>1</ns:wiVersion>
</ns:manageWorkItemRequest>

我希望结果为:

ns:manageWorkItemRequest / ns:wiFocus / act:orderItem / agr:instance / spec1:customerServiceIdentifier / ETHA15302121

实际要求是,如果我在上述xml中得到此“ ETHA15302121”值,则应该显示路径,即xml中该值正好以'/'分隔的格式。

sql sql-server xml xpath
1个回答
0
投票

您的XML格式不正确(中间缺少结束标记,缺少名称空间声明。

添加完缺少的部分后,看起来像这样,您可以沿这条路线尝试一些操作(警告:这不会很快...):

您的XML

DECLARE @xml XML=
N'<root xmlns:ns="dummy1" xmlns:act="dummy2" xmlns:agr="dummy3" xmlns:spec1="dummy4">
  <ns:manageWorkItemRequest>
    <ns:wiFocus>
      <act:orderDate>2020-03-16T10:30:56.000Z</act:orderDate>
      <act:orderItem>
        <agr:instance>
          <spec1:customerServiceIdentifier>ETHA15302121</spec1:customerServiceIdentifier>
          <spec1:instanceCharacteristic>
            <spec1:action>
              <spec1:code>Modify</spec1:code>
            </spec1:action>
            <spec1:instanceIdentifier>
              <spec1:value>OS014-AHEFV5T9</spec1:value>
            </spec1:instanceIdentifier>
          </spec1:instanceCharacteristic>
        </agr:instance>
      </act:orderItem>
      <act:orderVersion>1</act:orderVersion>
    </ns:wiFocus>
    <ns:wiAction>Create</ns:wiAction>
    <ns:wiVersion>1</ns:wiVersion>
  </ns:manageWorkItemRequest>
</root>';

-查询

WITH AllNamespaces As
(
    SELECT  CONCAT('ns',ROW_NUMBER() OVER(ORDER BY (B.namespaceUri))) Prefix
           ,B.namespaceUri
    FROM @xml.nodes('//*') A(nd)
    CROSS APPLY(VALUES(A.nd.value('namespace-uri(.)','nvarchar(max)')))B(namespaceUri)
    WHERE LEN(B.namespaceUri)>0
    GROUP BY B.namespaceUri
)
,recCte AS
(
    SELECT 1 AS NestLevel
          ,ROW_NUMBER() OVER(ORDER BY A.nd) AS ElementPosition
          ,CAST(REPLACE(STR(ROW_NUMBER() OVER(ORDER BY A.nd),5),' ','0') AS VARCHAR(900)) COLLATE DATABASE_DEFAULT AS SortString
          ,CONCAT(ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)'),'[',ROW_NUMBER() OVER(PARTITION BY ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)') ORDER BY A.nd),']') AS FullName
          ,CAST(CONCAT('/',ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)'),'[',ROW_NUMBER() OVER(PARTITION BY ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)') ORDER BY A.nd),']') AS NVARCHAR(MAX)) COLLATE DATABASE_DEFAULT AS XPath
          ,A.nd.value('text()[1]','nvarchar(max)') AS NodeValue
          ,A.nd.query('./*') NextFragment
    FROM @xml.nodes('/*') A(nd)
    LEFT JOIN AllNamespaces ns ON ns.namespaceUri=A.nd.value('namespace-uri(.)','nvarchar(max)')

    UNION ALL

    SELECT r.NestLevel+1
          ,ROW_NUMBER() OVER(ORDER BY A.nd)  
          ,CAST(CONCAT(r.SortString,REPLACE(STR(ROW_NUMBER() OVER(ORDER BY A.nd),5),' ','0')) AS VARCHAR(900)) COLLATE DATABASE_DEFAULT
          ,CONCAT(ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)'),'[',ROW_NUMBER() OVER(PARTITION BY ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)') ORDER BY A.nd),']') AS FullName
          ,CONCAT(r.XPath,'/',ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)'),'[',ROW_NUMBER() OVER(PARTITION BY ns.Prefix+':',A.nd.value('local-name(.)','nvarchar(max)') ORDER BY A.nd),']') AS FullName
          ,A.nd.value('text()[1]','nvarchar(max)') AS NodeValue
          ,A.nd.query('./*') NextFragment
    FROM recCte r
    CROSS APPLY NextFragment.nodes('*') A(nd)
    INNER JOIN AllNamespaces ns ON ns.namespaceUri=A.nd.value('namespace-uri(.)','nvarchar(max)')
)
SELECT * 
FROM recCte
WHERE NodeValue IS NOT NULL
ORDER BY SortString;

-结果/ *

+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| NestLevel | ElementPosition | SortString                               | FullName                         | XPath                                                                                                                                                      | NodeValue                | NextFragment |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 4         | 1               | 00001000010000100001                     | ns2:orderDate[1]                 | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderDate[1]                                                                                      | 2020-03-16T10:30:56.000Z |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 6         | 1               | 000010000100001000020000100001           | ns4:customerServiceIdentifier[1] | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderItem[1]/ns3:instance[1]/ns4:customerServiceIdentifier[1]                                     | ETHA15302121             |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 8         | 1               | 0000100001000010000200001000020000100001 | ns4:code[1]                      | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderItem[1]/ns3:instance[1]/ns4:instanceCharacteristic[1]/ns4:action[1]/ns4:code[1]              | Modify                   |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 8         | 1               | 0000100001000010000200001000020000200001 | ns4:value[1]                     | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderItem[1]/ns3:instance[1]/ns4:instanceCharacteristic[1]/ns4:instanceIdentifier[1]/ns4:value[1] | OS014-AHEFV5T9           |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 4         | 3               | 00001000010000100003                     | ns2:orderVersion[1]              | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderVersion[1]                                                                                   | 1                        |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 3         | 2               | 000010000100002                          | ns1:wiAction[1]                  | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiAction[1]                                                                                                      | Create                   |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+
| 3         | 3               | 000010000100003                          | ns1:wiVersion[1]                 | /root[1]/ns1:manageWorkItemRequest[1]/ns1:wiVersion[1]                                                                                                     | 1                        |              |
+-----------+-----------------+------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+--------------+

* /

-仅显示所创建的XPath可以按预期工作:

WITH XMLNAMESPACES('dummy1' AS ns1,'dummy2' AS ns2,'dummy3' AS ns3,'dummy4' AS ns4,'dummy5' AS ns5)
SELECT @xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderDate[1]','nvarchar(max)')
      ,@xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderItem[1]/ns3:instance[1]/ns4:customerServiceIdentifier[1]','nvarchar(max)')
      ,@xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderItem[1]/ns3:instance[1]/ns4:instanceCharacteristic[1]/ns4:action[1]/ns4:code[1]','nvarchar(max)')
      ,@xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderItem[1]/ns3:instance[1]/ns4:instanceCharacteristic[1]/ns4:instanceIdentifier[1]/ns4:value[1]','nvarchar(max)')
      ,@xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiFocus[1]/ns2:orderVersion[1]','nvarchar(max)')
      ,@xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiAction[1]','nvarchar(max)')
      ,@xml.value('/root[1]/ns1:manageWorkItemRequest[1]/ns1:wiVersion[1]','nvarchar(max)');

简而言之:

  • 名称空间前缀可以由您自己定义。基础URI很重要。
  • 第一个cte将创建一组所有出现的URI,并将其与前缀一起返回。
  • 递归CTE将遍历XML。只要APPLY.nodes()可以返回嵌套节点,此操作就会继续。
  • 全名以及完整的XPath都是串联的。
  • CAST和COLLATE有助于避免数据类型不匹配(递归CTE对此非常挑剔)。
  • 串联的SortString是必需的,以确保输出中的顺序相同。
© www.soinside.com 2019 - 2024. All rights reserved.