简体   繁体   中英

StAX - XMLEventReader unexpected behavior

I've just tried utilize StAX to parse some trivial XML document

<?xml version="1.0"?>
<root>
    <Employee>
        <name>John</name>
    </Employee>
    <Employee>
        <name>Lisa</name>
    </Employee>
</root>

...but faced a problem which makes me crazy. Here is the code:

public class Foo {

    public String name;

    @Override
    public String toString() {
        return "Foo{" + "name='" + name + '\'' + '}';
    }
}

public class StAXParserTest {

    @Test
    public void testFoo() throws Exception {
        List<Foo> result = new ArrayList<>();
        XMLEventReader eventReader = XMLInputFactory
                .newInstance()
                .createXMLEventReader(getResourceAsStream("example.xml"));
        while (eventReader.hasNext()) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                StartElement startElem = event.asStartElement();
                switch (startElem.getName().getLocalPart()) {
                    case "Employee":
                        result.add(parseFoo(eventReader));
                        break;
                }
            }
        }
        System.out.println(result);
    }

    private static Foo parseFoo(XMLEventReader eventReader) throws XMLStreamException {
        Foo foo = new Foo();
        while (true) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                switch (event.asStartElement().getName().getLocalPart()) {
                    case "name":
                        foo.name = eventReader.nextEvent().asCharacters().getData();
                        break;
                }
            }

            if (event.isEndElement() && event.asEndElement().getName().getLocalPart().equals("Foo")) {
                return foo;
            }
        }
    }

    private InputStream getResourceAsStream(String filename) throws URISyntaxException {
        return this.getClass().getClassLoader().getResourceAsStream(filename);
    }
}

There is nothing wrong it. But if you run the test you'll get the following error.

java.util.NoSuchElementException
    at com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:88)
    at stax.StAXParserTest.parseFoo(StAXParserTest.java:40)
    at stax.StAXParserTest.testFoo(StAXParserTest.java:29)

I've spent an hour to figure out the cause. In order to solve the problem POJO class name must be EXACTLY the same as XML tag name (ie Foo.class should be renamed to Employee.class) and than it works:

[Employee{name='John'}, Employee{name='Lisa'}]

So my question is WHY-YYYYYY? It's absolutely non-intuitive. This is not JAXB. Not any other object mapper. If I do all the work by myself than why class name matters?

PS Initially, it was Employee.class and <employee/> problem, but I simplified the test case to emphasize on class name.

You must check employee as ending node, not "foo" .

        if (event.isEndElement() && event.asEndElement()
            .getName().getLocalPart()
            .equals("Employee")) {
            return foo;
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM