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 Casagrande



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&#234;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://www.w3schools.com/xsl/

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

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

Oscar Casagrande

Oscar Casagrande - Técnico em Processamento de Dados pelo Colégio Técnico Elevação, tecnólogo em Desenvolvimento de Sistemas para Web no Instituto Brasileiro de Tecnologia Avançado (IBTA, agora Instituto Veris) e fazendo pós-graduação em Engenharia de Sistemas com ênfase em SOA no Instituto Veris.
Blog:
http://oscarcasagrande.blogspot.com.