Formatar XML com XSL usando Dot Net

Nesse artigo utilizei Visual C# 2010 Express, Framework 4.0 e para o aplicativo teste fiz um console application.

Com o advento de integração, SOA, Web Services, cada dia mais temos que adaptar o conteúdo de nossos dados com agilidade, no meu caso eu atuo em uma empresa na qual temos vários parceiros comerciais que consomem nosso catálogo de produtos, e a forma de integração que temos é com o uso de XML, bom para acelerar o desenvolvimento do XML para cada parceiro, nós criávamos um XML para cada um, só que isso não era feito de forma automática, a codificação de cada XML era feita individualmente, os objetos eram reutilizados, mas ai tivemos problemas com performance, pois a consulta era feita em tempo real, ou seja, os parceiros concorriam com os clientes que navegavam no site, o XML demorava para ser carregado, quando era necessário efetuar algum filtro por categoria, gênero, marca etc, isso era feito na aplicação, ou seja, o catalogo era carregado inteiro e filtrado através de um delegate, quando eram poucos parceiros, poucos clientes, tudo bem, mas 1 ano depois com muito mais acessos o negócio ficou ruim, e é isso que vou mostrar como fazer aqui, como esse problema foi resolvido, os passos foram:

  1. Não acessar mais o banco diretamente, mas sim um XML base;
  2. Efetuar a formatação dos dados baseado em um XSL e não mais fazer isso na codificação;
  3. Colocar os critérios dentro do XSL ao invés de fazer na aplicação ou em query.

O que é um arquivo XSL e para que serve

Segundo a Wikpedia “XSL Transformations, ou XSLT (eXtensible Stylesheet Language for Transformation – linguagem extensível para folhas de estilo de transformações), é uma linguagem de marcação XML usada para criar documentos XSL que, por sua vez, definem a apresentação dos documentos XML nos browsers e outros aplicativos que a suportem.” ou seja, serve para formatar a saída de dados do XML

Fonte: http://pt.wikipedia.org/wiki/XSLT

Agora que estamos alinhados com o cenário vamos começar.

XML Base

Isso é algo muito tranquilo, foi criado um JOB que gera um XML em uma pasta visível pela aplicação com todo catálogo de produtos, para esse estudo vamos usar o exemplo abaixo:

<?xml version="1.0"
encoding="utf-8" ?>
<catalogo>
  <item>
    <Sku>500135</Sku>
<Descricao><![CDATA[Bola de Tênis Wilson Championship ]]></Descricao>
<CodigoCategoria>102</CodigoCategoria>
    <Categoria>RACKET</Categoria>
<CodigoMarca>15</CodigoMarca>
<Marca>WILSON</Marca>
 </item>
 <item>
    <Sku>500139</Sku>
<Descricao><![CDATA[Haltere Ferro Centauro MeioKg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500140</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 1 Kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500141</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 2Kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodSubGrupo>34</CodSubGrupo>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500142</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 3kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500143</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 4Kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY
               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
</catalogo>

XSL’s

Bom, o XSL pode ficar ao gosto de cada um, eu vou colocar dois exemplos aqui, o primeiro nos dará a seguinte saída do XML Base:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='xml' indent='yes' version='1.0' encoding='UTF-8' standalone='yes' cdata-section-elements='NOME'/>
<xsl:template match="/">
<produtos>
<xsl:for-each select="catalogo/item[CodigoCategoria='102' and CodigoMarca='999']">
<PRODUTO>
<SKU>
<xsl:value-of select="Sku"/>
</SKU>
<NOME>
<xsl:value-of select="Descricao"/>
</NOME>
<CATEGORIA>
<xsl:value-of select="Categoria"/>
</CATEGORIA>
</PRODUTO>
</xsl:for-each>
</produtos>
</xsl:template>
</xsl:stylesheet>

O segundo nos dará a saída abaixo:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='xml' indent='yes' version='1.0' encoding='UTF-8' standalone='yes' cdata-section-elements='NOME'/>
<xsl:template match="/">
<produtos>
<xsl:for-each select="catalogo/item[CodigoCategoria='102']">
<ITEM>
<CODIGO>
<xsl:value-of select="Sku"/>
</CODIGO>
<DESCRICAO>
<xsl:value-of select="Descricao"/>
</DESCRICAO>
</ITEM>
</xsl:for-each>
</produtos>
</xsl:template>
</xsl:stylesheet>

Esses arquivos devem ser criados em um local que a aplicação posso lê-los.

Agora vamos entender algumas tag’s do XSL:

Aqui é feita a declaração do XSL, a versão e qual namespace (xmlns) é utilizado, a tag deve ser fechada

<xsl:stylesheet version="1.0" xmlns:xsl="<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>">

A saída do arquivo é definida aqui, o método/formato (method), a versão do formato (version), a codificação (encoding) e as tags que terão a saída com CDATA (cdata-section-elements).

<xsl:output method='xml' version='1.0' encoding='UTF-8' cdata-section-elements='NOME'/>

Nesse momento o nó raiz é escolhido para trabalhar, a tag deve ser fechada.

<xsl:template match="/">

Tudo o que não estiver usando o prefixo xsl será escrito da mesma forma como estiver no XSL. Vamos ver o loop agora

Aqui é o começo do loop

<xsl:for-each select="catalogo/item">

E aqui é o seu final

</xsl:for-each>

Tudo o que estiver entre essas tag’s será repetido até que todos os nós tenha sido lidos.

Para escrever os valores que estão no XML basta usar a tag value-of e no atributo select colocar o campo que deseja conforme o exemplo

<xsl:value-of select="Sku"/>

Adicionando critérios no XSL

Assim como em uma query é possível adicionar critérios em XSL, basta adicioná-los conforme o código abaixo na tag for-each, no primeiro exemplo o XSL trará apenas os produtos com o campo CodigoCategoria igual a 102, no segundo exemplo, todos com CodigoCategoria igual a 102 e o CodigoMarca igual 999.

<xsl:for-each select="catalogo/item[CodigoCategoria='102']">
<xsl:for-each select="catalogo/item[CodigoCategoria='102' and CodigoMarca='999']">

Usando XSL para formatar o XML

O Dot Net Framework nos dá suporte para trabalhar com arquivos XML através do Namespace System.Xml e para trabalhar com XSL com o Namespace System.Xml.Xsl

Vamos utilizar a classe XslCompiledTransform para formatar o XML com nosso XSL, essa classe é um processador de XSL e XSLT, ela é a sucessora da classe XslTransform, e segundo a MSDN oferece ganhos de performance com relação a classe antiga (e obsoleta na versão 4.0 do Dot Net Framework)

Uma das sobrecargas do construtor do XslCompiledTransform recebe um XmlReader, então carreguei o XSL dentro de um XmlReader e criei o objeto do XslCompiledTransform, o método Transform de nosso objeto XslCompiledTransform tem uma sobrecarga que recebe o xml base, uma lista de argumentos de Xslt que será passado como nulo e um objeto que terá o resultado da transformação, nesse caso é passado um StringWriter, pronto, agora o objeto StringWriter tem o XML carregado conforme as definições do XSL, tudo bem simples,

Código

Aqui está todo o código utilizado para a aplicação funcionar corretamente.

using System;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
namespace GeradorXmlParceiro
{
class Program
{
static string caminhoXmlBase = @"C:\XmlBase\XmlBase.xml";
static string caminhoXsl = @"C:\Xsl\Xsl1.xsl";
static string caminhoXmlFormatado = @"C:\XmlTransformado\XmlTransformado.xml";
static void Main(string[] args)
{
CriarXmlComXsl();
}

static void CriarXmlComXsl()
{
XmlDocument xml = new XmlDocument();
xml = FormartarXmlBaseParaFormatoComXsl(caminhoXsl);
xml.Save(caminhoXmlFormatado);
}

static XmlDocument FormartarXmlBaseParaFormatoComXsl(string caminhoXsl)
{
XmlDocument xml = new XmlDocument();
XslCompiledTransform xsl = new XslCompiledTransform();
XmlDocument xmlBase = ObterXmlBase();
try
{
XmlReader reader = XmlReader.Create(caminhoXsl);
xsl.Load(reader);
StringWriter writer = new StringWriter();
xsl.Transform(xmlBase, null, writer);
xml.LoadXml(writer.ToString());
}
catch (Exception ex)
{
throw new Exception("Ocorreu um erro ao efetuar a transformação do XML.", ex.InnerException);
}
return xml;
}

static XmlDocument ObterXmlBase()
{
XmlDocument xml = new XmlDocument();
try
{
xml.Load(caminhoXmlBase);
}
catch (Exception ex)
{
throw new Exception("Ocorreu um erro ao carregar o XML.", ex.InnerException);
}
return xml;
}
}
}

É isso ai! Espero que esse artigo posso contribuir para o crescimento da comunidade! Até a próxima!

Referências

http://www.w3schools.com/xsl/

http://www.w3schools.com/xml/

http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.aspx

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s