Suporte de bibliotecas XML em Java
1. Introdução
Neste artigo, compararemos bibliotecas Java XML e APIs.
Este é o segundo artigo da série sobre suporte Java para XML, se você quiser se aprofundar no suporte XPath em Java, dê uma olhada emthe previous article.
2. Visão geral
Agora, vamos nos aprofundar no suporte mundial a XML e, para isso, começaremos explicando o mais simples possível todas as iniciais relacionadas ao assunto.
No suporte a Java XML, podemos encontrar poucas definições de API, cada uma com seus prós e contras.
-
SAX: é uma API de análise baseada em evento, fornece um acesso de baixo nível, é eficiente em termos de memória e mais rápida que o DOM, pois não carrega toda a árvore de documentos na memória, mas não fornece suporte para navegação como o fornecido pelo XPath, embora seja mais eficiente, é mais difícil de usar.
-
DOM: É como um analisador baseado em modelo que carrega um documento de estrutura em árvore na memória, então temos a ordem dos elementos originais, podemos navegar em nosso documento em ambas as direções, fornece uma API para leitura e escrita, oferece manipulação de XML e é muito fácil de usar, embora o preço seja alto consumo de recursos de memória.
-
StAX: Oferece a facilidade do DOM e a eficiência do SAX, mas carece de algumas funcionalidades fornecidas pelo DOM como a manipulação de XML e apenas nos permite navegar no documento para frente.
-
JAXB: nos permite navegar no documento em ambas as direções, é mais eficiente que o DOM, permite a conversão de XML para tipos de java e suporta a manipulação de XML, mas só pode analisar um documento XML válido.
Você ainda pode encontrar algumas referências ao JAXP, mas a última versão deste projeto é de março de 2013 e está praticamente morta.
Tabela APIs XML
3. O XML
Nesta seção, veremos as implementações mais populares, para que possamos testar amostras de trabalho reais e verificar as diferenças entre elas.
Nos exemplos a seguir, trabalharemos com um arquivo XML simples com uma estrutura como esta:
Guava
Introduction to Guava
04/04/2016
GuavaAuthor
...
4. DOM4J
Vamos começar dando uma olhada no que podemos fazer comDOM4Je, para este exemplo, precisamos adicionar a última versão destedependency.
Esta é uma das bibliotecas mais populares para trabalhar com arquivosXML, pois nos permite realizar a leitura bidirecional, criar novos documentos e atualizar os existentes.
DOM4J pode trabalhar comDOM,SAX,XPatheXLST. SAX é compatível comJAXP. __
Vamos dar uma olhada aqui, por exemplo, como podemos selecionar uma filtragem de elemento por um determinado id.
SAXReader reader = new SAXReader();
Document document = reader.read(file);
List elements = document.selectNodes("//*[@tutId='" + id + "']");
return elements.get(0);
A classeSAXReader é responsável por criar uma árvoreDOM4J a partir de eventos de análise deSAX. Assim que tivermos umorg.dom4j.Document, precisamos apenas chamar o método necessário e passar para ele a expressãoXPath como umString.
Podemos carregar um documento existente, fazer alterações no seu conteúdo e atualizar o arquivo original.
for (Node node : nodes) {
Element element = (Element)node;
Iterator iterator = element.elementIterator("title");
while (iterator.hasNext()) {
Element title =(Element)iterator.next();
title.setText(title.getText() + " updated");
}
}
XMLWriter writer = new XMLWriter(
new FileWriter(new File("src/test/resources/example_updated.xml")));
writer.write(document);
writer.close();
No exemplo acima, estamos alterando o conteúdo de cada título e criando um novo arquivo.
Observe aqui como é simples obter todos osnode de título em uma lista chamandoelementIteratore passando o nome donode.
Assim que tivermos nosso conteúdo modificado, usaremos oXMLWriter que pega uma árvoreDOM4J e a formata em um fluxo comoXML.
Criar um novo documento a partir do zero é tão simples como podemos ver abaixo.
Document document = DocumentHelper.createDocument();
Element root = document.addElement("XMLTutorials");
Element tutorialElement = root.addElement("tutorial").addAttribute("tutId", "01");
tutorialElement.addAttribute("type", "xml");
tutorialElement.addElement("title").addText("XML with Dom4J");
...
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(
new FileWriter(new File("src/test/resources/example_new.xml")), format);
writer.write(document);
writer.close();
DocumentHelper nos dá uma coleção de métodos para usar porDOM4J, comocreateDocument que cria um documento vazio para começar a trabalhar com ele.
Podemos criar quantos atributos ou elementos precisarmos com os métodos fornecidos porDOM4J, e assim que tivermos nosso documento concluído, apenas gravamos em um arquivo como fizemos com o caso de atualização anterior.
5. JDOM
Para trabalhar comJDOM,, temos que adicionar estedependency ao nosso pom.
O estilo de trabalho deJDOM’s é muito semelhante aoDOM4J’s, então vamos dar uma olhada em apenas alguns exemplos:
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(this.getFile());
Element tutorials = doc.getRootElement();
List titles = tutorials.getChildren("tutorial");
No exemplo acima, estamos recuperando todos os elementos do elemento raiz de uma forma muito simples, como podemos fazer comDOM4J:
SAXBuilder builder = new SAXBuilder();
Document document = (Document) builder.build(file);
String filter = "//*[@tutId='" + id + "']";
XPathFactory xFactory = XPathFactory.instance();
XPathExpression expr = xFactory.compile(filter, Filters.element());
List node = expr.evaluate(document);
Novamente, aqui no código acima, temos umSAXBuilder criando uma instânciaDocument de um determinado arquivo. Estamos recuperando um elemento por seu atributotutId passando uma expressãoXPath para oXPathFactory fornecido porJDOM2.
6. StAX
Agora, vamos ver como podemos recuperar todos os elementos de nosso elemento raiz usandoStax API. Stax está incluído emJDK desde o Java 6, portanto, você não precisa adicionar nenhuma dependência.
Primeiramente, precisamos criar uma classeTutorial:
public class Tutorial {
private String tutId;
private String type;
private String title;
private String description;
private String date;
private String author;
// standard getters and setters
}
e então estamos prontos para seguir com:
List tutorials = new ArrayList<>();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(this.getFile()));
Tutorial current;
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
switch (event.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
StartElement startElement = event.asStartElement();
String qName = startElement.getName().getLocalPart();
...
break;
case XMLStreamConstants.CHARACTERS:
Characters characters = event.asCharacters();
...
break;
case XMLStreamConstants.END_ELEMENT:
EndElement endElement = event.asEndElement();
// check if we found the closing element
// close resources that need to be explicitly closed
break;
}
}
No exemplo acima, para nos ajudar a recuperar as informações, precisamos criar uma classe para armazenar os dados recuperados.
Para ler o documento, declaramos o que é chamado de manipuladores de eventos e os usamos para navegar pelo documento adiante. Lembre-se de que as implementações SAX não fornecem navegação bidirecional. Como você pode ver aqui, muito trabalho precisa ser feito apenas para recuperar uma lista simples de elementos.
7. JAXB
JAXB está incluído noJDK, assim como o Xerces, não precisa de nenhuma dependência extra para este.
É muito simples carregar, criar e manipular informações de um arquivoXML usandoJAXB.
Precisamos apenas criar as entidades java corretas para vincularXMLe é isso.
JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Tutorials tutorials = (Tutorials) jaxbUnmarshaller.unmarshal(this.getFile());
No exemplo acima, carregamos nosso arquivoXML em nosso objeto e a partir daí podemos lidar com tudo como uma estrutura Java normal;
Para criar um novo documento, é tão simples quanto lê-lo, mas fazendo o caminho inverso, como feito no código abaixo.
Em primeiro lugar, vamos modificar nossa classeTutorial para adicionar anotaçõesJAXB agettersesetters:
public class Tutorial {
...
public String getTutId() {
return tutId;
}
@XmlAttribute
public void setTutId(String tutId) {
this.tutId = tutId;
}
...
@XmlElement
public void setTitle(String title) {
this.title = title;
}
...
}
@XmlRootElement
public class Tutorials {
private List tutorial;
// standard getters and setters with @XmlElement annotation
}
Com@XmlRootElement definimos qual objeto vai representar o nó raiz do nosso documento e então usamos@XmlAttribute ou@XmlElement para definir se esse atributo representa um atributo de um nó ou um elemento de o documento.
Então podemos seguir com:
Tutorials tutorials = new Tutorials();
tutorials.setTutorial(new ArrayList<>());
Tutorial tut = new Tutorial();
tut.setTutId("01");
...
tutorials.getTutorial().add(tut);
JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(tutorials, file);
Como você pode ver, vincular arquivo XML a objetos Java é a maneira mais fácil de trabalhar com esse tipo de arquivo.
8. Suporte para Expressão XPath
Para criar expressões XPath complexas, podemos usar o Jaxen. Esta é uma biblioteca XPath de código aberto adaptável a muitos modelos de objetos diferentes, incluindoDOM,XOM,DOM4J eJDOM.
Podemos criar expressões XPath e compilá-las em vários documentos suportados.
String expression = "/tutorials/tutorial";
XPath path = new DOMXPath(expression);
List result = path.selectNodes(xmlDocument);
Para fazer funcionar, precisaremos adicionar estedependency ao nosso projeto.
9. Conclusão
Como você pode ver, existem muitas opções para trabalhar comXML, dependendo dos requisitos de sua aplicação, você pode trabalhar com qualquer uma delas ou pode ter que escolher entre eficiência e simplicidade.
Você pode encontrar os exemplos de trabalho completos para este artigo em nosso repositório githere.