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 diretos e calculados construtores.
Usando 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.
Construindo elementos
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 elemento><ProductModel. O elemento construído tem três elementos filho
Um nó de texto.
Dois nós de elementos, <Summary> e <Features>.
O elemento><Summary tem um filho de nó de texto cujo valor é "Some description".
O <Características> elemento tem três filhos de nó de elementos, <>de cores, <>de peso e <>de garantia. Cada um desses nós tem um nó de texto filho e tem os valores Vermelho, 25, 2 anos partes e trabalho, respectivamente.
declare @x 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>')
Este é 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 elemento <NewRoot
> com um elemento filho (<e
>). O valor do elemento <e
> é calculado especificando uma expressão de caminho dentro de chaves ("{ ... }").
DECLARE @x 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.
Este é o resultado:
<NewRoot>
<e>
<root>5</root>
</e>
</NewRoot>
A consulta a seguir é semelhante à anterior. No entanto, a expressão nas chaves especifica o data() função para recuperar o valor atômico do elemento <root
> e o atribui ao elemento construído, <e
>.
DECLARE @x xml;
SET @x='<root>5</root>';
DECLARE @y xml;
SET @y = (SELECT @x.query('
<NewRoot>
<e> { data(/root) } </e>
</NewRoot>' ));
SELECT @y;
Este é 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 xml;
SET @x='<root>5</root>';
DECLARE @y xml;
SET @y = (SELECT @x.query('
<NewRoot> Hello, I can use {{ and }} as part of my text</NewRoot>'));
SELECT @y;
Este é 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 valor do elemento <FirstLocation
> é 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;
Este é 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 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 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>
Construindo atributos
Quando você estiver construindo elementos usando o construtor de elemento direto, também poderá especificar atributos do elemento usando sintaxe semelhante a XML, conforme mostrado neste exemplo:
declare @x xml;
set @x='';
select @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
</ProductModel>')
Este é o XML resultante:
<ProductModel ProductModelID="111">
This is product model catalog description.
<Summary>Some description</Summary>
</ProductModel>
O elemento construído <ProductModel
> 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 filhoSome 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 função data() não é estritamente necessária. Como você está atribuindo o valor da expressão a um atributo, data() é implicitamente aplicado para recuperar o valor digitado da expressão especificada.
DECLARE @x xml;
SET @x='<root>5</root>';
DECLARE @y xml;
SET @y = (SELECT @x.query('<NewRoot attr="{ data(/root) }" ></NewRoot>'));
SELECT @y;
Este é 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;
Este é 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 valor5
é 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 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)}"/>' )
Este é 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.
Este é 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 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 retornará 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 xml SET @x ='<x>5</x>' select @x.query( '<a attr="{''Item'', /x }" />')
Se você aplicar a função data(), a consulta funcionará porque recupera o valor atômico da expressão,
/x
, que é concatenada com a cadeia de caracteres. Segue-se uma sequência de valores atómicos:SELECT @x.query( '<a attr="{''Item'', data(/x)}"/>' )
Este é 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 acima retorna o seguinte erro:
XML well-formedness check: Attribute cannot appear outside of element declaration. Rewrite your XQuery so it returns well-formed XML.
Adicionando 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.
Usando a cláusula WITH XMLNAMESPACES.
No prólogo XQuery.
Usando 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 filho <b
> desfaz a declaração do namespace padrão declarado no elemento pai.
declare @x xml
set @x ='<x>5</x>'
select @x.query( '
<a xmlns="a">
<b xmlns=""/>
</a>' )
Este é 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 xml
set @x ='<x>5</x>'
select @x.query( '
<x:a xmlns:x="a">
<b/>
</x:a>' )
Este é 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 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
Observe que a criação de um novo prefixo de namespace dessa maneira substituirá qualquer declaração de namespace pré-existente para esse prefixo. Por exemplo, a declaração de namespace, AWMI="https://someURI"
, no prólogo de consulta é substituída pela declaração de namespace no elemento <FirstLocation
>.
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
Usando um Prolog 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 xml
set @x ='<x>5</x>'
select @x.query( '
declare default element namespace "a";
<a><b xmlns=""/></a>' )
Observe que 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.
Este é 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 XSD anyURI. 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 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
Este é 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 Direct XML
Os construtores para instruções de processamento e comentários XML usam a mesma sintaxe que a da construção XML correspondente. Construtores computados para nós de texto também são suportados, mas são usados principalmente em XML DML para construir nós de texto.
Nota Para obter um exemplo de uso de um construtor de nó de texto explícito, consulte o exemplo específico em inserir (XML DML).
Na consulta a seguir, o XML construído inclui um elemento, dois atributos, um comentário e uma instrução de processamento. Observe que 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;
Este é 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>
Usando 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
Texto
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>
Esta é a consulta que usa construtores computados para gerar o XML:
declare @x 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 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 }
}
} ')
Observe que o elemento computado e os construtores de atributo, 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 de 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
Este é o resultado parcial:
<FirstLocation LocationID="10">
<AllTheSteps>
<AWMI:step> ... </AWMI:step>
<AWMI:step> ... </AWMI:step>
...
</AllTheSteps>
</FirstLocation>
Limitações adicionais 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