0

This is the class I have:

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

    private String name;

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

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

and the sample xml file I have is as follows

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

Currently I can create an object from this file with the following code:

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..

However, what I want to do is to be able to unmarshall the following xml file:

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

into the class:

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

So how can I bypass 'bar' and 'baz' while unmarshalling?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319

1 Answers1

1

Depending on the actual structure of your XML and what you want to achieve.

Maybe using XPath could be an alternative way, if you need only few values from the XML input.

Find a small snippet below.

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

output

name = koraytugay
qux = 00000001

edit You could extend XMLEventReader and check on each event if it is a XML tag you want to skip.

The XML event reader.

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

The JAXB class.

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

A example app to show the principle.

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

output

name: koraytugay
qux : 00000001
SubOptimal
  • 22,518
  • 3
  • 53
  • 69