使用STax在Java中解析XML

时间:2012-03-01 17:31:39

标签: java xml parsing stax

即使对我来说,这似乎是一个愚蠢的问题,但那是我无法找到答案的那一个。

我试图使用Java中的STax解析XML,而我试图解析的XMl看起来像这样 -

<?xml version="1.0" encoding="UTF-8"?>
<Macros>
    <MacroDefinition>
            <MacroName>
                <string>Macro1</string>
            </MacroName>
    </MacroDefinition>
</Macros>

现在我有一个Macro类,如下所示 -

 public class Macro {
    private String name; 

    public String getName() {
        return name;
    }

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

我还有一个解析器类,我尝试将XML转换为'Macro'类的对象。解析器类片段如下 -

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

}

我面临的问题是解析器无法读取'MacroName'的子节点。我想getAttributes是什么导致它无法工作,但不知道我应该调用什么方法来获取任何特定节点的子节点。
任何有关这方面的帮助将不胜感激 由于
p1nG

3 个答案:

答案 0 :(得分:3)

很抱歉这么说,但是你的代码有很多问题,甚至没有编译。

首先,返回类型应为List<Macro>,因为Macro类不会继承,也不会实现Item

其次,您应确保安全嵌套,遵循XML的架构,而不是随意测试事件名称相等性,并在此过程中随时创建Macro个对象。如果您打算同时检索除宏名称之外的其他数据,那么只需检查STRING事件是否发生就无法实现。

第三,嵌套相同的支票是没用的,例如event.isStartElement()

第四,您应该向一个类(例如StaxParser)提供SourceReaderStream,而不是直接提供文件名,但我没有将此更改包括在内避免破坏你的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();
            }
        };
    }
}

答案 1 :(得分:2)

首先注意Macro1不是XML属性,因此事件属性将为空。更改后的代码(我只显示了可能感兴趣的代码行):

  if (event.isStartElement()
     && event.asStartElement().getName().getLocalPart().equals(STRING)) {
          if (macro == null) {
               macro = new Macro();
          }
           macro.setName(eventReader.getElementText());
  }

一些提示:永远不要使用== use equals方法比较字符串。如果你需要完整的工作示例,我可以发布我的解决方案,但它有点复杂。

答案 2 :(得分:0)

你必须改变      macro.setMacroName(event.asCharacters()的getData());

要      macro.setMacroName(attribute.getvalue()的toString());