如何使用 JAX-B 从 XML 中读取所选 class 的对象(多态)
How to read objects (Polymorphic) of the chosen class, from the XML using JAX-B
我创建了一个多态对象列表。我可以将它们转换为 XML ,反之亦然(使用 JAXB 编组和解组。)但我只想读取所选 class.
中的对象
我使用了一些关于通过 JAXB 转换对象列表的教程,例如这个:
http://memorynotfound.com/convert-xml-to-polymorphic-object-using-jax-b/ or this one: http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-using-substitution.html
我有动物列表,还有两个扩展抽象动物 class、狗、猫和鸟的 classes。我将该列表(包含狗和猫)保存到 XML,并且我只想从 XML 文件中获取猫。可以制作吗?
使用教程中的代码 -> http://memorynotfound.com/convert-xml-to-polymorphic-object-using-jax-b/
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root)unmarshaller.unmarshal(new StringReader(xml));
我会得到输出:
Root{animals=[com.memorynotfound.xml.jaxb.Dog@520a3426, com.memorynotfound.xml.jaxb.Cat@18eed359,com.memorynotfound.xml.jaxb.Bird@643bd123]}
我努力实现的是:
Root{animals=[ com.memorynotfound.xml.jaxb.Cat@18eed359]}
在其中一个答案中,我了解到 XMLEvent。这是一个非常好的主意,但几乎每个教程都谈到过滤。我想要实现的是摆脱所有其他 classes。
我尝试更改代码:
public XMLEvent nextEvent() throws XMLStreamException {
// Read next event
XMLEvent e = super.nextEvent();
// If it's a start element for dog
if (e.getEventType() == XMLEvent.START_ELEMENT && ("Cat".equals(e.asStartElement().getName().getLocalPart()) ||
"Bird".equals(e.asStartElement().getName().getLocalPart()))
)
{
// Then run through events until a closing dog event
do {
e = super.nextEvent();
} while (e.getEventType() != XMLEvent.END_ELEMENT || ! ("Cat".equals(e.asStartElement().getName().getLocalPart()) ||
"Bird".equals(e.asStartElement().getName().getLocalPart()))
);
// then read next event after the ends
e = super.nextEvent();
}
return e;
}
但是没有用,所以我不确定我是否理解解决方案。
由于在根中 class animals 将 dog 和 cat 作为元素,如果可用,它会尝试将其编组到这两个对象。
一种实现您想要的方法是删除 XmlElementWrapper 下的一个元素。
@XmlElementWrapper(name = "animals")
@XmlElements({
@XmlElement(name = "cat", type = Cat.class)
})
public void setAnimals(List<Animal> animals) {
this.animals = animals;
}
以上会给你:
Root{animals=[ com.memorynotfound.xml.jaxb.Cat@18eed359]}
您可以创建自定义 javax.xml.stream.XMLEventReader
并过滤一些事件。这是一个愚蠢但有效的例子:
public final class FilteredXmlEventReader extends EventReaderDelegate {
final Set<String> filteredElements;
FilteredXmlEventReader(XMLEventReader delegate, String... filteredElements) {
super(delegate);
this.filteredElements = new HashSet<String>(Arrays.asList(filteredElements));
}
public XMLEvent nextEvent() throws XMLStreamException {
// Read next event
XMLEvent e = super.nextEvent();
// If it's a start element for any filtered
if (e.getEventType() == XMLEvent.START_ELEMENT && filteredElements.contains(e.asStartElement().getName().getLocalPart())) {
String element = e.asStartElement().getName().getLocalPart();
// Then run through events until a closing similar element
do {
e = super.nextEvent();
} while (e.getEventType() != XMLEvent.END_ELEMENT || !element.equals(e.asEndElement().getName().getLocalPart()));
// then read next tag after closing element
e = super.nextEvent();
}
return e;
}
}
然后使用此 XMLEventReader
:
解组您的内容
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
XMLEventReader xmlReader = XMLInputFactory.newFactory().createXMLEventReader(new StringReader(xml));
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(new FilteredXmlEventReader(xmlReader, "Dog", "Bird"));
那么Dog
和Birds
元素将不会被读取。
请注意,如果多个筛选元素嵌套在此实现中,可能会出现问题。
编辑:编辑上面的代码以支持多个过滤元素。
我创建了一个多态对象列表。我可以将它们转换为 XML ,反之亦然(使用 JAXB 编组和解组。)但我只想读取所选 class.
中的对象我使用了一些关于通过 JAXB 转换对象列表的教程,例如这个: http://memorynotfound.com/convert-xml-to-polymorphic-object-using-jax-b/ or this one: http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-using-substitution.html 我有动物列表,还有两个扩展抽象动物 class、狗、猫和鸟的 classes。我将该列表(包含狗和猫)保存到 XML,并且我只想从 XML 文件中获取猫。可以制作吗?
使用教程中的代码 -> http://memorynotfound.com/convert-xml-to-polymorphic-object-using-jax-b/
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root)unmarshaller.unmarshal(new StringReader(xml));
我会得到输出:
Root{animals=[com.memorynotfound.xml.jaxb.Dog@520a3426, com.memorynotfound.xml.jaxb.Cat@18eed359,com.memorynotfound.xml.jaxb.Bird@643bd123]}
我努力实现的是:
Root{animals=[ com.memorynotfound.xml.jaxb.Cat@18eed359]}
在其中一个答案中,我了解到 XMLEvent。这是一个非常好的主意,但几乎每个教程都谈到过滤。我想要实现的是摆脱所有其他 classes。 我尝试更改代码:
public XMLEvent nextEvent() throws XMLStreamException {
// Read next event
XMLEvent e = super.nextEvent();
// If it's a start element for dog
if (e.getEventType() == XMLEvent.START_ELEMENT && ("Cat".equals(e.asStartElement().getName().getLocalPart()) ||
"Bird".equals(e.asStartElement().getName().getLocalPart()))
)
{
// Then run through events until a closing dog event
do {
e = super.nextEvent();
} while (e.getEventType() != XMLEvent.END_ELEMENT || ! ("Cat".equals(e.asStartElement().getName().getLocalPart()) ||
"Bird".equals(e.asStartElement().getName().getLocalPart()))
);
// then read next event after the ends
e = super.nextEvent();
}
return e;
}
但是没有用,所以我不确定我是否理解解决方案。
由于在根中 class animals 将 dog 和 cat 作为元素,如果可用,它会尝试将其编组到这两个对象。
一种实现您想要的方法是删除 XmlElementWrapper 下的一个元素。
@XmlElementWrapper(name = "animals")
@XmlElements({
@XmlElement(name = "cat", type = Cat.class)
})
public void setAnimals(List<Animal> animals) {
this.animals = animals;
}
以上会给你:
Root{animals=[ com.memorynotfound.xml.jaxb.Cat@18eed359]}
您可以创建自定义 javax.xml.stream.XMLEventReader
并过滤一些事件。这是一个愚蠢但有效的例子:
public final class FilteredXmlEventReader extends EventReaderDelegate {
final Set<String> filteredElements;
FilteredXmlEventReader(XMLEventReader delegate, String... filteredElements) {
super(delegate);
this.filteredElements = new HashSet<String>(Arrays.asList(filteredElements));
}
public XMLEvent nextEvent() throws XMLStreamException {
// Read next event
XMLEvent e = super.nextEvent();
// If it's a start element for any filtered
if (e.getEventType() == XMLEvent.START_ELEMENT && filteredElements.contains(e.asStartElement().getName().getLocalPart())) {
String element = e.asStartElement().getName().getLocalPart();
// Then run through events until a closing similar element
do {
e = super.nextEvent();
} while (e.getEventType() != XMLEvent.END_ELEMENT || !element.equals(e.asEndElement().getName().getLocalPart()));
// then read next tag after closing element
e = super.nextEvent();
}
return e;
}
}
然后使用此 XMLEventReader
:
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
XMLEventReader xmlReader = XMLInputFactory.newFactory().createXMLEventReader(new StringReader(xml));
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(new FilteredXmlEventReader(xmlReader, "Dog", "Bird"));
那么Dog
和Birds
元素将不会被读取。
请注意,如果多个筛选元素嵌套在此实现中,可能会出现问题。
编辑:编辑上面的代码以支持多个过滤元素。