quarta-feira, 23 de junho de 2010

Criando XML Datasets com o FOR XML

A partir do Sql Server 2005, podemos gerar XML fragments através de querys SQL. De maneira bastante pragmática, podemos gerar um fragmento de XML a partir de uma query, adicionando a cláusula FOR XML, no fim da query. O exemplo abaixo contempla o mode RAW:
use tempdb
go

create table registros(
  dt_venda int,
  grupo varchar(20),
  valor numeric(10,2)
)

insert into registros(dt_venda,grupo,valor)
values (2007,'Florianópolis',100.32)

insert into registros(dt_venda,grupo,valor)
values (2007,'São Paulo',300.72)

insert into registros(dt_venda,grupo,valor)
values (2007,'Rio de Janeiro',700.82)

insert into registros(dt_venda,grupo,valor)
values (2008,'Florianópolis',800.32)

insert into registros(dt_venda,grupo,valor)
values (2008,'São Paulo',700.72)

insert into registros(dt_venda,grupo,valor)
values (2008,'Rio de Janeiro',660.82)

insert into registros(dt_venda,grupo,valor)
values (2009,'Florianópolis',340.32)

insert into registros(dt_venda,grupo,valor)
values (2009,'São Paulo',120.72)

insert into registros(dt_venda,grupo,valor)
values (2009,'Rio de Janeiro',30.82)
insert into registros(dt_venda,grupo,valor)
values (2009,'Rio de Janeiro',null)
SELECT * FROM registros
FOR XML RAW
O mode RAW é o mais simples de todos, e gera um XML com nodes nomeados como “row”.  E as tags de valores são os campos do XML
<row dt_venda="2007" grupo="Florianópolis" valor="100.32" />
<row dt_venda="2007" grupo="São Paulo" valor="300.72" />
<row dt_venda="2007" grupo="Rio de Janeiro" valor="700.82" />
<row dt_venda="2008" grupo="Florianópolis" valor="800.32" />
<row dt_venda="2008" grupo="São Paulo" valor="700.72" />
<row dt_venda="2008" grupo="Rio de Janeiro" valor="660.82" />
<row dt_venda="2009" grupo="Florianópolis" valor="340.32" />
<row dt_venda="2009" grupo="São Paulo" valor="120.72" />
<row dt_venda="2009" grupo="Rio de Janeiro" valor="30.82" />
Se adicionarmos a cláusula ROOT, teremos um XML com um node raiz.
SELECT * FROM registros
FOR XML RAW, ROOT('Root')

<Root>
  <row dt_venda="2007" grupo="Florianópolis" valor="100.32" />
  <row dt_venda="2007" grupo="São Paulo" valor="300.72" />
  <row dt_venda="2007" grupo="Rio de Janeiro" valor="700.82" />
  <row dt_venda="2008" grupo="Florianópolis" valor="800.32" />
  <row dt_venda="2008" grupo="São Paulo" valor="700.72" />
  <row dt_venda="2008" grupo="Rio de Janeiro" valor="660.82" />
  <row dt_venda="2009" grupo="Florianópolis" valor="340.32" />
  <row dt_venda="2009" grupo="São Paulo" valor="120.72" />
  <row dt_venda="2009" grupo="Rio de Janeiro" valor="30.82" />
</Root>
Existem basicamente, quatro sabores de XML para a cláusula FOR XML:
·         RAW
·         AUTO
·         EXPLICIT
·         PATH

XML RAW
Como vimos anteriormente, RAW é o mais simples de todos. Podemos mudar o resultado do output, para que cada coluna da tabela, seja um elemento do XML, com a cláusula ELEMENTS.
SELECT * FROM registros
FOR XML RAW, ROOT('Root'), ELEMENTS
<Root>
  <row>
    <dt_venda>2007</dt_venda>
    <grupo>Florianópolis</grupo>
    <valor>100.32</valor>
  </row>
Como vimos anteriormente, RAW é o mais simples de todos. Podemos mudar o resultado do output, para que cada coluna da tabela seja um elemento do XML com a cláusula ELEMENTS. Observe que as colunas com valores nulos, não são adicionadas no XML resultante:
  <row>
    <dt_venda>2009</dt_venda>
    <grupo>Rio de Janeiro</grupo>
  </row>
</Root>
Podemos apresentar os elementos nulos, adicionando a diretiva XSINIL.
SELECT * FROM registros
FOR XML RAW, ROOT('Root'), ELEMENTS



<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
    <dt_venda>2009</dt_venda>
    <grupo>Rio de Janeiro</grupo>
    <valor>30.82</valor>
  </row>
  <row>
    <dt_venda>2009</dt_venda>
    <grupo>Rio de Janeiro</grupo>
    <valor xsi:nil="true" />
  </row>

Podemos apresentar os elementos nulos, adicionando a diretiva XSINIL.
XML AUTO
A cláusula XML AUTO difere do modo RAW, pois nativamente suporta hierarquias, porém estas hierarquias devem ser simples pois o modo suporta apenas um PATH. Observe o seguinte exemplo:
CREATE TABLE CLIENTES(
  CODIGO INT IDENTITY(1,1),
  NOME VARCHAR(100)
)
GO

CREATE TABLE TELEFONES(
  COD_CLIENTE INT,
  TELEFONE VARCHAR(25)
)
GO

INSERT INTO CLIENTES VALUES ('Rodrigo')
INSERT INTO CLIENTES VALUES ('Daniel')
go

INSERT INTO TELEFONES VALUES (1,'32336598')
INSERT INTO TELEFONES VALUES (2,'21548787')
GO

SELECT
  C.NOME,
  T.TELEFONE
FROM CLIENTES C
INNER JOIN TELEFONES T ON (C.CODIGO=T.COD_CLIENTE)
FOR XML AUTO, ROOT ('Clientes')
XML EXPLICIT
A cláusula XML Explicit, é a que tem a sintaxe mais incomum. Seu diferencial é possibilidade de montar a estrutura do seu XML, o que é inviável utilizando outros modes de XML.
CREATE TABLE CLIENTES(
  CODIGO INT IDENTITY(1,1),
  NOME VARCHAR(100)
)
GO

CREATE TABLE TELEFONES(
  COD_CLIENTE INT,
  TELEFONE VARCHAR(25)
)
GO

INSERT INTO CLIENTES VALUES ('Rodrigo')
INSERT INTO CLIENTES VALUES ('Daniel')
go

INSERT INTO TELEFONES VALUES (1,'32336598')
INSERT INTO TELEFONES VALUES (2,'21548787')
GO

SELECT
  1 AS TAG
  ,NULL AS PARENT
  ,NULL AS "CLIENTE!1!!ELEMENT"
  ,NULL AS "CLIENTE!2!NOME"
  ,NULL AS "TELEFONE!3!NUMERO"
UNION ALL
SELECT
  2 AS TAG,
  1 AS PARENT, 
  C.CODIGO AS "CLIENTE!1!!ELEMENT",
  C.NOME AS "CLIENTE!2!ELEMENT",
  NULL AS "TELEFONE!3!NUMERO"
FROM CLIENTES C
UNION ALL
SELECT
  3 AS TAG,
  2 AS PARENT, 
  T.COD_CLIENTE AS "CLIENTE!1!!ELEMENT",
  NULL AS "CLIENTE!2!ELEMENT",
  T.TELEFONE AS "TELEFONE!3!NUMERO"
FROM TELEFONES T
ORDER BY "CLIENTE!1!!ELEMENT", TAG
FOR XML EXPLICIT, ROOT ('Clientes')
O resultado é:

<Clientes>
  <CLIENTE>
    <CLIENTE NOME="Rodrigo">
      <TELEFONE NUMERO="32336598" />
    </CLIENTE>
    <CLIENTE NOME="Daniel">
      <TELEFONE NUMERO="21548787" />
    </CLIENTE>
  </CLIENTE>
</Clientes>
XML PATH

A cláusula PATH é o caminho mais produtivo para trabalhar com XML Datasets. Observe este exemplo, com a tabela registros criada anteriormente:

SELECT
      dt_venda as "@Data",
      NEWID() as "comment()",
      cast('<Teste/>' as XML) AS "node()",
      grupo as "AdditionalInfo/@Type",
      valor as "AdditionalInfo/text()"
FROM
      registros
FOR XML PATH('Totais'), ROOT('Cidades')

O resultado é:

<Cidades>
  <Totais Data="2007">
    <!--31A05E93-DD17-4839-95B1-28C4A61E1555-->
    <Teste />
    <AdditionalInfo Type="Florianópolis">100.32</AdditionalInfo>
  </Totais>
  <Totais Data="2007">
    <!--DDCB446A-0FCB-4D8F-90B3-415D4F16147C-->
    <Teste />
    <AdditionalInfo Type="São Paulo">300.72</AdditionalInfo>
  </Totais>
  <Totais Data="2007">
    <!--C5500C5D-F438-42A4-BBBD-08D6411D73DD-->
    <Teste />
    <AdditionalInfo Type="Rio de Janeiro">700.82</AdditionalInfo>
  </Totais>
  <Totais Data="2008">
    <!--C6CADDE0-6788-42C7-9397-8A0BB8337969-->
    <Teste />
    <AdditionalInfo Type="Florianópolis">800.32</AdditionalInfo>
  </Totais>
  <Totais Data="2008">
    <!--CAC24611-A7D0-4AC5-8CEB-BB1BECDB2C6E-->
    <Teste />
    <AdditionalInfo Type="São Paulo">700.72</AdditionalInfo>
  </Totais>
  <Totais Data="2008">
    <!--54D1D2BA-A8B3-41CC-8DFF-12F06D995B75-->
    <Teste />
    <AdditionalInfo Type="Rio de Janeiro">660.82</AdditionalInfo>
  </Totais>
  <Totais Data="2009">
    <!--480D8A3E-0CC2-4348-BC98-D0632E8B9ABA-->
    <Teste />
    <AdditionalInfo Type="Florianópolis">340.32</AdditionalInfo>
  </Totais>
  <Totais Data="2009">
    <!--5F8F446C-882A-4A43-A5AA-B2264348D4B9-->
    <Teste />
    <AdditionalInfo Type="São Paulo">120.72</AdditionalInfo>
  </Totais>
  <Totais Data="2009">
    <!--2FA42BEE-D563-4E82-83B7-5334C4512BA7-->
    <Teste />
    <AdditionalInfo Type="Rio de Janeiro">30.82</AdditionalInfo>
  </Totais>
  <Totais Data="2009">
    <!--2CA067D8-F560-4005-BEDD-BFF4E173D86C-->
    <Teste />
    <AdditionalInfo Type="Rio de Janeiro" />
  </Totais>
</Cidades>
Até o próximo artigo, quando veremos a utilização do XML Data Type.

Nenhum comentário:

Postar um comentário

Leave your comment here!