Dessa vez trago para vocês um guia rápido com as principais funcionalidades da API Java 1.5 para manipular arquivos XML. Gostaria inicialmente de deixar claro que este tutorial não tem o propósito de ensinar conceitos de XML. Portanto, nos próximos parágrafos estarei assumindo que você já tem conhecimento sobre o referido tópico. Esse artigo é dividido em quatro seções. A primeira mostra um mapeamento entre elementos de um arquivo XML e classes em Java. A segunda ensina como transformar um arquivo XML em disco num objeto de manipulação em Java (parsing). Vamos fazer uma breve explanação sobre os principais métodos de acesso a dados já em memória na seção 3. E, finalmente, iremos mostrar como fazer consulta a documentos XML na seção 4.
Representação de elementos XML
A fim de facilitar o entendimento desta seção, vamos utilizar o documento XML abaixo e ilustrar a partir dele como é feita a representação de cada elemento após ele ser carregado em memória através do parsing (explicado na seção seguinte).
<html>
<head>
<title>Título</title>
</head>
<body onload="javascript:alert('Olá!')">
<p>Olá Mundo!</p>
</body>
</html>
Todo o documento acima e informações de controle interno como codificação do texto são mapeados e acessados através da interface org.w3c.dom.Document. Ou seja, idealmente após fazer o parsing teremos um objeto que implementa essa interface, que é a visão mais “macro” de um arquivo XML em memória.
Numa visão mais detalhada do arquivo, temos a introdução de conceitos como Node, Element, Attr e Text, todos do pacote org.w3c.dom. Tanto o elemento Document quanto o Element, Attr e Text herdam da interface Node, ou seja, todos esses elementos são vistos como sendo nós da árvore XML.
Parsing
Uma das maneiras de se realizar o parsing de um arquivo XML é através do método parse(File f) da classe javax.xml.parsers.DocumentBuilder. Veja o trecho de código abaixo que mostra como se obter um Document através de um arquivo em disco:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(false);
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
Document doc = docBuilder.parse(new File("arquivo.xml"));
Para que o parsing suporte namespaces é necessário mudar o valor de false para true na linha em vermelho no código acima. Observe que o conceito e a utilização de namespaces foge ao escopo deste documento.
Agora que estamos com um Document em mãos, vamos mostrar como navegar através dos seus elementos, modificar seu conteúdo e gravá-lo em disco.
Métodos de manipulação de elementos
Além de todos os métodos definidos pela interface Node, a interface Document provê métodos para criação de atributos (Attr), elementos (Element) e textos (Text). Veja um resumo de como fazer isso:
- createAttribute(String name) – Cria e retorna um atributo que pode ser inserido em qualquer elemento do tipo Element através do método setAttributeNode(Attr newAttr).
- createElement(String tagName) – Cria e retorna um Element que pode ser inserido em outros Elements através do método appendChild(Node newChild) da interface Node.
- createTextNode(String data) – Cria e retorna elementos do tipo Text que podem ser inseridos através do mesmo appendChild citado acima em elementos do tipo Element.
A interface Document também possui um método getDocumentElement para obtenção do elemento raiz do XML. Tendo esse elemento do tipo Element em mãos, vamos mostrar um exemplo de código usando o XML da Listagem 1.
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.sun.org.apache.xpath.internal.XPathAPI;
public class Exemplo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
Document doc = docBuilder.parse(new File(“arquivo.xml”));
// mudando o valor de 'title'
Element htmlTag = doc.getDocumentElement();
Element headTag =
(Element) htmlTag.getElementsByTagName("head").item(0);
Element titleTag =
(Element) headTag.getElementsByTagName("title").item(0);
titleTag.setTextContent("Novo título");
// adicionando mais parágrafos em 'body'
Element p1Tag = doc.createElement("p");
p1Tag.setAttribute("class", "black");
p1Tag.setTextContent("Um novo parágrafo... ;)");
Element p2Tag = doc.createElement("p");
p2Tag.setAttribute("class", "white");
p2Tag.setTextContent("Outro parágrafo..");
Element p3Tag = doc.createElement("p");
p3Tag.setAttribute("class", "black");
p3Tag.setTextContent("Fim !");
Element bodyTag =
(Element) htmlTag.getElementsByTagName("body").item(0);
bodyTag.appendChild(p1Tag);
bodyTag.appendChild(p2Tag);
bodyTag.appendChild(p3Tag);
// removendo atributo 'onload'
bodyTag.removeAttribute("onload");
// removendo o primeiro parágrafo de 'body'
NodeList pTags = bodyTag.getElementsByTagName("p");
Node p1 = pTags.item(0);
bodyTag.removeChild(p1);
// fazendo uma consulta XPath
NodeList resultado = XPathAPI.selectNodeList(bodyTag,
"p[@class = 'black']");
for (int i = 0; i < resultado.getLength(); i++) {
System.out.println("?: " +
resultado.item(i).getTextContent());
}
}
}
Após a execução do exemplo acima, gostaríamos de visualizar como ficou o documento XML final. Podemos fazer isso “serializando” o documento usando um OutputStream (System.out ou até mesmo um FileOutputStream). Veja o exemplo abaixo:
XMLSerializer serializer = new XMLSerializer(System.out, new
OutputFormat(doc, "iso-8859-1", true));
serializer.serialize(doc);
Alguns dos métodos estáticos disponíveis na XPathAPI são:
- eval(Node contextNode, String str) Realiza tanto consultas como avalia funções XPath e retornam um objeto org.apache.xpath.objects.XObject que pode encapsular strings, números, listas, entre outros a depender do que for passado no parâmetro str. O contextNode é o nó que informa o ponto inicial da execução de uma busca.
- selectNodeList(Node contextNode, String str) Realiza consultas XPath e retorna uma lista de elementos XML (Nodes). O contextNode é o nó que informa o ponto inicial da execução de uma busca.
- selectSingleNode(Node contextNode, String str) Executa a mesma operação do método acima, porém retorna apenas o primeiro Node encontrado.