Gerando XML no SQL Server – Arte do FOR XML PATH
Partimos para o FOR XML PATH, que torna a Arte do FOR XML extremamente flexível, permitindo que o FOR XML PATH seja adequado para suprir qualquer necessidade de geração de XML por meio de T-SQL.
Vamos para o primeiro exemplo desta facilidade, onde criaremos um XML simples a partir de uma consulta, na qual as colunas relacionadas serão os nós filhos:
SELECT TOP (3)
FirstName
, LastName
FROM
Person.Contact
FOR XML PATH('Contacts'), ROOT('Person')
<Person>
<Contacts>
<FirstName>Gustavo</FirstName>
<LastName>Achong</LastName>
</Contacts>
<Contacts>
<FirstName>Catherine</FirstName>
<LastName>Abel</LastName>
</Contacts>
<Contacts>
<FirstName>Kim</FirstName>
<LastName>Abercrombie</LastName>
</Contacts>
</Person>
E com uma pequena variação (@), temos ao invés de nós filhos, atributos:
SELECT TOP (3)
FirstName AS [@FirstName]
, LastName AS [@LastName]
FROM
Person.Contact
FOR XML PATH('Contacts'), ROOT('Person')
<Person> <Contacts FirstName="Gustavo" LastName="Achong" /> <Contacts FirstName="Catherine" LastName="Abel" /> <Contacts FirstName="Kim" LastName="Abercrombie" /> </Person>
Para quem já percebeu com os exemplos anteriores, com o FOR XML PATH temos uma interpretação simplificada do XPATH na geração dos nós e atributos, assim podemos criar facilmente caminhos com atributos, elementos e até comentários de forma totalmente livre:
SELECT TOP (3)
LastName AS [Name/@LastName] -- Atributo
, FirstName AS [Name/text()] -- Texto
, EmailAddress AS [Contact/Email/text()] -- Texto
, Phone AS [Contact/Phone] -- Texto, sem 'text()'
, ModifiedDate AS [comment()] -- Comentário
FROM
Person.Contact
FOR XML PATH('Contacts'), ROOT('Person')
<Person>
<Contacts>
<Name LastName="Achong">Gustavo</Name>
<Contact>
<Email>gustavo0@adventure-works.com</Email>
<Phone>398-555-0132</Phone>
</Contact>
<!--2005-05-16T16:33:33.060-->
</Contacts>
<Contacts>
<Name LastName="Abel">Catherine</Name>
<Contact>
<Email>catherine0@adventure-works.com</Email>
<Phone>747-555-0171</Phone>
</Contact>
<!--2005-05-16T16:33:33.077-->
</Contacts>
<Contacts>
<Name LastName="Abercrombie">Kim</Name>
<Contact>
<Email>kim2@adventure-works.com</Email>
<Phone>334-555-0137</Phone>
</Contact>
<!--2005-05-16T16:33:33.077-->
</Contacts>
</Person>
Dai iniciam os desafios para gerar uma HTML TABLE com várias colunas no FOR XML PATH, sendo as próximas consultas não obtendo o resultado esperado:
Erro 1: Representação de duas colunas no mesmo path gera texto concatenado:
SELECT TOP (3)
FirstName AS [TD]
,LastName AS [TD]
FROM
Person.Contact
FOR XML PATH('TR'), ROOT('TABLE')
<TABLE>
<TR>
<TD>GustavoAchong</TD>
</TR>
<TR>
<TD>CatherineAbel</TD>
</TR>
<TR>
<TD>KimAbercrombie</TD>
</TR>
</TABLE>
Erro 2: Texto com nós XML é transformado (encode):
SELECT TOP (3)
'<TD>' + FirstName + '</TD>',
'<TD>' + LastName + '</TD>'
FROM
Person.Contact
FOR XML PATH('TR'), ROOT('TABLE')
<TABLE> <TR><TD>Gustavo</TD><TD>Achong</TD></TR> <TR><TD>Catherine</TD><TD>Abel</TD></TR> <TR><TD>Kim</TD><TD>Abercrombie</TD></TR> </TABLE>
Solução: Para solução deste problema, temos as seguintes alternativas:
-- Gerando um path vazio, exigindo do SQL Server a criação de dois nós separados
SELECT TOP (3)
FirstName AS [TD]
, NULL AS [text()]
, LastName AS [TD]
FROM
Person.Contact
FOR XML PATH('TR'), ROOT('TABLE')
-- Gerando o XML por conversão de dados
SELECT TOP (3)
CAST('<TD>' + FirstName + '</TD><TD>' + LastName + '</TD>' AS XML)
FROM
Person.Contact
FOR XML PATH('TR'), ROOT('TABLE')
-- Gerando o XML por subconsulta
SELECT TOP (3)
(SELECT FirstName AS [text()] FOR XML PATH('TD'), TYPE)
, (SELECT LastName AS [text()] FOR XML PATH('TD'), TYPE)
FROM
Person.Contact
FOR XML PATH('TR'), ROOT('TABLE')
<TABLE>
<TR>
<TD>Gustavo</TD>
<TD>Achong</TD>
</TR>
<TR>
<TD>Catherine</TD>
<TD>Abel</TD>
</TR>
<TR>
<TD>Kim</TD>
<TD>Abercrombie</TD>
</TR>
</TABLE>
