Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

JAX-B: Parseando lista encadeada com mais de 2 níveis

Pessoal, eu gostaria de saber como posso fazer para parsear utilizando o JAX-B um xml como o abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<setup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="pattern.xsd">
    <customer name="customer">
        <databases>
            <database>
                <name>System1</name>
                <host>host1</host>
                <port>1234</port>
            </database>
            <database>
                <name>System2</name>
                <host>host2</host>
                <port>5677</port>
            </database>
            <database>
                <name>System3</name>
                <host>host3</host>
                <port>9876</port>
            </database>
        </databases>
    </customer>
</setupmonitoria>

Estou tendo dificuldades para acessar os elementos, estou tentando fazer da seguinte maneira mas acredito que não seja o caminho:

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="setup")
@XmlAccessorType(XmlAccessType.FIELD)
public class Setup {

    @XmlAttribute(name="name")
    private String customer;

    @XmlElementWrapper(name="databases")
    @XmlElement(name="database")
    private List<SetupDatabase> databases = new ArrayList<>();

    @Override
    public String toString() {
        return this.databases.toString();
    }

    public String getCustomer() {
        return customer;
    }

    public void setCustomer(String customer) {
        this.customer = customer;
    }

    public List<SetupDatabase> getDatabases() {
        return databases;
    }

    public void setDatabases(List<SetupDatabase> databases) {
        this.databases = databases;
    }
}

Acredito que enquanto temos um xml com uma lista encadeada a outra (por exemplo venda > produtos > produto) tudo bem, agora no meu caso é mais complicado. Também não consigo acessar o atributo da tag.

Agradeço a ajuda de antemão.

8 respostas

Oi Allan,

Cria a classe Customer e dentro dela adiciona o atributo que representa a lista de databases.

Certo Alberto, mas como ficam as annotations? Como eu teria mais uma classe envolvida eu teria que usar o XMLAttribute nela?

solução!

Dentro da classe Customer, vc usaria as annotations que nem aqui:

@XmlElementWrapper(name="databases")
@XmlElement(name="database")

Na verdade vc fez quase tudo certo, já quase lá.

Ah entendi... seria como parsear cada lista do xml para um objeto.. uma "orientação a objeto" do xml. Acredito que se o xml for mto grande ainda seja melhor optar por STAX, não? Apesar do código final ficar mais confuso a possibilidade de trabalhar com eventos me permite navegar pelo XML de forma mais precisa e dinâmica.

Oi Allan, eu só opto por formas mais manuais, como o Stax se eu realmente tiver com um problema de customização ou performance que não consiga resolver com a solução mais simples.. Em geral, com o passar do tempo, manutenção vira um gargalo maior que performance.

Alberto, muito obrigado pela contribuição, fiz o que sugeriu e a implementação funcionou, não foi inserir novamente para não poluir o tópico. Para concluir, como melhor prática, gostaria de uma recomendação sua. Pegue como exemplo o meu xml onde eu tenho vários databases:

<databases>
            <database>
                  ...
            </database>
            <database>
                  ...
            </database>
            <database>
                   ...
            </database>
        </databases>

a idéia é q neste mesmo xml eu tenha outro nó com conexões unix por exemplo, depois outro com conexões RDP, etc... Minha idéia é separar todos esses dados de cada cliente para depois trabalhar com eles num hibernate, jdbc, jsch...

Você acredita que exista a necessidade de separar os dados lidos no xml em demais objetos? Se sim, você me recomenda instanciar esses objetos conforme eu leio o xml (visto que eu vou ler tudo de uma vez) ou ir instanciando objetos separados (sob demanda, numa chamada de método por exemplo)?

Para exemplificar:

1) ler todo o xml onde existem 2 clientes com 2 databases cada

2) Na leitura do XML criasse o Cliente que tem a lista de databases

3) No momento da leitura ou posteriormente, instancio mais objetos que representaram cada database e a forma como manipulo elas (schemas, tabelas, owners, views....)

Entende o que eu digo? "Quebrar" a leitura em demais objetos..

Para começar, eu iria com a primeira opção :). Me parece a mais simples, mesmo que vá consumir mais memória e tal.

Obrigado! vou fazer isso então, leio o xml e instancio tudo no momento da leitura, não tenho nada tão grande também q vá consumir tanta memória, só tenho que assegurar a boa administração dos recursos!

Obrigado Novamente Alberto!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software