Java 如何使用JAX-B从XML中读取所选类的对象(多态)
我创建了一个多态对象列表。我可以将它们转换为XML,反之亦然(marshall和unmarshal使用JAXB),但我只想读取所选类中的对象 我使用了一些关于JAXB转换对象列表的教程,例如: 或者这个: 我有动物列表,还有两个扩展抽象动物类的类,狗,猫和鸟。我将该列表(包含狗和猫)保存为XML,并且我只想从XML文件中获取猫。有可能吗 使用教程中的代码-> 我会感到惊讶: Root{anives=[com.memorynotfound.xml.jaxb。Dog@520a3426,com.memorynotfound.xml.jaxb。Cat@18eed359,com.memorynotfound.xml.jaxb。Bird@643bd123]} 我努力实现的目标是: Root{anives=[com.memorynotfound.xml.jaxb。Cat@18eed359]} 在其中一个答案中,我了解了XMLEvent。这是一个非常好的想法,但几乎每个教程都提到了过滤。我想要达到的是摆脱所有其他类。 我试图更改代码:Java 如何使用JAX-B从XML中读取所选类的对象(多态),java,list,jaxb,polymorphism,Java,List,Jaxb,Polymorphism,我创建了一个多态对象列表。我可以将它们转换为XML,反之亦然(marshall和unmarshal使用JAXB),但我只想读取所选类中的对象 我使用了一些关于JAXB转换对象列表的教程,例如: 或者这个: 我有动物列表,还有两个扩展抽象动物类的类,狗,猫和鸟。我将该列表(包含狗和猫)保存为XML,并且我只想从XML文件中获取猫。有可能吗 使用教程中的代码-> 我会感到惊讶: Root{anives=[com.memorynotfound.xml.jaxb。Dog@520a3426,com.mem
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;
}
但是它不起作用,所以我不确定我是否理解这个解决方案。因为在根类中,动物同时将dog和cat作为元素,它将尝试将其封送到这两个对象(如果可用) 实现所需功能的一种方法是删除XmlElementWrapper下的一个元素
@XmlElementWrapper(name = "animals")
@XmlElements({
@XmlElement(name = "cat", type = Cat.class)
})
public void setAnimals(List<Animal> animals) {
this.animals = animals;
}
您可以创建一个自定义的
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;
}
}
然后,Dog
和Birds
元素将不会被读取
请注意,如果此实现嵌套了多个过滤元素,则可能会出现问题
编辑:编辑上面的代码以支持多个过滤元素。但在这种情况下,我将无法读取狗。我想从所选的类中读取对象,所以只有猫(或者狗,如果用户选择狗类的话)。使用您的解决方案,我将能够只阅读猫,这是真的。但如果用户改变主意,我将无法只阅读狗。首先,感谢您的回复。我读过关于XMLEvent的文章,它看起来是一个非常好的过滤方法。但是如果我有狗,猫和鸟,我只想读猫呢?要过滤除CAT以外的所有类吗?如果(e.getEventType()==XMLEvent.START_元素&&(“Dog.”等于(e.asStartElement().getName().getLocalPart())| |“Bird.”等于(e.asStartElement().getName().getLocalPart())不起作用。如果我尝试不同的方法,但我想不出如何更改代码。我在答案中编写的
FilterDogXmlEventReader
是虚拟的。您可以通过添加一个包含所有筛选值的实例变量来改进它。然后在构建事件读取器时设置筛选值。然后在ll筛选值,而不是只匹配Dog
谢谢,这正是我想要实现的。我需要仔细阅读您是如何做到这一点的,以进一步了解它,但谢谢!我认为您在布尔运算符优先级方面存在问题。我已更新了解决方案,以支持多个筛选值。
Root{animals=[ com.memorynotfound.xml.jaxb.Cat@18eed359]}
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;
}
}
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"));