Desenvolvimento - C#
Formatar XML com XSL usando Dot Net
Veja como formatar arquivos XML usando XSL e melhorando a performance de sua aplicação.
por Oscar CasagrandeNesse 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 Meio Kg]]></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 3 kg]]></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="http://www.w3.org/1999/XSL/Transform">
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://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.aspx