Contents

Como ler e escrever ficheiros XML com Java

Os ficheiros XML podem servir uma variedade de objectivos, incluindo o armazenamento de dados. Antes de o JSON se tornar popular, o XML era o formato preferido para representar, armazenar e transportar dados estruturados.

Apesar do declínio da sua prevalência nos tempos actuais, ainda é possível encontrar XML de vez em quando. Por isso, é crucial adquirir proficiência no trabalho com este formato. Explore os meandros da utilização da Interface de Programação de Aplicação (API) do Modelo de Objeto de Documento (DOM) para ler e escrever documentos XML utilizando Java como ferramenta principal.

Requisitos para o processamento de XML em Java

A Java Standard Edition, ou SE, inclui a API Java para processamento de XML, normalmente referida como JAXP, uma estrutura abrangente que engloba várias facetas do tratamento de XML. Este repertório alargado é constituído por vários componentes integrais, incluindo:

O Document Object Model (DOM) engloba um conjunto de classes que facilitam a manipulação de componentes XML, incluindo elementos, nós e atributos. No entanto, dado que foi concebido para carregar um ficheiro XML inteiro para a memória para processamento, não está idealmente equipado para lidar eficazmente com documentos de dimensões substanciais.

A Simple API for XML (SAX) é um mecanismo de análise ligeiro concebido especificamente para tratar documentos XML. Ao contrário do Document Object Model (DOM), que constrói toda uma estrutura em árvore durante o processamento, o SAX funciona através do disparo de eventos baseados no conteúdo XML encontrado durante a análise de um ficheiro. Esta abordagem reduz o consumo de memória e permite uma maior flexibilidade em termos de tratamento de grandes quantidades de dados. No entanto, a utilização do SAX pode ser um pouco difícil em comparação com a utilização do DOM devido à sua dependência de paradigmas de programação baseados em eventos.

StAX, ou a API de fluxo contínuo para XML, representa uma adição mais recente ao domínio do processamento de XML. Com capacidades de desempenho impressionantes em termos de filtragem, processamento e modificação de fluxos, esta poderosa ferramenta consegue atingir os seus objectivos sem necessitar de carregar documentos XML para a memória. Em contraste com a arquitetura orientada para eventos favorecida pela API SAX, o StAX emprega uma abordagem do tipo pull que o torna mais simples e mais fácil de utilizar quando se trata de codificação.

Para tratar dados XML numa aplicação Java, é necessário incorporar determinados pacotes que facilitam esta funcionalidade. Estes pacotes fornecem vários métodos e classes para analisar, manipular e gerar documentos XML.

 import javax.xml.parsers.*;
import javax.xml.transform.*;
import org.w3c.dom.*;

Preparar um ficheiro XML de amostra

/pt/images/sample-xml-file-from-microsoft.jpeg

Para compreender o código de amostra e os conceitos subjacentes, utilize este ficheiro XML de amostra da Microsoft . Aqui está um excerto:

 <?xml version="1.0"?>
<catalog>
  <book id="bk101">
    <author>Gambardella, Matthew</author>
    <title>XML Developer's Guide</title>
    <genre>Computer</genre>
    <price>44.95</price>
    <publish_date>2000-10-01</publish_date>
    <description>An in-depth look at creating applications
      with XML.</description>
  </book>
  <book id="bk102">
    <author>Ralls, Kim</author>
...snipped... 

Ler o ficheiro XML com a API DOM

Para processar eficazmente um ficheiro XML utilizando a Interface de Programação de Aplicações do Modelo de Objectos de Documento (DOM), temos de criar primeiro uma instância da classe DocumentBuilder , que facilitará a análise do documento XML.

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder(); 

Pode agora optar-se por armazenar a totalidade do documento na memória, começando pelo elemento raiz do XML, que neste caso corresponde ao elemento “catálogo”.

 // XML file to read
File file = "<path_to_file>";
Document document = builder.parse(file);
Element catalog = document.getDocumentElement();

De facto, ao utilizar esta abordagem, obtém-se acesso completo à totalidade do documento XML, começando pelo seu nó principal, nomeadamente o elemento “catálogo”.

Extração de informação utilizando a API DOM

Depois de obter o elemento raiz utilizando o analisador XML, pode utilizar a API Document Object Model (DOM) para aceder a informações valiosas no seu interior. Como exemplo, recuperar todos os descendentes imediatos do elemento raiz e iterar através deles é uma abordagem prática. No entanto, tenha em atenção que o método getChildNodes() devolve todos os tipos de filhos, incluindo nós de texto e nós de comentários, que não são relevantes para a nossa tarefa atual. Por conseguinte, devemos visar especificamente apenas os elementos filhos ao processar estes resultados.

 NodeList books = catalog.getChildNodes();

for (int i = 0, ii = 0, n = books.getLength() ; i < n ; i\\+\\+) {
  Node child = books.item(i);

  if ( child.getNodeType() != Node.ELEMENT_NODE )
    continue;

  Element book = (Element)child;
  // work with the book Element here
}

Para localizar um elemento filho específico sob seu pai em um documento XML usando C#, é possível criar um método estático que itera sobre a coleção de nós filhos para identificar o elemento desejado com base em seu nome. Se o elemento for descoberto durante esse processo, ele será retornado; caso contrário, null representa o resultado.

 static private Node findFirstNamedElement(Node parent,String tagName)
{
  NodeList children = parent.getChildNodes();

  for (int i = 0, in = children.getLength() ; i < in ; i\\+\\+) {
    Node child = children.item(i);

    if (child.getNodeType() != Node.ELEMENT_NODE)
      continue;

    if (child.getNodeName().equals(tagName))
      return child;
  }

  return null;
}

Tenha em atenção que a API DOM classifica o conteúdo textual incluído num elemento como um nó individual da categoria TEXT\_NODE. O conteúdo textual pode incluir vários nós de texto contíguos, necessitando de um tratamento específico para obter o texto de um determinado elemento:

 static private String getCharacterData(Node parent)
{
  StringBuilder text = new StringBuilder();

  if ( parent == null )
    return text.toString();

  NodeList children = parent.getChildNodes();

  for (int k = 0, kn = children.getLength() ; k < kn ; k\\+\\+) {
    Node child = children.item(k);

    if (child.getNodeType() != Node.TEXT_NODE)
      break;

    text.append(child.getNodeValue());
  }

  return text.toString();
}

Utilizando as funções utilitárias fornecidas, vamos examinar um exemplo que extrai dados pertinentes de um documento XML que representa um catálogo de livros.O código que se segue apresenta pormenores completos sobre cada publicação individual contida no referido catálogo:

 NodeList books = catalog.getChildNodes();

for (int i = 0, ii = 0, n = books.getLength() ; i < n ; i\\+\\+) {
  Node child = books.item(i);

  if (child.getNodeType() != Node.ELEMENT_NODE)
    continue;

  Element book = (Element)child;
  ii\\+\\+;

  String id = book.getAttribute("id");
  String author = getCharacterData(findFirstNamedElement(child, "author"));
  String title = getCharacterData(findFirstNamedElement(child, "title"));
  String genre = getCharacterData(findFirstNamedElement(child, "genre"));
  String price = getCharacterData(findFirstNamedElement(child, "price"));
  String pubdate = getCharacterData(findFirstNamedElement(child, "pubdate"));
  String descr = getCharacterData(findFirstNamedElement(child, "description"));

  System.out.printf("%3d. book id = %s\n" \\+
    " author: %s\n" \\+
    " title: %s\n" \\+
    " genre: %s\n" \\+
    " price: %s\n" \\+
    " pubdate: %s\n" \\+
    " descr: %s\n",
    ii, id, author, title, genre, price, pubdate, descr);
}

Segue-se uma explicação passo a passo do código:

O código examina os jovens da ninhada, ou componente de raiz, que serve de base a toda a estrutura.

Para cada nó filho individual, que corresponde a um livro em particular, o programa verifica se a sua estrutura de dados subjacente possui a caraterística de ser um ELEMENTO\_NÓIDE. Caso este pré-requisito não seja cumprido, o processo prossegue para a iteração seguinte.

Se um nó filho do tipo ELEMENT\_NODE for encontrado no processo de travessia da árvore DOM, a propriedade filho será convertida numa instância da interface Element .

A execução subsequente do programa envolve a extração de múltiplos atributos e dados de caracteres associados a um elemento de livro especificado, como o seu identificador único (“id”), nome do autor, título, género, preço, data de publicação e informações descritivas. Esta informação extraída é posteriormente impressa na consola utilizando o método System.out.printf() para fins de apresentação.

Aqui está o aspeto da saída:

/pt/images/parsing-xml-in-java-source-code-and-output.jpeg

Escrevendo saída XML usando a API de transformação

Java oferece a API de transformação XML como um meio de manipular dados XML. Esta API é utilizada em conjunto com a transformação de identidade para produzir resultados. Para ilustrar, considere a possibilidade de aumentar o catálogo de exemplo anterior, incorporando um novo elemento de livro.

As informações relativas a uma obra literária, incluindo o autor e o título, podem ser obtidas a partir de um recurso externo, como uma base de dados ou um ficheiro de propriedades. O ficheiro de propriedades fornecido serve de modelo para este fim.

 id=bk113
author=Jane Austen
title=Pride and Prejudice
genre=Romance
price=6.99
publish_date=2010-04-01
description="It is a truth universally acknowledged, that a single man in possession of a good fortune must be in want of a wife." So begins Pride and Prejudice, Jane Austen's witty comedy of manners-one of the most popular novels of all time-that features splendidly civilized sparring between the proud Mr. Darcy and the prejudiced Elizabeth Bennet as they play out their spirited courtship in a series of eighteenth-century drawing-room intrigues.

Para processar um documento XML, é necessário utilizar a técnica de análise descrita anteriormente. Isto envolve a decomposição da estrutura baseada em texto do ficheiro e a extração de informação relevante para análise ou manipulação posterior.

 File file = ...; // XML file to read
Document document = builder.parse(file);
Element catalog = document.getDocumentElement();

Utilizando a classe Properties fornecida na linguagem de programação Java, é possível recuperar e processar eficazmente as informações armazenadas num ficheiro de configuração externo separado, designado por ficheiro “properties”. Este processo envolve uma complexidade de codificação mínima, simplificando a integração de preferências ou definições definidas pelo utilizador com a lógica geral da aplicação.

 String propsFile = "<path_to_file>";
Properties props = new Properties();

try (FileReader in = new FileReader(propsFile)) {
  props.load(in);
}

Ao carregar o ficheiro de propriedades, é possível extrair os valores desejados para adição a partir do referido ficheiro.

 String id = props.getProperty("id");
String author = props.getProperty("author");
String title = props.getProperty("title");
String genre = props.getProperty("genre");
String price = props.getProperty("price");
String publish_date = props.getProperty("publish_date");
String descr = props.getProperty("description");

Agora, crie um elemento vaziobookelement.

 Element book = document.createElement("book");
book.setAttribute("id", id);

A incorporação dos componentes individuais do livro no corpus textual apresenta-se como uma tarefa simples. Para facilitar este processo, é possível compilar um catálogo das designações necessárias, organizando-as numa coleção designada por “Lista”. Ao executar uma operação recorrente dentro desta lista, as respectivas entradas podem ser eficientemente anexadas ao quadro narrativo mais alargado.

 List<String> elnames =Arrays.asList("author", "title", "genre", "price",
  "publish_date", "description");

for (String elname : elnames) {
  Element el = document.createElement(elname);
  Text text = document.createTextNode(props.getProperty(elname));
  el.appendChild(text);
  book.appendChild(el);
}

catalog.appendChild(book);

O componente do catálogo acima mencionado possui atualmente uma entidade adicional, recentemente introduzida, que é o livro. A única tarefa que resta é formular o documento XML (Extensible Markup Language) revisto que inclui as referidas actualizações.

Para gerar um documento XML utilizando um transformador, é necessário obter primeiro uma instanciação do referido transformador. Isto pode ser conseguido através da implementação do código necessário numa linguagem de programação ou num ambiente de desenvolvimento. Por exemplo, em Python, pode utilizar-se a biblioteca transformers e as suas funções associadas para construir uma instância de um transformador para utilização em tarefas de processamento de linguagem natural.

 TransformerFactory tfact = TransformerFactory.newInstance();
Transformer tform = tfact.newTransformer();
tform.setOutputProperty(OutputKeys.INDENT, "yes");
tform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3"); 

Pode utilizar o método setOutputProperty() para especificar o nível de indentação pretendido na saída gerada.

A última fase envolve a execução do processo de conversão. O resultado é apresentado através do fluxo de saída, que pode ser observado através da monitorização da consola ou do terminal onde o programa está a ser executado.

 tform.transform(new DOMSource(document), new StreamResult(System.out));

Para guardar a saída do programa num ficheiro em vez de a imprimir na consola, pode utilizar-se a seguinte abordagem:

 tform.transform(new DOMSource(document), new StreamResult(new File("output.xml")));

Para ler e escrever ficheiros XML (Extensible Markup Language) utilizando a linguagem de programação Java, é necessário executar sequencialmente uma série de acções processuais. Estas incluem a definição de um objeto de documento XML, a criação de nós dentro desse documento, a ligação de elementos filhos a nós pais, a especificação de atributos de elementos, a adição ou inserção de novos nós em várias posições dentro do documento e, finalmente, o fecho de quaisquer etiquetas abertas antes de terminar o processo.

Agora já sabe como ler e escrever ficheiros XML com Java

A utilização de Java para analisar e manipular Extensible Markup Language (XML) é uma competência indispensável frequentemente encontrada em aplicações práticas. As APIs Document Object Model (DOM) e Transformation são notavelmente benéficas para este fim.

Obter uma compreensão abrangente do Modelo de Objeto de Documento (DOM) é indispensável para os programadores que procuram criar scripts do lado do cliente para aplicações baseadas na Web ou websites. Felizmente, a arquitetura do DOM está normalizada em várias linguagens de programação, permitindo uma manipulação consistente através de código escrito em linguagens como Java e JavaScript.