#java #xml #jaxb
#java #xml #jaxb
Вопрос:
Я пытаюсь проанализировать XML-файл с вложенными объектами, на которые ссылается уникальный атрибут.
<items>
<item id="firstItem" />
<item id="secondItem">
<dependencies>
<dependency id="firstItem" />
</dependencies>
</item>
</items>
В настоящее время я использую обычный способ и создал новый класс для каждого тега.
@XmlRootElement(name = "items")
public class Items {
private List<Item> items = new ArrayList();
@XmlElement(name = "item")
public List<Item> getItems() {
return items;
}
/* setter */
}
public class Item {
private string id;
private Dependencies dependencies = new Dependencies();
@XmlAttribute(name = "id")
public String getId() {
return id;
}
/* setter */
@XmlElement(name = "dependencies")
public Dependencies getDependencies() {
return dependencies;
}
/* setter */
}
public class Dependencies {
private List<Dependency> dependencies = new ArrayList();
@XmlElement(name = "dependency")
public List<Dependency> getDependencies() {
return dependencies;
}
/* setter */
}
public class Dependency {
private String id;
@XmlAttribute(name = "id")
public String getId() {
return id;
}
/* setter */
}
и прочитайте файл, используя javax.xml.bind.Разархивировщик
Items items = new items();
JAXBContext context = JAXBContext.newInstance(Items.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
items = (Items) unmarshaller.unmarshal(/* My InputStream */);
Предпочтительным результатом был бы единый класс, который может содержать список самого себя.
public class Item {
private List<Item> dependencies = new ArrayList();
}
Возможно ли это с помощью инструментов xml?
Ответ №1:
Вам нужно написать пользовательский адаптер, но даже при этом у вас нет доступа к родительскому списку элементов. Таким образом, вы можете десериализовать идентификаторы в пользовательском адаптере и связать Item
объекты после десериализации. Пример реализации:
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class JaxbApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
JAXBContext context = JAXBContext.newInstance(Items.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Items root = (Items) unmarshaller.unmarshal(xmlFile);
System.out.println(root);
}
}
class ItemXmlAdapter extends XmlAdapter<Object, Item> {
@Override
public Item unmarshal(Object v) {
Element element = (Element) v;
Node dependencies = element.getFirstChild();
List<String> ids = new ArrayList<>();
if (dependencies != null) {
NodeList childNodes = dependencies.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i ) {
Node item = childNodes.item(i);
NamedNodeMap attributes = item.getAttributes();
if (attributes != null) {
Node id = attributes.getNamedItem("id");
if (id != null) {
ids.add(id.getNodeValue());
}
}
}
}
Item item = new Item();
item.setId(element.getAttribute("id"));
item.setDependencyIds(ids);
return item;
}
@Override
public Object marshal(Item v) throws Exception {
return null; // Implement if needed
}
}
@XmlRootElement(name = "items")
class Items {
private List<Item> items = new ArrayList<>();
@XmlElement(name = "item")
public List<Item> getItems() {
return items;
}
}
@XmlJavaTypeAdapter(ItemXmlAdapter.class)
class Item {
private String id;
private List<String> dependencyIds;
private List<Item> dependencies;
// getters, setters
}
Для ваших XML
отпечатков:
Items{items=[Item{id='firstItem', dependencyIds=[]}, Item{id='secondItem', dependencyIds=[firstItem]}]}