2012-06-12 7 views
1

Я пытаюсь уничтожить XML-файлы, которые имеют необычный макет, поскольку элементы не упорядочены с обычными элементами и атрибутами, а вместо этого в виде «списка в xml» формате :xquery эквивалент выражения tsql where в узлах XML

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
<SOAP-ENV:Body> 
<ns:Lists xmlns:ns="urn:Listing"> 
    <ns:items> 
     <ns:listRef>List1</ns:listRef> 
     <ns:name>Test list items</ns:name> 
     <ns:extendedFields> 
     <ns:extendedField> 
      <ns:name>Fruit</ns:name> 
      <ns:data>Apple</ns:data> 
     </ns:extendedField> 
     <ns:extendedField> 
      <ns:name>Vegetable</ns:name> 
       <ns:data /> 
     </ns:extendedField> 
     <ns:extendedField> 
       <ns:name>Sweet</ns:name> 
      <ns:data>Crunchie</ns:data> 
     </ns:extendedField> 
    </ns:extendedFields> 
    </ns:items> 
</ns:Lists> 
</SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

Я пробовал варианты XQuery ниже, но я не понимаю. Что мне нужно сделать, это эквивалент Xpath «select ns: data from x, где ns: name =« Fruit »», например. Раньше я был в состоянии сделать это, используя одиночную нумерацию, чтобы указать на расположение бита, которое я хотел на дереве, но в этом случае число extendedFields является переменным, и последовательность изменяется, поэтому единственный способ добраться до нужный вам узел будет указывать нужную пару имя/значение.

DECLARE @x xml 
SET @x = 
( SELECT xml_data_column 
    FROM dbo.Table 
WHERE xmlFileName = 'D:\XML_list.xml'); 

;WITH XMLNAMESPACES('urn:Listing' AS ns) 
SELECT t.c.value('../ns:listRef[1]', 'varchar(20)') listRef 
, t.c.value('../ns:name[1]', 'varchar(20)') name 
, t.c.value('/.', 'varchar(30)') ext1b 
, t.c.value('ns:extendedField[1]/ns:name[1]', 'varchar(30)') name1 
, t.c.value('ns:extendedField[1]/ns:data[1]', 'varchar(30)') data1 
, t.c.value('ns:extendedField[2]/ns:name[1]', 'varchar(30)') name2 
, t.c.value('ns:extendedField[2]/ns:data[1]', 'varchar(30)') data2 
, t.c.value('ns:extendedField[3]/ns:name[1]', 'varchar(30)') name3 
, t.c.value('ns:extendedField[3]/ns:data[1]', 'varchar(30)') data3 
FROM @x.nodes('//ns:Lists/ns:items/ns:extendedFields[1]') AS t(c) 

Так что, если я хотел бы видеть, что фрукты вещь этот человек выбрали, то я хотел бы выход выглядеть следующим образом:

listRef, name,    Fruit 
List1, Test list items, Apple 

ответ

0
with xmlnamespaces('urn:Listing' AS ns) 
select L.X.value('ns:listRef[1]', 'varchar(20)') as listRef, 
     L.X.value('ns:name[1]', 'varchar(20)') as name, 
     E.X.value('ns:data[1]', 'varchar(30)') as Fruit 
from @x.nodes('//ns:Lists/ns:items') as L(X) 
    cross apply L.X.nodes('ns:extendedFields/ns:extendedField[ns:name = "Fruit"]') as E(X) 
+0

Brilliant! Спасибо Микаэлю. Это работает на 100%, и я вижу, что могу расширить список полей, просто добавив крест в нижней части. Именно то, что мне нужно. – brynn

+0

Последующий вопрос: я использовал вышеуказанный более года без какой-либо одной проблемы. Но теперь, обновляясь до SQL2008 R2, и при тестировании сценария в SSIS возникает ошибка: «В процессоре запросов не хватало внутренних ресурсов и не удалось создать план запроса. Это редкое событие и ожидается только для чрезвычайно сложных запросов или запросов которые ссылаются на очень большое количество таблиц или разделов. Пожалуйста, упростите запрос ». Я точно указал его на один из вариантов, в котором есть 12 крестов, поэтому я понимаю, что это недовольство. Любые идеи, как я могу обойти это? – brynn

+0

... тем временем я только что разделил это на две отдельные партии, поэтому есть меньше кросс-приложений. – brynn

Смежные вопросы