Reputation: 1239
This, even to me, seems like a silly question but then is one of those to which i cant find an answer.
Im trying to parse an XML using STax in Java and the XMl im trying to parse looks like this --
<?xml version="1.0" encoding="UTF-8"?>
<Macros>
<MacroDefinition>
<MacroName>
<string>Macro1</string>
</MacroName>
</MacroDefinition>
</Macros>
Now i have a Macro class as follows --
public class Macro {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I also have a parser class from where i try to convert the XML into an object of the 'Macro' class. The parser class snippet is as follows --
public class StaxParser {
static final String MACRODEFINITION = "MacroDefinition";
static final String MACRONAME = "MacroName";
static final String STRING = "string";
@SuppressWarnings({ "unchecked", "null" })
public List<Item> readMacro(String configFile) {
List<Macro> macroList = new ArrayList<Macro>();
try {
// First create a new XMLInputFactory
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
// Setup a new eventReader
InputStream in = new FileInputStream(configFile);
XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
// Read the XML document
Macro macro = null;
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
if (startElement.getName().getLocalPart() == (MACRODEFINITION)) {
macro = new Macro();
}
if (event.isStartElement()) {
if (event.asStartElement().getName().getLocalPart()
.equals(MACRONAME)) {
Iterator<Attribute> attributes = event
.asStartElement().getAttributes();
while (attributes.hasNext()) {
Attribute attribute = attributes.next();
if (attribute.getName().toString()
.equals(STRING)) {
macro.setMacroName(event.asCharacters()
.getData());
}
}
event = eventReader.nextEvent();
continue;
}
}
}
// If we reach the end of an item element we add it to the list
if (event.isEndElement()) {
EndElement endElement = event.asEndElement();
if (endElement.getName().getLocalPart() == (MACRODEFINITION)) {
macroList.add(macro);
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
return macroList;
}
}
The problem im facing is that the parser is not able to read the child nodes of 'MacroName'. Im thinking getAttributes
is what is causing it not to work but have no clue of what method i should be calling to get the child nodes of any particular node.
Any help with this would be greatly appreciated.
Thanks
p1nG
Upvotes: 2
Views: 6252
Reputation: 428
You have to change macro.setMacroName(event.asCharacters().getData());
to macro.setMacroName(attribute.getvalue().toString());
Upvotes: 0
Reputation: 1527
Sorry to say that, but your code has many issues and doesn't even compile.
First of all, the return type should be List<Macro>
, since the Macro
class doesn't inherit from, nor implement, the Item
.
Second, you should ensure a safe nesting, to follow the schema of your XML, not arbitrarily test for event name equality and create Macro
objects here and there along the way. If you plan to retreive also other data besides the macro name, you can't get away with just checking for the STRING
event occurence.
Third, it's useless to nest the same checks, e.g. event.isStartElement()
.
Fourth, you should provide a Source
or a Reader
or a Stream
to a class such as the StaxParser, not directly a filename, but I didn't include this change to avoid breaking your API.
class StaxParser {
static final String MACRODEFINITION = "MacroDefinition";
static final String MACRONAME = "MacroName";
static final String STRING = "string";
@SuppressWarnings({ "unchecked", "null" })
public List<Macro> readMacro(final String configFile) {
final List<Macro> macroList = new ArrayList<Macro>();
try {
// First create a new XMLInputFactory
final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
// Setup a new eventReader
final InputStream in = new FileInputStream(configFile);
final XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
// Read the XML document
final Template template = getTemplate(eventReader);
macroList.addAll(template.process(null, getMacrosProcessor(template)));
} catch (final FileNotFoundException e) {
e.printStackTrace();
} catch (final XMLStreamException e) {
e.printStackTrace();
}
return macroList;
}
interface Template {
<T> T process(String parent, EventProcessor<T> ep) throws XMLStreamException;
}
static Template getTemplate(final XMLEventReader eventReader) {
return new Template() {
@Override
public <T> T process(final String parent, final EventProcessor<T> ep) throws XMLStreamException {
T t = null;
boolean process = true;
while (process && eventReader.hasNext()) {
final XMLEvent event = eventReader.nextEvent();
if (ep.acceptsEvent(event)) {
t = ep.processEvent(event);
}
if (event.isEndElement()) {
if (null != parent && parent.equals(event.asEndElement().getName().getLocalPart())) {
process = false;
}
}
}
return t;
}
};
}
interface EventProcessor<T> {
boolean acceptsEvent(XMLEvent event);
T processEvent(XMLEvent event) throws XMLStreamException;
}
static EventProcessor<List<Macro>> getMacrosProcessor(final Template template) {
final List<Macro> macroList = new ArrayList<Macro>();
return new EventProcessor<List<Macro>>() {
@Override
public boolean acceptsEvent(final XMLEvent event) {
return event.isStartElement()
&& MACRODEFINITION.equals(event.asStartElement().getName().getLocalPart());
}
@Override
public List<Macro> processEvent(final XMLEvent event) throws XMLStreamException {
macroList.add(template.process(MACRODEFINITION, getMacroDefinitionProcessor(template)));
return macroList;
}
};
}
static EventProcessor<Macro> getMacroDefinitionProcessor(final Template template) {
return new EventProcessor<Macro>() {
@Override
public boolean acceptsEvent(final XMLEvent event) {
return event.isStartElement() && MACRONAME.equals(event.asStartElement().getName().getLocalPart());
}
@Override
public Macro processEvent(final XMLEvent event) throws XMLStreamException {
final Macro macro = new Macro();
macro.setName(template.process(MACRONAME, getMacroNameProcessor(template)));
return macro;
}
};
}
static EventProcessor<String> getMacroNameProcessor(final Template template) {
return new EventProcessor<String>() {
@Override
public boolean acceptsEvent(final XMLEvent event) {
return event.isStartElement() && STRING.equals(event.asStartElement().getName().getLocalPart());
}
@Override
public String processEvent(final XMLEvent event) throws XMLStreamException {
return template.process(STRING, getStringProcessor());
}
};
}
static EventProcessor<String> getStringProcessor() {
return new EventProcessor<String>() {
@Override
public boolean acceptsEvent(final XMLEvent event) {
return event.isCharacters();
}
@Override
public String processEvent(final XMLEvent event) throws XMLStreamException {
return event.asCharacters().getData();
}
};
}
}
Upvotes: 4
Reputation: 776
First notice that Macro1 is not XML attribute, so event attributes will be empty. Code after changes (I have only shown lines of code that may be of interest):
if (event.isStartElement()
&& event.asStartElement().getName().getLocalPart().equals(STRING)) {
if (macro == null) {
macro = new Macro();
}
macro.setName(eventReader.getElementText());
}
A few tips: never ever compare strings using == use equals method. If you need full working example I could post my solution, but it is bit more complicated.
Upvotes: 2