2011-07-11 1 views
2

J'ai xml stocké dans une table et un tableau avec les noms/chemins des éléments qui m'intéressent.Comment extraire des valeurs de XML sans coder en dur les noms des éléments à l'aide de XQuery dans SQL Server?

Je voudrais extraire les valeurs de ces éléments sans chemins de codage durs et/ou noms des éléments. La structure de mon xml ne changera pas, elle aura toujours parent/enfant/élément.

Est-il possible de joindre xml et table pour obtenir les valeurs des éléments?

Voici un exemple de ce que j'ai pu obtenir. Je pense qu'il est possible d'étendre cette solution à JOIN sur ChildNode et Element, mais je ne sais pas comment utiliser .query() et .value() pour obtenir ChildNode et Element.

Nous vous remercions de votre aide.

DECLARE @xml xml 
SET @xml = 
'<Products> 
    <RedProduct> 
     <Details_RedProduct> 
     <Width>1</Width> 
     <Depth>2</Depth> 
     <Weight>3</Weight> 
     </Details_RedProduct> 
    </RedProduct> 
    <GreenProduct> 
     <Details_GreenProduct> 
     <Width>4</Width> 
     <Depth>5</Depth> 
     <Height>6</Height> 
     </Details_GreenProduct> 
     </GreenProduct> 
    <BlueProduct> 
     <Details_BlueProduct> 
     <Width>7</Width> 
     <Depth>8</Depth> 
     <Lenght>9</Lenght> 
     </Details_BlueProduct> 
    </BlueProduct> 
</Products>' 

DECLARE @ProductElement table (ProductNode nvarchar(100), ChildNode nvarchar(100), Element nvarchar(20)) 
INSERT INTO @ProductElement SELECT 'RedProduct','','Width' 
INSERT INTO @ProductElement SELECT 'GreenProduct','','Width' 
INSERT INTO @ProductElement SELECT 'GreenProduct','','Height' 
UPDATE @ProductElement SET ChildNode = 'Details_' + ProductNode 

SELECT ProductsCollection.query('local-name(.)').value('.','nvarchar(100)') as TestOutput 
FROM @xml.nodes('//Products/*') productsXml (ProductsCollection) 
INNER JOIN @ProductElement el ON el.ProductNode = ProductsCollection.query('local-name(.)').value('.','nvarchar(100)') 

Répondre

1

Vous pouvez utiliser sql:column() dans votre expression XQuery et comparer contre local-name(.) pour obtenir les noeuds que vous voulez.

select PE.ProductNode, 
     PE.ChildNode, 
     PE.Element, 
     T.Col.value('.', 'int') as ElementValue 
from @ProductElement as PE 
    cross apply @xml.nodes('/Products/*[local-name(.) = sql:column("PE.ProductNode")] 
            /*[local-name(.) = sql:column("PE.ChildNode")] 
            /*[local-name(.) = sql:column("PE.Element")]') as T(Col) 

Résultat:

ProductNode   ChildNode   Element    ElementValue 
-------------------- -------------------- -------------------- ------------ 
RedProduct   Details_RedProduct Width    1 
GreenProduct   Details_GreenProduct Width    4 
GreenProduct   Details_GreenProduct Height    6 

Edit: Une autre version qui utilise une jointure sur les champs à la place. Il peut-être avoir une meilleure performance pour vous en fonction de ce que vos données ressemblent. La première version analyse le XML pour chaque ligne de @ProductElement et la deuxième version déchire le XML et l'utilise pour se joindre à @ProductElement.

select PE.ProductNode, 
     PE.ChildNode, 
     PE.Element, 
     X.ElementValue 
from @ProductElement as PE 
    inner join (
       select T1.Col.value('local-name(.)', 'varchar(100)') as ProductNode, 
         T2.Col.value('local-name(.)', 'varchar(100)') as ChildNode, 
         T3.Col.value('local-name(.)', 'varchar(100)') as Element, 
         T3.Col.value('.',    'varchar(100)') as ElementValue 
       from @xml.nodes('/Products/*') as T1(Col) 
       cross apply T1.Col.nodes('*') as T2(Col) 
       cross apply T2.Col.nodes('*') as T3(Col) 
      ) as X 
    on PE.ProductNode = X.ProductNode and 
     PE.ChildNode = X.ChildNode and 
     PE.Element = X.Element 
+0

La deuxième option est légèrement plus rapide dans mon cas. Merci beaucoup pour votre réponse et pour avoir fourni deux options. –

Questions connexes