如何使用JAX-B

时间:2015-05-11 15:33:01

标签: java list jaxb polymorphism

我创建了一个多态对象列表。我可以将它们转换为XML,反之亦然(使用JAXB进行编组和解组。)但我想只读取所选类中的对象。

我使用了一些关于通过JAXB转换对象列表的教程,例如: http://memorynotfound.com/convert-xml-to-polymorphic-object-using-jax-b/或此一个:http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-using-substitution.html 我有动物清单,还有两个类,它们扩展了抽象动物类,狗,猫和鸟。我将该列表(包含狗和猫)保存到XML,我想从XML文件中只获取Cats。有可能吗?

使用教程中的代码 - > 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));

我会得到ouptut:

  

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。这是一个非常好的想法,但几乎每个教程都说过滤。我想要实现的是摆脱所有其他类。 我试图更改代码:

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;
}

但它没有用,所以我不确定我是否理解这个解决方案。

2 个答案:

答案 0 :(得分:1)

因为在Root类中,动物将狗和猫都作为元素,所以如果可用的话,它会尝试将它编组到这两个对象上。

实现目标的一种方法是删除XmlElementWrapper下的一个元素。

  vec4 texColor  = texture2D(u_texture, v_texCoord) * v_color;

上面会给你:

  @XmlElementWrapper(name = "animals")
  @XmlElements({
    @XmlElement(name = "cat", type = Cat.class)
  })
  public void setAnimals(List<Animal> animals) {
    this.animals = animals;
  }

答案 1 :(得分:1)

您可以创建自定义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"));

然后不会读取DogBirds元素。

请注意,如果多个已过滤的元素与此实现嵌套,则可能会出现问题。

编辑:编辑上面的代码以支持多个已过滤的元素。