Uso de XML/XSLT
O que são XSL e XSLT?
- XSL = eXtensible Stylesheet Language. É uma
família de recomendações para definir
a apresentação e a
transformação de um XML.
- A XSL se divide em três:
- XSL Transformations (XSLT): Uma
linguagem para transformar XML.
- XML Path Language (XPath): Uma
linguagem para acessar e referir a partes de um documento XML.
- XSL Formatting Objects (XSL-FO): Um
vocabulário XML para especificar semântica de
formatação.
- As três são importantes, mas aqui
só falaremos de XSLT.
XML e XSLT
- Um processador XSLT pega uma folha de estilo contendo
comandos XSLT e a transforma usando um documento de entrada XML.
- Vejamos um exemplo simples:
- Eis XML representando um empregado
- Queremos representar isso em HTML
<employee id="03432">
<name>Joe Shmo</name>
<title>Manager</title>
</employee>
- Suponha que o HTML desejado seja
<html>
<body>
<p><b>Joe Shmo</b>: Manager</p>
</body>
</html>
- Podemos usar o seguinte stylesheet
- O stylesheet pode estar num arquivo ou base de dados
<xsl:stylesheet xmlns:xsl="">
<xsl:template match="/">
<html>
<body>
<p>
<b>
<xsl:value-of select="employee/name"/>
</b>
<xsl:text>: </xsl:text>
<xsl:value-of select="employee/title"/>
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Comandos XSL básicos
- Stylesheets (folhas de estilo) são definidas por
um conjunto de
comandos
- Stylesheets usam casamento de padrões para
localizar elementos e atributos
- Também há expressões que
podem chamar extensões (em Java ou Javascript)
- Vamos ver alguns comandos XSL
Declaração de stylesheet
- A declaração de stylesheet possui
versão e namespace
- O prefixo declarado representa o namespace para os
elementos (tags) que serão usados na folha de estilo e onde
a
definição dos elementos se localiza:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
.
.
.
</xsl:stylesheet>
- Se houver referência a extensões, o
namespace deve ser fornecido
- Por exemplo, para usar Java:
xmlns:java="http://xml.apache.org/xslt/java"
Casamento de padrões
- XPath é usada para selecionar o
elemento ou atributo que queremos acessar. A XPath é baseada
no casamento de padrões.
- A sintaxe básica é simples: basta
especificar o nodo
desejado, usando / para separar elementos
- Observe que, no XML acima, o casamento foi feito no nodo
"/" que é a raiz
- Poderíamos ter casado o nodo Employee
- Neste caso, o statement select poderia referenciar
"name" em vez de "employee/name"
- Com o seguinte XML ...
<employee id="03432">
<name>Joe Shmo</name>
<title>Manager</title>
</employee>
- ... podemos selecionar atributos da seguinte forma:
employee/@id seleciona o id do empregado
- Grupos de nodos podem ser acessados com employee/*
- Um empregado específico pode ser localizado com
employee/@id='03432'
- Casamento de padrões permite selecionar valores
específicos do documento XML
- O comando <xsl:value-of select... permite
selecionar um valor como mostra a tabela
|
|
Comando |
|
Resultado |
|
<xsl:value-of
select="employee/name"/> |
|
Joe Shmo |
|
<xsl:value-of
select="employee/@id"/> |
|
03432 |
Acessando
elementos e atributos
Templates
- Templates provêem uma forma de casar nodos num
documento XML e realizar operações nos nodos
- A sintaxe é:
<xsl:template match="nodename">
.
.
.
</xsl:template>
- O template "casa" (e será portanto usado) para
um certo nome de nodo e os comandos do template serão
aplicados
- Podemos chamar templates no stylesheet usando o comando
apply-templates:
<xsl:apply-templates select="nodename"/>
<xsl:template match="name"
<xsl:value-of select="..."/>
</xsl:template>
- Podemos chamar esse template em qualquer lugar onde houver
um nome de nodo a referenciar:
<xsl:apply-templates select="name"/>
Comandos Lógicos
- Há formas de fazer ifs e laços
Comando Choose
- O comando choose permite testar
situações
<xsl:choose>
<xsl:when test="test situation">
stylesheet commands
</xsl:when>
<xsl:otherwise>
stylesheet commands
</xsl:otherwise>
</xsl:choose>
- O bloco do primeiro teste bem sucedido será
aplicado
- O otherwise é obrigatório
<xsl:otherwise/>
Command if
- O comando if permite fazer um teste único
- Se precisar de else, use o comando choose
<xls:if test="test situation">
...
</xsl:if>
Laços (comando for-each)
- Só existe o comando for-each para fazer
laços
- Pode-se fazer loop num conjunto de nodos:
<xsl:for-each select="select statement">
...
</xsl:for-each>
- Por exemplo, se houver mais do que 1 empregado no documento
XML e você quiser fazer um laço com todos os
managers, então:
<xsl:for-each select="employee[title='Manager']">
...
</xsl:for-each>
Variáveis
- O comando variable permite atribuir o valor de uma
variável e usá-la depois.
- O mecanismo de extensão usa variáveis
para armazenar os valores obtidos de extensões:
<xsl:variable name="count">atribuir valor a count aqui</xsl:variable>
- A variável count pode ser acessada depois usando
$count no stylesheet:
<xsl:value-of select="$count"/>
Parâmetros
- Podem-se passar parâmetros para o stylesheet
usando o tag param
- Pode-se também especificar um valor default num
statement select
- O default é um string e as aspas simples
devem ser usadas
<xsl:param name="param1" select="'default value'"/>
- Você pode atribuir os parâmetros da
stylesheet usando o objeto Transformer:
transformer.setParameter("param1", "default value");
Extensões
- Extensões adicionam funcionalidade a uma
stylesheet
- XSL tem algumas funções
básicas:
- sum() -- Somar valores em nodos
- count() -- Contar os nodos
- position() -- Retornar a posição
do nodo corrente num laço
- last() -- Testar se este é o
último nodo
- Para adicionar funcionalidade, devem-se usar
extensões
- Falaremos de extensões escritas em java aqui
- O namespace java deve ser especificado na
declaração da stylesheet:
xmlns:java="http://xml.apache.org/xslt/java"
- O que se pode fazer com extensões em Java:
- Criar instâncias de classes
- variable myVector
select="java:java.util.Vector.new()"
- Chamar métodos das instâncias
- variable myAdd select="java:addElement($myVector,
string(@id))"
- Chamar métodos estáticos das
classes
- variable myString
select="java:java.lang.String.valueOf(@quantity))"
A API do XSLT da JRE
- Nos exemplos, usaremos a
implementação do processador XSLT que
já vem com a JRE 5.0.
- Usaremos as seguintes classes no servlet-exemplo abaixo:
Class javax.xml.transform.Transformer
- É o processador XSLT.
- O processamento é feito com o método
transform() que transforma a árvore fonte na
árvore
destino
- Para criar um Transformer, basta usar um TransformerFactory
via TransformerFactory.newTransformer(Source
xsltSource).
- void transform(Source xmlSource, Result outputTarget):
transforma o XML fonte na saída esperada.
Class javax.xml.transform.Source
- Interface comum para várias fontes de documentos
(Stream, SAX, DOM).
Class javax.xml.transform.Result
Um exemplo completo
- Temos um processo do lado servidor que usa XML para
armazenar dados transacionais
- Precisamos de uma solução que permita
analizar as transações do dia
- Queremos uma solução simples
(não-invasora) que não mexa com o processo de
armazenamento de dados da empresa
- Eis algumas soluções usando XSL:
- Criar um programa que rode periodicamente no servidor
que usará XSLT para transformar o XML em HTML
- Os arquivos HTML são armazenados no
servidor e acessados via browser
- Se você tiver controle sobre os
usuários, faça com que usem um browser que
dê suporte a XSLT
- Seu documento XML deve incluir um
cabeçalho que indique qual documento XSLT a usar e o browser
vai fazer a transformação
- Use XSLT num servlet rodando no servidor
- O próprio servidor vai pegar o XSLT de
um
arquivo ou BD e produzirá o HTML
- Usaremos o terceiro método, embora os outros
dois métodos sejam válidos
- Eis o schema XML das transações:
<!ELEMENT orders (invoice)+>
<!ELEMENT invoice (item+,name,address+)>
<!ELEMENT item EMPTY>
<!ELEMENT name (#PCDATA)>
<!ELEMENT address (street, city, state, zip)>
<!ELEMENT street (#PCDATA)>
<!ELEMENT city (#PCDATA)>
<!ELEMENT state (#PCDATA)>
<!ELEMENT zip (#PCDATA)>
<!ATTLIST invoice
number CDATA #REQUIRED
orderDate CDATA #REQUIRED
shipDate CDATA #REQUIRED>
<!ATTLIST item
part CDATA #REQUIRED
quantity CDATA #REQUIRED
cost CDATA #REQUIRED>
<!ATTLIST address
type (shipping|billing|other) #REQUIRED>
- Já que XSL não usa o DTD para fazer o
processamento, pequenas mudanças poderão ocorrer
no DTD sem precisar alterar o XSL
- Usaremos 4 stylesheets, uma para cada view:
- View de
transações: Uma lista de
transações do dia, incluindo número da
fatura (invoice), nome do freguês, total da fatura
- View de produtos
vendidos: Uma lista de produtos vendidos por dia,
incluindo a quantidade
- View de detalhes:
Um drill-down das views de transação e produtos
vendidos
- Fornece os detalhes da fatura
- View XML:
o XML que estamos processando
- Operação básica
- O HTML inicial apresenta um frame que permite escolher
uma stylesheet
- Ao escolher a stylesheet, um pedido é
enviado para o servlet
- O servlet abre o XML e a stylesheet e usa o Transformer
para realizar a tradução
- Vejamos cada view
A View de transações
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://xml.apache.org/xslt/java"
exclude-result-prefixes="java"
version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/orders">
<html>
<h1>Today's Invoices</h1>
<body>
<table border="on" cellspacing="1" cellpadding="5">
<thead>
<th>Invoice Number</th>
<th>Customer Name</th>
<th>Total Purchase</th>
</thead>
<tbody>
<xsl:for-each select="invoice">
<tr>
<td>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:text>xsl?stylesheet=detail&invoiceNum=</xsl:text>
<xsl:value-of select="@number"/>
</xsl:attribute>
<xsl:value-of select="@number"/>
</xsl:element>
</td>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="java:SumInvoice.summ(item)"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
- O resultado é mostrado abaixo

A view de detalhes
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://xml.apache.org/xslt/java"
exclude-result-prefixes="java"
version="1.0">
<xsl:param name="invoiceNum" select="string('none')"/>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<table border="on" cellspacing="1" cellpadding="5">
<xsl:for-each select="orders/invoice[@number=$invoiceNum]">
<tr>
<td>
<table border="on" cellspacing="1" cellpadding="5">
<tr>
<td><b>Invoice Number:</b>
<xsl:value-of select="@number"/>
</td>
<td colspan="3"><xsl:value-of select="name"/></td>
</tr>
<tr>
<td colspan="4">
<xsl:apply-templates select="address"/>
</td>
</tr>
<tr>
<td colspan="4"><b>Items</b>
</td>
</tr>
<tr>
<td>Part</td>
<td>Quantity</td>
<td>Cost</td>
<td>Subtotal</td>
</tr>
<xsl:for-each select="item">
<tr>
<td><xsl:value-of select="@part"/></td>
<td><xsl:value-of select="@quantity"/></td>
<td><xsl:value-of select="@cost"/></td>
<td><xsl:value-of select="@quantity * @cost"/></td>
</tr>
</xsl:for-each>
<tr>
<td>
<b><xsl:text>Total</xsl:text></b>
</td>
<td>
<xsl:value-of select="sum(item/@quantity)"/>
</td>
<td>
<xsl:text></xsl:text>
</td>
<td>
<xsl:value-of select="java:SumInvoice.summ(item)"/>
</td>
</tr>
</table>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="address">
<table>
<tr>
<td><i>
<xsl:choose>
<xsl:when test="@type='shipping'">
<xsl:text>Shipping Address</xsl:text>
</xsl:when>
<xsl:when test="@type='billing'">
<xsl:text>Billing Address</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Other Address</xsl:text>
</xsl:otherwise>
</xsl:choose></i>
</td>
</tr>
<tr>
<td colspan="4">
<xsl:value-of select="street"/>
</td>
</tr>
<tr>
<td colspan="4">
<xsl:value-of select="city"/>
<xsl:text> </xsl:text>
<xsl:value-of select="state"/>,
<xsl:value-of select="zip"/>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
- O resultado é mostrado abaixo

O servlet
- Já que os documentos XML e XSL
estarão em arquivos, podemos usar a versão de
Source que lida com java.io.Reader object
- O Result vai para um OutputStream, o que pode ser
obtido de HTTPResponse
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
public class XSLTServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
// By redirecting our doGets to the doPost method we can have a stylesheet
// executed from a link
// ex. <a href="xsl?stylesheet=detail&invoiceNum=00002">00002
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
// Process the HTTP Post request
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = new PrintWriter(response.getOutputStream());
// Get the stylesheet selected by the user
String stylesheet = request.getParameter("stylesheet");
// Get the invoice number selected by the user, this is used only for
// certain
// stylesheets. If it is not present, the stylesheet won't use it.
String invoiceNum = request.getParameter("invoiceNum");
// Prepare FileReaders for the stylesheet and XML
FileReader xslReader = new FileReader(".\\javaworld\\xsl\\"
+ stylesheet + ".xsl");
FileReader xmlReader = new FileReader(".\\javaworld\\xml\\"
+ "invoice.xml");
response.setContentType("text/html");
try {
// Create an instance of a Transformer
TransformerFactory transFact = TransformerFactory.newInstance();
Transformer trans = transFact.newTransformer(new StreamSource(
xslReader));
// Set the invoice number parameter
trans.setParameter("invoiceNum", invoiceNum);
// Process the stylesheet, all the output will go straight
// out to the browser.
trans.transform(new StreamSource(xmlReader), new StreamResult(out));
} catch (TransformerConfigurationException e) {
out.write(e.getMessage());
e.printStackTrace(out);
} catch (TransformerException e) {
out.write(e.getMessage());
e.printStackTrace(out);
}
out.close();
}
// Get Servlet information
public String getServletInfo() {
return "XSLTServlet Information";
}
}
Quando usar XML/XSL/XSLT?
Vantagens
- Não é específico para J2EE
como JSP
- O mundo Microsoft usa muito XSLT
- Não é só para ambiente Web
como JSP
- XSLT é uma tecnologia empregável em
várias situações, não
apenas para gerar HTML
- É um transformador geral de XML para outra
representação
- É superior a outras
soluções quando os dados são
estruturados em árvore
- XSLT tem excelente funcionalidade de sort (para gerar
relatórios)
- O markup gerado sempre será "bem formado"
- XSLT nos força a gerar dados em XML, o que pode
acarretar outros benefícios
Desvantagens
- XSLT tem sintaxe complexa
- O desempenho é inferior a JSP
- A diferença não é
crítica para a maioria das aplicações
- Integração com J2EE é
menor do que JSP
- Se os dados não estiverem em XML, temos que
fazer um processamento adicional para gerar o XML primeiro
Exemplos
- Exemplos de como gerar html, TeX e Java. aqui
Bibliografia