Dessa vez trago para vocês um guia rápido com as principais funcionalidades da API Java 1.5 para manipular arquivos XML.
Artigos Java Manipulando arquivos XML em Java
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).
<body onload="javascript:alert('Olá!')">
Listagem 1 – Exemplo de um arquivo XML.
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.
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:
Listagem 2 – Carregando um documento de um arquivo.
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.
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.
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());
Listagem 3 – Código mostrando uso da API.
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));
Listagem 4 – Serialização de arquivos XML.
Consultas a elementos
Vamos finalizar este artigo ensinando como usar a org.apache.xpath.XPathAPI para fazer consultas XPath (http://www.w3.org/TR/xpath). Ressalto que não irei focar em como criar a consulta em si, mas sim em como usar a API em sua execução. Para melhor entender sobre XPath, aconselho um excelente material introdutório disponível em www.w3schools.com/xpath.
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.