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>