2015-04-27 6 views
1

У меня есть куча XML-файлов, которые мне нужны для синтаксического анализа SQL.SQL Parse xml string

XML, может принимать многочисленные формы:

<Grandparent> 
    <parent> 
     <child1>something</child1> 
     <child2>something</child2> 
    </parent> 
</Grandparent> 

или

<Grandparent> 
     <child1>something</child1> 
     <child2>something</child2> 
</Grandparent> 

Кроме того, число узлов «ребенок» является переменной величиной, и нет никакого способа узнать заранее, сколько детей есть.

Что я сделал до сих пор:

@xml.nodes('/Grandparent') 

, который возвращает либо <parent> узел и детей или просто child узлов в зависимости от формата XML.

Версия SQL и тот факт, что я пишу ее как функцию SQL, похоже, означает, что попытка получить value, как показано в this anwser, не работает.

Поэтому я решил разобрать строку. По существу, я ищу < и возьму подстроку оттуда до > для имени узла. Затем я беру что-то между > и </ для значения. Я делаю это в цикле while, пока строка xml не будет завершена. Он отлично работает, если у xml нет этого узла parent.

Я не знаю, как определить, есть ли этот узел parent и как игнорировать его, если это так. Вот где я застрял.

То, что я хочу получить в любом случае:

Node | Value 
child1 | something 
child2 | something 

и т.д. для как много дочерних узлов, что есть.

+2

Что RDBMS вы используете? –

+0

Все еще не ясно, что если вы можете сделать '@ xml.nodes ('/ Grandparent')', почему тогда вы не можете получить 'значение', как показано в этой ссылке ответа? И учитывая, что 2 образца, каков результат, который вы ожидаете получить? – har07

+0

@ Политбанк-З да! MS SQL-сервер. –

ответ

0

Вы можете использовать потомку оси // получить дочерние узлы на любой глубине уровня в пределах родительского узла.

Другой полезный синтаксис XPath для этой задачи local-name() которые возвращают имя текущего узла контекста/атрибута без имен:

select c.value('local-name(.)', 'varchar(max)') as 'node' 
     , c.value('.', 'varchar(max)') as 'value' 
from @xml.nodes('/Grandparent//*[not(*)]') as T(c) 

Это XPath бит //*[not(*)] означает, выберите узлы-потомки, которые не имеют дочерний узел, другими словами, выберите самого большого потомка.

SQL Fiddle

+1

'/ Grandparent // * [not (*)]' все, что мне нужно! Спасибо! –

0

Выйти на конечность здесь с двумя предположениями; Ваш вопрос не ясно о следующем:

  1. Я предполагаю, что ваши дочерние узлы имеют такое же имя (например, ребенок, не child1 и child2) и
  2. Вы хотите SQL заявление, что возвращает 1 ребенок за строку.

Если какой-либо из этих предположений неверно, этот ответ не поможет :)

DECLARE @xml XML = '<Grandparent> 
    <parent> 
     <child>something</child> 
     <child>something</child> 
    </parent> 
</Grandparent>' 


SELECT x.value('.[1]', 'varchar(100)') 
FROM @xml.nodes('/Grandparent//child') t(x) 


SET @xml= '<Grandparent> 
     <child>something</child> 
     <child>something</child> 
</Grandparent>' 


SELECT x.value('.[1]', 'varchar(100)') 
FROM @xml.nodes('/Grandparent//child') t(x) 
0

Try:

DECLARE @xml xml = N' 
    <Grandparent> 
     <parent> 
      <child1>something</child1> 
      <child2>something</child2> 
     </parent> 
    </Grandparent>'; 

SELECT 
    child.value('fn:local-name(.)', 'varchar(100)') AS Node 
    ,child.value('.', 'varchar(100)') AS value 
FROM @xml.nodes('//*[self::child1 or self::child2]') AS ansestor(child); 

SET @xml = N' 
    <Grandparent> 
      <child1>something</child1> 
      <child2>something</child2> 
    </Grandparent>'; 

SELECT 
    child.value('fn:local-name(.)', 'varchar(100)') AS Node 
    ,child.value('.', 'varchar(100)') AS value 
FROM @xml.nodes('//*[self::child1 or self::child2]') AS ansestor(child);