2017-01-10 4 views
2

Ich brauche alle Attribute aus einer langen Liste von verschiedenen Elementen zu extrahieren. Daher versuche ich eine Schleife zu erstellen, die alle meine Elemente durchläuft und ihre Attribute zurückgibt.Schleife für Attribute von Elementen XML Extrahieren

Durch mehrere Beiträge, die ich in der Lage gewesen, den Code unten zu schreiben. Allerdings habe ich mehr als 1000 Elemente, weshalb ich mich sehr freuen würde, wenn es irgendwie möglich wäre, eine Schleife um den letzten Teil herum zu bauen, anstatt sie für alle Elemente zu kopieren.

with cte as 
(
select cast(
'<schema fwRel="2"> 
<taxFormId isPrimeKey="true" fkRef="C1-TXFRM" mapField="TAX_FORM_ID" dataType="string"/> 
<formType fkRef="C1-FRMTY" mapField="FORM_TYPE_CD" dataType="string"/> 
<bo suppress="true" required="true" fkRef="F1-BUSOB" mapField="BUS_OBJ_CD" dataType="string"/> 
<transferReason mdField="C1_TXF_TFRRSN_FLG" dataType="lookup" mapXML="BO_DATA_AREA" lookup="C1_TXF_TFRRSN_FLG"/> 
</schema>' as xml) xml_col 
) 

select cte.xml_col.value('(/schema/taxFormId/@fkRef)[1]', 'varchar(100)') as Dummy1 
cte.xml_col.value('(/schema/taxFormId/@mapField)[1]', 'varchar(100)') as Dummy2 
cte.xml_col.value('(/schema/taxFormId/@dataType)[1]', 'varchar(100)') as Dummy3 
cte.xml_col.value('(/schema/taxFormId/@mapXML)[1]', 'varchar(100)') as Dummy4 

from cte 

Ich hoffe, dass ich genügend Informationen zur Verfügung gestellt haben

+0

Sie den Code erwähnt - können Sie es hinzufügen? – Damian

+0

Irgendwie hat Edge mich geschraubt. Es ist jetzt angebracht –

Antwort

1

Eine einfache Möglichkeit, Attribute aufgelistet zu bekommen:

with cte as 
(
select cast(
'<schema fwRel="2"> 
    <taxFormId isPrimeKey="true" fkRef="C1-TXFRM" mapField="TAX_FORM_ID" dataType="string" /> 
    <formType fkRef="C1-FRMTY" mapField="FORM_TYPE_CD" dataType="string" /> 
    <bo suppress="true" required="true" fkRef="F1-BUSOB" mapField="BUS_OBJ_CD" dataType="string" /> 
    <transferReason mdField="C1_TXF_TFRRSN_FLG" dataType="lookup" mapXML="BO_DATA_AREA" lookup="C1_TXF_TFRRSN_FLG" /> 
</schema>' as xml) xml_col 
) 

--Die Abfrage verwendet .nodes(N'/schema/*') Alle Knoten unterhalb <schema> und .nodes(N'@*') aufzulisten alle Attribute innerhalb dieses Knotens zur Liste:

select nd.value(N'local-name(.)',N'nvarchar(max)') AS NodeName 
     ,attr.value(N'local-name(.)',N'nvarchar(max)') AS AttrName 
     ,attr.value(N'.',N'nvarchar(max)') AS AttrValue 
from cte 
OUTER APPLY xml_col.nodes(N'/schema/*') AS A(nd) 
OUTER APPLY A.nd.nodes(N'@*') AS B(attr) 

Das Ergebnis:

taxFormId  isPrimeKey true 
taxFormId  fkRef  C1-TXFRM 
taxFormId  mapField TAX_FORM_ID 
taxFormId  dataType string 
formType  fkRef  C1-FRMTY 
formType  mapField FORM_TYPE_CD 
formType  dataType string 
bo    suppress true 
bo    required true 
bo    fkRef  F1-BUSOB 
bo    mapField BUS_OBJ_CD 
bo    dataType string 
transferReason mdField  C1_TXF_TFRRSN_FLG 
transferReason dataType lookup 
transferReason mapXML  BO_DATA_AREA 
transferReason lookup  C1_TXF_TFRRSN_FLG 

Wenn Sie eine Erklärung, wie die in Ihrem Beispiel benötigen könnte man es dynamisch erstellen (als String) und verwenden diesen EXEC (dynamischen SQL) auszuführen.

+0

Danke! Das hat meinen Tag gerettet :) –

0

Es ist ein wenig über töten sein können, aber ich benutze oft ein TVF zu analysieren und große XML-Dateien Hash. Die Funktion gibt die Daten in einer übergeordneten/untergeordneten Hierarchie mit den Bereichsschlüsseln R1/R2 zurück.

Zum Beispiel:

Declare @XML xml=' 
<schema fwRel="2"> 
    <taxFormId isPrimeKey="true" fkRef="C1-TXFRM" mapField="TAX_FORM_ID" dataType="string"/> 
    <formType fkRef="C1-FRMTY" mapField="FORM_TYPE_CD" dataType="string"/> 
    <bo suppress="true" required="true" fkRef="F1-BUSOB" mapField="BUS_OBJ_CD" dataType="string"/> 
    <transferReason mdField="C1_TXF_TFRRSN_FLG" dataType="lookup" mapXML="BO_DATA_AREA" lookup="C1_TXF_TFRRSN_FLG"/> 
</schema>' 

Select * from [dbo].[udf-XML-Hier](@XML) Order by R1 

Returns

enter image description here

Sie werden feststellen, es gibt Spalten für Elementname, Attributname, XPath Titel (optional), und Wert. Die R1, R2, Lvl, ID und PT sind alle abgeleitet.

Als TVF, man könnte jede Anwendung WHERE oder ORDER gewünschten


Die UDF (mit Original-Quelle), wenn interessiert

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(10000001 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 

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 
*/ 
+0

Danke! :) Ich habe es geschafft, dass das funktioniert. Wie Sie jedoch selbst sagen, ist es ein kleiner Overkill. –