kb.erickguedes.com
XSLT: Transformação de Documentos

Extensões, XSLT 3.0 e Produção

Aula 5 de 5

EXSLT — Extensões Comunitárias

EXSLT adiciona funções matemáticas, de string, data e regex ao XSLT 1.0.

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:date="http://exslt.org/dates-and-times"
  xmlns:math="http://exslt.org/math"
  xmlns:str="http://exslt.org/strings"
  extension-element-prefixes="date math str">

  <!-- Data atual -->
  <p>Gerado em: <xsl:value-of select="date:date-time()"/></p>

  <!-- Matemática -->
  <p>Média: <xsl:value-of select="math:avg(//preco)"/></p>
  <p>Maior: <xsl:value-of select="math:max(//preco)"/></p>
  <p>Menor: <xsl:value-of select="math:min(//preco)"/></p>

  <!-- String tokenize e replace -->
  <xsl:for-each select="str:split(nomes, ';')">
    <li><xsl:value-of select="."/></li>
  </xsl:for-each>
</xsl:stylesheet>
# Saxonica/saxon9he já inclui suporte a EXSLT
java -jar saxon9he.jar -s:dados.xml -xsl:exslt.xsl -o:output.html

Extensões Saxon

O processador Saxon oferece funcionalidades avançadas proprietárias.

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:saxon="http://saxon.sf.net/"
  extension-element-prefixes="saxon">

  <!-- Tokenização com regex -->
  <xsl:for-each select="tokenize(descricao, '\s+')">
    <span><xsl:value-of select="."/> </span>
  </xsl:for-each>

  <!-- Análise de strings JSON -->
  <xsl:variable name="json"
    select="unparsed-text('config.json')"/>
</xsl:stylesheet>

XSLT 3.0 — Novidades

<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map">

  <!-- Streaming: processa documentos grandes sem carregar tudo -->
  <xsl:mode streamable="yes"/>
  <xsl:template match="produto">
    <p><xsl:value-of select="nome"/></p>
  </xsl:template>

  <!-- Maps e Arrays (estruturas de dados JSON-like) -->
  <xsl:variable name="config" as="map(xs:string, xs:string)">
    <xsl:map>
      <xsl:map-entry key="'host'" select="'localhost'"/>
      <xsl:map-entry key="'port'" select="'8080'"/>
    </xsl:map>
  </xsl:variable>

  <!-- Transformação em cadeia -->
  <xsl:variable name="transformado">
    <xsl:transform select="'<root><item>X</item></root>'">
      <xsl:output method="xml"/>
    </xsl:transform>
  </xsl:variable>
</xsl:stylesheet>

XML para PDF via XSL-FO

XSL-FO (Formatting Objects) é uma linguagem para formatação de páginas, usada para gerar PDF.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format">

  <xsl:template match="/">
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
        <fo:simple-page-master master-name="pagina">
          <fo:region-body margin="2cm"/>
        </fo:simple-page-master>
      </fo:layout-master-set>

      <fo:page-sequence master-reference="pagina">
        <fo:flow flow-name="xsl-region-body">
          <fo:block font-size="18pt" font-weight="bold" space-after="1cm">
            Relatório de Produtos
          </fo:block>

          <xsl:for-each select="//produto">
            <fo:block font-size="12pt" space-after="0.5cm">
              <xsl:value-of select="concat(nome, ' - R$ ', preco)"/>
            </fo:block>
          </xsl:for-each>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
</xsl:stylesheet>
# Gerar PDF com Apache FOP
fop -xml dados.xml -xsl relatorio-fo.xsl -pdf saida.pdf

Build Tooling e Performance

<!-- Ant build para pipeline XSLT -->
<project name="xslt-pipeline" default="transform">
  <target name="transform">
    <xslt in="dados.xml" out="output.html" style="template.xsl">
      <param name="categoria" expression="Eletrônicos"/>
      <param name="limite" expression="100"/>
    </xslt>
  </target>

  <target name="all" depends="transform">
    <xslt in="output.xml" out="final.pdf" style="fo.xsl"/>
  </target>
</project>
# Dicas de performance
# 1. Use keys para lookups em vez de XPath aninhado
# 2. Prefira xsl:for-each-group a Muenchian se XSLT 2.0+
# 3. Use xsl:mode streamable="yes" para documentos grandes
# 4. Evite //desnecessário — seja específico no XPath

# Benchmark de transformação
time xsltproc template.xsl grande.xml > /dev/null
time java -jar saxon9he.jar -s:grande.xml -xsl:template.xsl -o:/dev/null

Lab: Pipeline de Transformação Completo

# 1. Documento XML
cat << 'EOF' > dados.xml
<?xml version="1.0"?>
<produtos>
  <produto>
    <nome>Notebook Dell</nome>
    <preco>4999.00</preco>
    <categoria>Eletrônicos</categoria>
  </produto>
  <produto>
    <nome>Monitor 27"</nome>
    <preco>1599.00</preco>
    <categoria>Eletrônicos</categoria>
  </produto>
</produtos>
EOF

# 2. Transformar para HTML
cat << 'EOF' > to-html.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes"/>
  <xsl:template match="/">
    <html>
    <body>
      <h1>Produtos</h1>
      <xsl:for-each select="//produto">
        <p><xsl:value-of select="concat(nome, ' - R$ ', preco)"/></p>
      </xsl:for-each>
    </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
EOF

# 3. Pipeline
echo "=== Passo 1: XML -> HTML ==="
xsltproc to-html.xsl dados.xml > output.html
type output.html

echo ""
echo "=== Passo 2: Validar saída ==="
echo "Arquivo gerado: $(wc -c < output.html) bytes"

echo ""
echo "=== Passo 3: Usando Saxon ==="
if command -v java &> /dev/null; then
  echo "Saxon disponível (pule se não tiver o jar)"
fi

echo ""
echo "=== Bônus: EXSLT date ==="
cat << 'EOF' > exslt-demo.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:date="http://exslt.org/dates-and-times"
  extension-element-prefixes="date">
  <xsl:template match="/">
    <html><body>
      <p>Relatório gerado em: <xsl:value-of select="date:date-time()"/></p>
      <p>Ano: <xsl:value-of select="date:year()"/></p>
      <p>Timestamp: <xsl:value-of select="date:seconds()"/></p>
    </body></html>
  </xsl:template>
</xsl:stylesheet>
EOF

XSLT 3.0 com streaming e maps torna o XSLT moderno competitivo com linguagens de transformação como JavaScript e Python.