Reputation: 886
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 (i.e. Foo.class should be renamed to Employee.class) and than it works:
[Employee{name='John'}, Employee{name='Lisa'}]
So my question is W-H-Y-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?
P.S. Initially, it was Employee.class
and <employee/>
problem, but I simplified the test case to emphasize on class name.
Upvotes: 1
Views: 659
Reputation: 2786
You must check employee as ending node, not "foo"
.
if (event.isEndElement() && event.asEndElement()
.getName().getLocalPart()
.equals("Employee")) {
return foo;
}
Upvotes: 2