#java #xml #data-binding #jaxb #jibx
#java #xml #привязка к данным #jaxb #jibx
Вопрос:
будучи новичком в привязке Java XML, я сталкиваюсь с проблемой.
Допустим, у меня есть сценарий, в котором построена моя модель домена, и я хочу упорядочить этот домен в соответствии со структурой xml.
Теперь я хочу предоставить другой путь unmarshall:
- Маршалировать весь объектный граф [здесь проблем нет]
- Маршалируйте 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>