SQL Server анализирует XML с пространством имен - PullRequest
1 голос
/ 26 сентября 2019

Я пытаюсь разобрать следующий xml, чтобы получить первый тег, следующий за тегом s: Body (в этом случае я ищу строку queryEE, в других сообщениях с той же структурой Envelope / Body это будетбыть другим)

Я начал играть с этим примерно так:

declare @text varchar(max)

set @text = N'
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <queryEE xmlns="http://xx.gob.gcaba.xx/">
      <codeEE xmlns="">xxxx</codeEE>
    </queryEE>
  </s:Body>
</s:Envelope>'

declare @x xml

set @x = cast(@text as xml)

select @x.query('/s:Envelope')

Но я получаю ошибку:

Msg 2229, Level 16, State 1, Line 16
XQuery [query()]: The name "s" does not denote a namespace.

Похоже, у меня проблемыс пространством имен

Когда я пытаюсь с select @x.query('/Envelope'), я вообще ничего не получаю


Благодаря ответам, полученным от @shnugo, я наконец смог решить это с помощью:

select @x.value('local-name((/*:Envelope/*:Body/*)[1])','nvarchar(100)')

Ответы [ 2 ]

1 голос
/ 26 сентября 2019

Попробуйте так:

- ваше объявление

declare @text varchar(max)

set @text = N'
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <queryEE xmlns="http://xx.gob.gcaba.xx/">
      <codeEE xmlns="">xxxx</codeEE>
    </queryEE>
  </s:Body>
</s:Envelope>'

declare @x xml

set @x = cast(@text as xml);

- запрос

WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS s
                  ,'http://xx.gob.gcaba.xx/' AS innerDflt) 
select @x.value('(/s:Envelope/s:Body/innerDflt:queryEE/codeEE/text())[1]','nvarchar(100)');

Некоторый фон:

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

Существует пространство имен s: для определения <Envelope> и <Body>,Пока это нормально. Но тогда элемент <queryEE> определяет пространство имен по умолчанию (без префикса!), А встроенный <codeEE> определяет другое (но пустое!) Пространство имен по умолчанию.Я почти уверен, что это пустое пространство имен создается в запросе путем объединения XML-файлов ...

пространство имен по умолчанию сообщает движку, что все узлы без определенногопрефикс живет в пределах этого пространства имен.Поэтому мы должны решить эту проблему.

Мой код использует WITH XMLNAMESPACES для объявления всех пространств имен, встречающихся в XML.В отличие от исходного XML, я определяю префикс (innerDflt) для первого пространства имен по умолчанию.Это означает, что мы можем обратиться к <innerDflt:queryEE>.Встроенный элемент не нуждается в пространстве имен.Он живет в пустом пространстве имен по умолчанию (=> no).

Все это говорит, я просто хочу указать, что вы также можете использовать подстановочный знак:

select @x.value('(/*:Envelope/*:Body/*:queryEE/*:codeEE/text())[1]','nvarchar(100)')

И выможет даже использовать глубокий поиск

select @x.value('(//*:codeEE/text())[1]','nvarchar(100)')

Но общий совет: будьте настолько конкретны, насколько это возможно.

1 голос
/ 26 сентября 2019

Объявляйте свое пространство имен снова при использовании xquery для xml с пространствами имен.

declare @text varchar(max)

set @text = N'
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <queryEE xmlns="http://xx.gob.gcaba.xx/">
      <codeEE xmlns="">xxxx</codeEE>
    </queryEE>
  </s:Body>
</s:Envelope>'

declare @x xml

set @x = cast(@text as xml)

select @x.query('declare default element namespace "http://schemas.xmlsoap.org/soap/envelope/";   
    /Envelope')
...