Как упорядочить objectgraph с привязкой Java XML к определенной глубине?

#java #xml #data-binding #jaxb #jibx

#java #xml #привязка к данным #jaxb #jibx

Вопрос:

будучи новичком в привязке Java XML, я сталкиваюсь с проблемой.

Допустим, у меня есть сценарий, в котором построена моя модель домена, и я хочу упорядочить этот домен в соответствии со структурой xml.

Теперь я хочу предоставить другой путь unmarshall:

  1. Маршалировать весь объектный граф [здесь проблем нет]
  2. Маршалируйте objectgraph до определенной глубины!!! [задача]

Я не могу найти хороший способ решить эту проблему, не внося большой сложности. Можно создать копию домена и позже вручную, но это кажется неправильным. Любые другие доступные решения?

Ответ №1:

Вы могли бы использовать XmlAdapter и Marshal.Прослушиватель, чтобы получить это поведение:

ДЕМОНСТРАЦИЯ

Маршалирование.Прослушиватель будет настроен на отслеживание глубины дерева, которое мы маршалируем. Также мы установим XML-адаптеры уровня выполнения, которые знают о прослушивателе глубины. Эти адаптеры начнут возвращать значение null, когда будет достигнута желаемая глубина.

 import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Root rootA = new Root();
        rootA.setName("A");

        Root rootB = new Root();
        rootB.setName("B");
        rootA.setChild(rootB);

        Root rootC = new Root();
        rootC.setName("C");
        rootB.setChild(rootC);

        Root rootD = new Root();
        rootD.setName("D");
        rootC.setChild(rootD);

        Root rootE = new Root();
        rootE.setName("E");
        rootD.setChild(rootE);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        DepthListener depthListener = new DepthListener(3);
        marshaller.setListener(depthListener);
        marshaller.setAdapter(new RootAdapter(depthListener));
        marshaller.marshal(rootA, System.out);
    }

}
  

DepthListener

Цель этого класса — отслеживать текущую глубину.

 import javax.xml.bind.Marshaller;

public class DepthListener extends Marshaller.Listener {

    private int targetDepth;
    private int currentDepth = 0;

    public DepthListener(int depth) {
        this.targetDepth = depth;
    }

    @Override
    public void beforeMarshal(Object source) {
        currentDepth  ;
    }

    @Override
    public void afterMarshal(Object source) {
        currentDepth--;
    }

    public boolean isMarshalDepth() {
        return currentDepth <= targetDepth; 
    }

}
  

RootAdapter

Цель XmlAdapter — начать возвращать значение null при достижении желаемой глубины, чтобы остановить процесс маршалинга.

 import javax.xml.bind.annotation.adapters.XmlAdapter;

public class RootAdapter extends XmlAdapter<Root, Root> {

    private DepthListener depthListener;

    public RootAdapter() {
    }

    public RootAdapter(DepthListener depthListener) {
        this.depthListener = depthListener;
    }

    @Override
    public Root unmarshal(Root root) throws Exception {
        return root;
    }

    @Override
    public Root marshal(Root root) throws Exception {
        if(depthListener != null amp;amp; !depthListener.isMarshalDepth()) {
            return null;
        }
        return root;
    }

}
  

Root

Ниже показано, как указать XmlAdapter для объекта домена с помощью аннотации @XmlJavaTypeAdapter:

 import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlJavaTypeAdapter(RootAdapter.class)
@XmlType(propOrder={"name", "child"})
public class Root {

    private String name;
    private Root child;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Root getChild() {
        return child;
    }

    public void setChild(Root report) {
        this.child = report;
    }

}
  

Вывод

Ниже приведены выходные данные демонстрационного кода:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <name>A</name>
    <child>
        <name>B</name>
        <child>
            <name>C</name>
        </child>
    </child>
</root>