Как извлечь значения из XML без жесткого кодирования имен элементов, используя XQuery в SQL Server? - PullRequest
3 голосов
/ 11 июля 2011

xml хранится в таблице и таблице с именами / путями интересующих меня элементов.

Я хотел бы извлечь значения этих элементов без жестких путей кодирования и / или имен элементов. Структура моего xml не изменится, у него всегда будет родитель / ребенок / элемент.

Можно ли объединить xml и таблицу, чтобы получить значения элементов?

Ниже приведен пример того, что я смог получить. Я думаю, что можно расширить это решение для JOIN на ChildNode и Element, но не уверен, как использовать .query() и .value(), чтобы добраться до ChildNode и Element.

Спасибо за вашу помощь.

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)')

1 Ответ

2 голосов
/ 12 июля 2011

Вы можете использовать sql: column () в выражении xquery и сравнить с local-name(.), чтобы получить нужные вам узлы.

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)

Результат:

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

Редактировать: Другая версия, в которой вместо этого используется объединение полей.Это может иметь лучшую производительность для вас в зависимости от того, как выглядят ваши данные.Первая версия анализирует XML для каждой строки в @ProductElement, а вторая версия разбивает XML и использует его для объединения с @ 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
...