Partilhar via


Construção XML (XQuery)

Aplica-se a:SQL Server

No XQuery, você pode usar o direto e computados construtores para construir estruturas XML dentro de uma consulta.

Observação

Não há diferença entre os construtores diretos e computados .

Usar construtores diretos

Ao usar construtores diretos, você especifica sintaxe semelhante a XML ao construir o XML. Os exemplos a seguir ilustram a construção XML pelos construtores diretos.

Elementos de construção

Ao usar notações XML, você pode construir elementos. O exemplo a seguir usa a expressão do construtor do elemento direto e cria um <ProductModel> elemento . O elemento construído tem três elementos filho

  • Um nó de texto.

  • Dois nós de <Summary> elementos e <Features>.

    • O <Summary> elemento tem um filho de nó de texto cujo valor é "Some description".

    • O <Features> elemento tem três filhos de nó de elemento, <Color>, <Weight>, e <Warranty>. Cada um desses nós tem um filho de nó de texto e tem os valores Red, 25, , 2 years parts and laborrespectivamente.

DECLARE @x AS XML;

SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
<Features>
  <Color>Red</Color>
  <Weight>25</Weight>
  <Warranty>2 years parts and labor</Warranty>
</Features></ProductModel>');

Aqui está o XML resultante:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
  <Features>
    <Color>Red</Color>
    <Weight>25</Weight>
    <Warranty>2 years parts and labor</Warranty>
  </Features>
</ProductModel>

Embora a construção de elementos a partir de expressões constantes, como mostrado neste exemplo, seja útil, o verdadeiro poder desse recurso de linguagem XQuery é a capacidade de construir XML que extrai dados dinamicamente de um banco de dados. Você pode usar chaves para especificar expressões de consulta. No XML resultante, a expressão é substituída por seu valor. Por exemplo, a consulta a seguir constrói um <NewRoot> elemento com um elemento filho (<e>). O valor do elemento <e> é calculado especificando uma expressão de caminho dentro de chaves ("{ ... }").

DECLARE @x AS XML;

SET @x = '<root>5</root>';

SELECT @x.query('<NewRoot><e> { /root } </e></NewRoot>');

As chaves atuam como tokens de comutação de contexto e alternam a consulta da construção XML para a avaliação da consulta. Neste caso, a expressão do caminho XQuery dentro das chaves, /root, é avaliada e os resultados são substituídos por ela.

Eis o resultado:

<NewRoot>
  <e>
    <root>5</root>
  </e>
</NewRoot>

A consulta a seguir é semelhante à anterior. No entanto, a expressão nas chaves especifica a data() função para recuperar o valor atômico do <root> elemento e o atribui ao elemento construído, <e>.

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
                           <NewRoot>
                             <e> { data(/root) } </e>
                           </NewRoot>'));

SELECT @y;

Eis o resultado:

<NewRoot>
  <e>5</e>
</NewRoot>

Se quiser usar as chaves como parte do texto em vez de tokens de alternância de contexto, você pode escapar delas como "}}" ou "{{", conforme mostrado neste exemplo:

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
<NewRoot> Hello, I can use {{ and  }} as part of my text</NewRoot>'));

SELECT @y;

Eis o resultado:

<NewRoot> Hello, I can use { and  } as part of my text</NewRoot>

A consulta a seguir é outro exemplo de construção de elementos usando o construtor de elemento direto. Além disso, o <FirstLocation> valor do elemento é obtido executando a expressão nas chaves encaracoladas. A expressão de consulta retorna as etapas de fabricação no primeiro local do centro de trabalho da coluna Instruções da tabela Production.ProductModel.

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation>
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Eis o resultado:

<FirstLocation>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Insert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Attach <AWMI:tool>Trim Jig TJ-26</AWMI:tool> to the upper and lower right corners of the aluminum sheet.
  </AWMI:step>
   ...
</FirstLocation>

Conteúdo do elemento na construção XML

O exemplo a seguir ilustra o comportamento das expressões na construção do conteúdo do elemento usando o construtor de elemento direto. No exemplo a seguir, o construtor do elemento direct especifica uma expressão. Para essa expressão, um nó de texto é criado no XML resultante.

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { for $i in /root[1]/step
    return string($i)
 }
</result>');

A sequência de valores atômicos resultante da avaliação da expressão é adicionada ao nó de texto com um espaço adicionado entre os valores atômicos adjacentes, como mostrado no resultado. O elemento construído tem um filho. Este é um nó de texto que contém o valor mostrado no resultado.

<result>This is step 1 This is step 2 This is step 3</result>

Em vez de uma expressão, se você especificar três expressões separadas gerando três nós de texto, os nós de texto adjacentes serão mesclados em um único nó de texto, por concatenação, no XML resultante.

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { string(/root[1]/step[1]) }
 { string(/root[1]/step[2]) }
 { string(/root[1]/step[3]) }
</result>');

O nó do elemento construído tem um filho. Este é um nó de texto que contém o valor mostrado no resultado.

<result>This is step 1This is step 2This is step 3</result>

Construir atributos

Ao construir elementos usando o construtor de elemento direto, você também pode especificar atributos do elemento usando sintaxe semelhante a XML, conforme mostrado neste exemplo:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
</ProductModel>');

Aqui está o XML resultante:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
</ProductModel>

O elemento <ProductModel> construído tem um atributo ProductModelID e estes nós filho:

  • Um nó de texto, This is product model catalog description.

  • Um nó de elemento, <Summary>. Este nó tem um nó de texto filho Some description.

Ao construir um atributo, você pode especificar seu valor com uma expressão em chaves curvas. Nesse caso, o resultado da expressão é retornado como o valor do atributo.

No exemplo a seguir, a data() função não é estritamente necessária. Como você está atribuindo o valor da expressão a um atributo, data() é aplicado implicitamente para recuperar o valor digitado da expressão especificada.

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('<NewRoot attr="{ data(/root) }" ></NewRoot>'));

SELECT @y;

Eis o resultado:

<NewRoot attr="5" />

A seguir está outro exemplo em que as expressões são especificadas para a construção do atributo LocationID e SetupHrs. Essas expressões são avaliadas em relação ao XML na coluna Instrução. O valor digitado da expressão é atribuído aos atributos.

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Eis o resultado parcial:

<FirstLocation LocationID="10" SetupHours="0.5" >
  <AWMI:step ...
  </AWMI:step>
  ...
</FirstLocation>

Limitações de implementação

Estas são as limitações:

  • Não há suporte para expressões de atributos múltiplos ou mistos (string e expressão XQuery). Por exemplo, conforme mostrado na consulta a seguir, você constrói XML onde Item é uma constante e o valor 5 é obtido avaliando uma expressão de consulta:

    <a attr="Item 5" />
    

    A consulta a seguir retorna um erro, porque você está misturando cadeia de caracteres constante com uma expressão ({/x}) e isso não é suportado:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="Item {/x}"/>');
    

    Nesse caso, você tem as seguintes opções:

    • Forme o valor do atributo pela concatenação de dois valores atômicos. Esses valores atômicos são serializados no valor do atributo com um espaço entre os valores atômicos:

      SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
      

      Eis o resultado:

      <a attr="Item 5" />
      
    • Use a função concat para concatenar os dois argumentos de cadeia de caracteres no valor do atributo resultante:

      SELECT @x.query('<a attr="{concat(''Item'', /x[1])}"/>');
      

      Nesse caso, não há espaço adicionado entre os dois valores de cadeia de caracteres. Se você quiser um espaço entre os dois valores, você deve fornecê-lo explicitamente.

      Eis o resultado:

      <a attr="Item5" />
      
  • Não há suporte para várias expressões como um valor de atributo. Por exemplo, a consulta a seguir retorna um erro:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{/x}{/x}"/>');
    
  • Não há suporte para sequências heterogêneas. Qualquer tentativa de atribuir uma sequência heterogênea como um valor de atributo retorna um erro, conforme mostrado no exemplo a seguir. Neste exemplo, uma sequência heterogênea, uma cadeia de caracteres "Item" e um elemento <x>, é especificada como o valor do atributo:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{''Item'', /x }" />');
    

    Se você aplicar a data() função, a consulta funcionará porque recupera o valor atômico da expressão, /xque é concatenada com a cadeia de caracteres. Segue-se uma sequência de valores atómicos:

    SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
    

    Eis o resultado:

    <a attr="Item 5" />
    
  • A ordem do nó de atributo é imposta durante a serialização em vez de durante a verificação de tipo estático. Por exemplo, a consulta a seguir falha porque tenta adicionar um atributo após um nó que não é atributo.

    SELECT CONVERT (XML, '').query('
        element x { attribute att { "pass" }, element y { "Element text" }, attribute att2 { "fail" } }
        ');
    GO
    

    A consulta anterior retorna o seguinte erro:

    XML well-formedness check: Attribute cannot appear outside of element declaration. Rewrite your XQuery so it returns well-formed XML.
    

Adicionar namespaces

Ao construir XML usando os construtores diretos, os nomes de elementos e atributos construídos podem ser qualificados usando um prefixo de namespace. Você pode vincular o prefixo ao namespace das seguintes maneiras:

  • Usando um atributo de declaração de namespace.
  • Utilizando a WITH XMLNAMESPACES cláusula.
  • No prólogo XQuery.

Usar um atributo de declaração de namespace para adicionar namespaces

O exemplo a seguir usa um atributo de declaração de namespace na construção do elemento <a> para declarar um namespace padrão. A construção do elemento <b> filho desfaz a declaração do namespace padrão declarado no elemento pai.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <a xmlns="a">
    <b xmlns=""/>
  </a>');

Eis o resultado:

<a xmlns="a">
  <b xmlns="" />
</a>

Você pode atribuir um prefixo ao namespace. O prefixo é especificado na construção do elemento <a>.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b/>
  </x:a>');

Eis o resultado:

<x:a xmlns:x="a">
  <b />
</x:a>

Você pode cancelar a declaração de um namespace padrão na construção XML, mas não pode cancelar a declaração de um prefixo de namespace. A consulta a seguir retorna um erro, porque você não pode cancelar a declaração de um prefixo conforme especificado na construção do elemento <b>.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b xmlns:x=""/>
  </x:a>');

O namespace recém-construído está disponível para uso dentro da consulta. Por exemplo, a consulta a seguir declara um namespace na construção do elemento <FirstLocation>, e especifica o prefixo nas expressões para os valores dos atributos LocationID e SetupHrs.

SELECT Instructions.query('
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Criar um novo prefixo de namespace dessa maneira substitui qualquer declaração de namespace preexistente para esse prefixo. Por exemplo, a declaração de namespace, AWMI="https://someURI", no prolog de consulta é substituída pela declaração de namespace no <FirstLocation> elemento .

SELECT Instructions.query('
declare namespace AWMI="https://someURI";
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Usar um prólogo para adicionar namespaces

Este exemplo ilustra como namespaces podem ser adicionados ao XML construído. Um namespace padrão é declarado no prólogo de consulta.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
           declare default element namespace "a";
            <a><b xmlns=""/></a>');

Na construção do elemento <b>, o atributo de declaração de namespace é especificado com uma cadeia de caracteres vazia como seu valor. Isso cancela a declaração do namespace padrão declarado no pai.

Eis o resultado:

<a xmlns="a">
  <b xmlns="" />
</a>

Construção XML e manipulação de espaços em branco

O conteúdo do elemento na construção XML pode incluir caracteres de espaço em branco. Esses caracteres são manipulados das seguintes maneiras:

  • Os caracteres de espaço em branco em URIs de namespace são tratados como o tipo anyURIXSD . Especificamente, é assim que eles são tratados:

    • Todos os caracteres de espaço em branco no início e no final são cortados.
    • Os valores de caracteres internos de espaço em branco são recolhidos em um único espaço
  • Os caracteres de alimentação de linha dentro do conteúdo do atributo são substituídos por espaços. Todos os outros caracteres de espaço em branco permanecem como estão.

  • O espaço em branco dentro dos elementos é preservado.

O exemplo a seguir ilustra a manipulação de espaço em branco na construção XML:

-- line feed is replaced by space.
DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('

declare namespace myNS="   https://
 abc/
xyz

";
<test attr="    my
test   attr
value    " >

<a>

This     is  a

test

</a>
</test>
') AS XML_Result;

Eis o resultado:

-- result
<test attr="<test attr="    my test   attr  value    "><a>

This     is  a

test

</a></test>
"><a>

This     is  a

test

</a></test>

Outros construtores XML diretos

Os construtores para instruções de processamento e comentários XML usam a mesma sintaxe que a sintaxe de construção XML correspondente. Construtores computados para nós de texto também são suportados, mas são usados principalmente para construir nós de XML DML texto.

Observação

Para obter um exemplo de uso de um construtor de nó de texto explícito, consulte o exemplo específico em insert (XML DML).

Na consulta a seguir, o XML construído inclui um elemento, dois atributos, um comentário e uma instrução de processamento. Uma vírgula é usada antes do <FirstLocation>, porque uma sequência está sendo construída.

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   <?myProcessingInstr abc="value" ?>,
   <FirstLocation
        WorkCtrID = "{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
        SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
       <!-- some comment -->
       <?myPI some processing instructions ?>
       { (/AWMI:root/AWMI:Location[1]/AWMI:step) }
    </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Eis o resultado parcial:

<?myProcessingInstr abc="value" ?>
<FirstLocation WorkCtrID="10" SetupHrs="0.5">
  <!-- some comment -->
  <?myPI some processing instructions ?>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">I
  nsert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
    ...
</FirstLocation>

Usar construtores computados

Nesse caso, você especifica as palavras-chave que identificam o tipo de nó que deseja construir. Apenas as seguintes palavras-chave são suportadas:

  • elemento
  • atributo
  • enviar SMS

Para nós de elemento e atributo, essas palavras-chave são seguidas pelo nome do nó e também pela expressão, entre chaves, que gera o conteúdo para esse nó. No exemplo a seguir, você está construindo este XML:

<root>
  <ProductModel PID="5">Some text <summary>Some Summary</summary></ProductModel>
</root>

Aqui está a consulta que usa construtores computados para gerar o XML:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { 5 },
text{"Some text "},
    element summary { "Some Summary" }
 }
               } ');

A expressão que gera o conteúdo do nó pode especificar uma expressão de consulta.

DECLARE @x AS XML;
SET @x = '<a attr="5"><b>some summary</b></a>';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { /a/@attr },
text{"Some text "},
    element summary { /a/b }
 }
               } ');

Os elementos computados e construtores de atributos, conforme definido na especificação XQuery, permitem que você calcule os nomes dos nós. Quando você estiver usando construtores diretos no SQL Server, os nomes dos nós, como elemento e atributo, devem ser especificados como literais constantes. Portanto, não há diferença nos construtores diretos e construtores computados para elementos e atributos.

No exemplo a seguir, o conteúdo para os nós construídos é obtido das instruções de fabricação XML armazenadas na coluna Instruções do tipo de dados xml na tabela ProductModel.

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   element FirstLocation
     {
        attribute LocationID { (/AWMI:root/AWMI:Location[1]/@LocationID)[1] },
        element   AllTheSteps { /AWMI:root/AWMI:Location[1]/AWMI:step }
     }
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Eis o resultado parcial:

<FirstLocation LocationID="10">
  <AllTheSteps>
    <AWMI:step> ... </AWMI:step>
    <AWMI:step> ... </AWMI:step>
    ...
  </AllTheSteps>
</FirstLocation>

Outras limitações de implementação

Os construtores de atributos computados não podem ser usados para declarar um novo namespace. Além disso, os seguintes construtores computados não são suportados no SQL Server:

  • Construtores de nó de documento computado
  • Construtores de instruções de processamento computado
  • Construtores de comentários computados