如何在不解组父母的情况下解组XML中更深层次的元素?

时间:2016-05-19 08:13:14

标签: java xml jaxb

这是我的课程:

@XmlRootElement(name = "XmlParent")
public class Foo {

    private String name;

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

和我的样本xml文件如下

<XmlParent>
    <name>koraytugay</name>
</XmlParent>

目前,我可以使用以下代码从此文件创建对象:

JAXBContext jaxbContext = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final FileReader fileReader = new FileReader(file);
final Foo foo = (Foo) unmarshaller.unmarshal(fileReader);
// foo.getName() will be koraytugay which is fine..

但是,我想要做的是能够解组以下xml文件:

<XmlParent>
    <name>koraytugay</name>
    <bar>
        <baz>
            <qux>00000001</qux>
        </baz>
    </bar>
</XmlParent>

进入班级:

@XmlRootElement(name = "XmlParent")
public class Foo {

    private String name;
    private String qux;

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlElement
    public String getQux() {
        return qux;
    }

    public void setQux(String qux) {
        this.qux = qux;
    }
}

那我怎么能绕过&#39; bar&#39;和&#39;巴兹&#39;解组时?

1 个答案:

答案 0 :(得分:0)

取决于XML的实际结构以及您希望实现的目标。

如果您只需要XML输入中的少量值,那么使用XPath可能是另一种方法。

在下面找一个小片段。

import java.io.ByteArrayInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
...
String in = "<XmlParent>\n"
        + "    <name>koraytugay</name>\n"
        + "    <bar>\n"
        + "        <baz>\n"
        + "            <qux>00000001</qux>\n"
        + "        </baz>\n"
        + "    </bar>\n"
        + "</XmlParent>";
byte[] bytes = in.getBytes();

DocumentBuilder builder = DocumentBuilderFactory.newInstance()
        .newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(bytes));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
String name = xpath.evaluate("/XmlParent/name", document);
String qux = xpath.evaluate("/XmlParent/bar/baz/qux", document);
System.out.println("name = " + name);
System.out.println("qux = " + qux);

输出

name = koraytugay
qux = 00000001

编辑您可以扩展XMLEventReader并检查每个事件是否是您要跳过的XML标记。

XML事件阅读器。

import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

public class FilteringlXmlEventReader implements XMLEventReader {

    final XMLEventReader reader;
    final Set<QName> qNames;

    public FilteringlXmlEventReader(XMLEventReader reader,
            Set<QName> qNames) {
        this.reader = reader;
        this.qNames = qNames;
    }

    @Override
    public XMLEvent nextEvent() throws XMLStreamException {
        while (tagToSkip(reader.peek())) {
            reader.nextEvent();
        }
        return reader.nextEvent();
    }

    // from XMLEventReader
    @Override
    public boolean hasNext() {
        return reader.hasNext();
    }

    @Override
    public XMLEvent peek() throws XMLStreamException {
        return reader.peek();
    }

    @Override
    public String getElementText() throws XMLStreamException {
        return reader.getElementText();
    }

    @Override
    public XMLEvent nextTag() throws XMLStreamException {
        return reader.nextTag();
    }

    @Override
    public Object getProperty(String name) throws IllegalArgumentException {
        return reader.getProperty(name);
    }

    // from Iterator
    @Override
    public Object next() {
        return reader.next();
    }

    @Override
    public void remove() {
        reader.remove();
    }

    @Override
    public void close() throws XMLStreamException {
        reader.close();
    }

    /**
     * Check if the name of the XML tag which has triggered the passed 
     * event is to be skipped.
     *
     * @param event the current event
     * @return {@code true} the event should be skipped, otherwise 
     * {@code false}
     */
    private boolean tagToSkip(XMLEvent event) {
        switch (event.getEventType()) {
            case XMLStreamConstants.START_ELEMENT:
                StartElement startTag = (StartElement) event;
                return qNames.contains(startTag.getName());
            case XMLStreamConstants.END_ELEMENT:
                EndElement endTag = (EndElement) event;
                return qNames.contains(endTag.getName());
        }
        return false;
    }
}

JAXB类。

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "XmlParent")
public class FooBar {

    private String name;
    private String qux;

    @XmlElement
    public String getName() {
        return name; 
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlElement
    public String getQux() {
        return qux;
    }

    public void setQux(String qux) {
        this.qux = qux;
    }
}

显示原则的示例应用程序。

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import sub.optimal.xpath.FooBar;

public class FilteredUnmarshalling {

    public static void main(String[] args) throws Exception {
        String in = "<XmlParent>\n"
                + "    <name>koraytugay</name>\n"
                + "    <bar>\n"
                + "        <baz>\n"
                + "            <qux>00000001</qux>\n"
                + "        </baz>\n"
                + "    </bar>\n"
                + "</XmlParent>";
        byte[] bytes = in.getBytes();

        JAXBContext context = JAXBContext.newInstance(FooBar.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        XMLInputFactory factory = XMLInputFactory.newInstance();

        String[] tagNamesToFilter = {"bar", "baz"};
        Set<QName> tagsToFilter = new HashSet<>();
        for (String name : tagNamesToFilter) {
            tagsToFilter.add(new QName(name));
        }

        try (InputStream reader = new ByteArrayInputStream(bytes)) {
            XMLEventReader xmlEventReader=factory.createXMLEventReader(reader);
            FooBar fooBar = (FooBar)unmarshaller.unmarshal(
                    new FilteringlXmlEventReader(xmlEventReader,tagsToFilter));
            System.out.println("name: " + fooBar.getName());
            System.out.println("qux : " + fooBar.getQux());
        }
    }
}

<强>输出

name: koraytugay
qux : 00000001