【问题标题】:Parsing an XML in Java using STax使用 Stax 在 Java 中解析 XML
【发布时间】:2012-03-20 05:35:02
【问题描述】:

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

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

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

现在我有一个宏类如下--

 public class Macro {
    private String name; 

    public String getName() {
        return name;
    }

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

我还有一个解析器类,我尝试将 XML 转换为“宏”类的对象。解析器类sn-p如下--

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

【问题讨论】:

    标签: java xml parsing stax


    【解决方案1】:

    很抱歉,您的代码有很多问题,甚至无法编译。

    首先,返回类型应该是List&lt;Macro&gt;,因为Macro 类既不继承自Item,也没有实现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();
                }
            };
        }
    }
    

    【讨论】:

    • 我必须承认。我花了一段时间才弄清楚你在这段代码 sn-p 中做了什么,但这是迄今为止我见过的用 StAX 解析 xml 的最好方法!!!
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      到 macro.setMacroName(attribute.getvalue().toString());

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-30
        • 2013-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-17
        • 2012-04-11
        相关资源
        最近更新 更多