小编典典

T-SQL遍历XML数据列以派生唯一的路径集

sql

我有XML数据列,其中包含作为应用程序过程的一部分的问题和答案。我试图通过T-SQL / Dynamic SQL实现的是在有 目标
标记的任何地方派生唯一的路径集。因此,对于下面的xml示例,我希望得到类似

日志/客户端/客户端/部分/问题/ groupone /问题/目标日志/客户端/客户端/部分/问题/ grouptwo /问题/目标

然后的想法是使用它并遍历XML以得出所需标签的值。IE

[DATA] .value(’((/ log / clients / client / section / questions / groupone /
question / target’,’NVARCHAR(MAX)’)

问题是每个应用程序都有不同的问题集和xml结构,即某些应用程序可能有更多问题,某些应用程序可能有不同的分组。但是,我想要的只是如果有一个标签,那么它的路径是什么。

我怎样才能最好地做到这一点?

 <log>
  <clients>
   <client>
    <section name ="Apps鈥�> 
     <questions>
      <groupone>
       <question>
        <target>Age</target>
       </question>
       <question>
        <target> Height</target>
       </question>
       <question>
        <target> Weight</target>
       </question>
      </groupone>
      <grouptwo name = "exercise">
       <wording>what is your name</wording>
        <question>
         <id>1</id>
         <target>def<target>
        </question>
      </grouptwo>
     </questions>
    </section>
   </client>
  </clients>
 </log>

阅读 192

收藏
2021-03-10

共1个答案

小编典典

在这里,过时的方法FROM OPENXML可能是一个选择。检查此答案

此链接中,您会发现一个不时发布的功能John
Cappelletti,该功能将切碎所有XML(该功能代码下方的功劳)。

但我不确定,您真正想要实现的目标…为什么需要这条路?如果您对所有目标节点的值感兴趣,则可以执行以下操作(使用进行深度搜索//不需要确切的XPath

 SELECT t.value(N'(text())[1]','nvarchar(max)')
 FROM @xml.nodes('//target') AS A(t);

如果您真的需要 所有的一切 ,可以检查以下内容:

CREATE FUNCTION [dbo].[udf-XML-Hier](@XML xml)

Returns Table 
As Return

with  cte0 as ( 
                  Select Lvl       = 1
                        ,ID        = Cast(1 as int) 
                        ,Pt        = Cast(NULL as int)
                        ,Element   = x.value('local-name(.)','varchar(150)')
                        ,Attribute = cast('' as varchar(150))
                        ,Value     = x.value('text()[1]','varchar(max)')
                        ,XPath     = cast(concat(x.value('local-name(.)','varchar(max)'),'[' ,cast(Row_Number() Over(Order By (Select 1)) as int),']') as varchar(max))
                        ,Seq       = cast(1000000+Row_Number() over(Order By (Select 1)) as varchar(max))
                        ,AttData   = x.query('.') 
                        ,XMLData   = x.query('*') 
                  From   @XML.nodes('/*') a(x) 
                  Union  All
                  Select Lvl       = p.Lvl + 1 
                        ,ID        = Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10
                        ,Pt        = p.ID
                        ,Element   = c.value('local-name(.)','varchar(150)')
                        ,Attribute = cast('' as varchar(150))
                        ,Value     = cast( c.value('text()[1]','varchar(max)') as varchar(max) ) 
                        ,XPath     = cast(concat(p.XPath,'/',c.value('local-name(.)','varchar(max)'),'[',cast(Row_Number() Over(PARTITION BY c.value('local-name(.)','varchar(max)') Order By (Select 1)) as int),']') as varchar(max) )
                        ,Seq       = cast(concat(p.Seq,' ',10000000+Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10) as varchar(max))
                        ,AttData   = c.query('.') 
                        ,XMLData   = c.query('*') 
                  From   cte0 p 
                  Cross  Apply p.XMLData.nodes('*') b(c) 
              )
    , cte1 as (   
                  Select R1 = Row_Number() over (Order By Seq),A.*
                  From  (
                          Select  Lvl,ID,Pt,Element,Attribute,Value,XPath,Seq From cte0
                          Union All
                          Select Lvl       = p.Lvl+1
                                ,ID        = p.ID + Row_Number() over (Order By (Select NULL)) 
                                ,Pt        = p.ID
                                ,Element   = p.Element
                                ,Attribute = x.value('local-name(.)','varchar(150)')
                                ,Value     = x.value('.','varchar(max)')
                                ,XPath     = p.XPath + '/@' + x.value('local-name(.)','varchar(max)')
                                ,Seq       = cast(concat(p.Seq,' ',10000000+p.ID + Row_Number() over (Order By (Select NULL)) ) as varchar(max))
                          From   cte0 p 
                          Cross  Apply AttData.nodes('/*/@*') a(x) 
                        ) A 
               )

Select A.R1
      ,R2  = IsNull((Select max(R1) From cte1 Where Seq Like A.Seq+'%'),A.R1)
      ,A.Lvl
      ,A.ID
      ,A.Pt
      ,A.Element
      ,A.Attribute
      ,A.XPath
      ,Title = Replicate('|---',Lvl-1)+Element+IIF(Attribute='','','@'+Attribute)
      ,A.Value
 From  cte1 A

/*
Source: http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx

Taken from John Cappelletti: https://stackoverflow.com/a/42729851/5089204

Declare @XML xml='<person><firstname preferred="Annie" nickname="BeBe">Annabelle</firstname><lastname>Smith</lastname></person>'
Select * from [dbo].[udf-XML-Hier](@XML) Order by R1
*/
GO

DECLARE @xml XML=
'<log>
  <clients>
   <client>
    <section name ="Apps"> 
     <questions>
      <groupone>
       <question>
        <target>Age</target>
       </question>
       <question>
        <target> Height</target>
       </question>
       <question>
        <target> Weight</target>
       </question>
      </groupone>
      <grouptwo name = "exercise">
       <wording>what is your name</wording>
        <question>
         <id>1</id>
         <target>def</target>
        </question>
      </grouptwo>
     </questions>
    </section>
   </client>
  </clients>
 </log>';

 SELECT * FROM dbo.[udf-XML-Hier](@xml);
GO
2021-03-10