简体   繁体   English

使用STax在Java中解析XML

[英]Parsing an XML in Java using STax

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 -- 我试图使用Java中的STax解析XML,而XMl我试图解析的样子是这样的-

<?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. 我也有一个解析器类,从那里我试图将XML转换为'Macro'类的对象。 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'. 面临的问题是解析器无法读取“ 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. 我以为getAttributes是导致它无法工作的原因,但是不知道我应该调用哪种方法来获取任何特定节点的子节点。
Any help with this would be greatly appreciated. 任何帮助,将不胜感激。
Thanks 谢谢
p1nG p1nG

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 . 首先,返回类型应为List<Macro> ,因为Macro类既不继承也不实现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. 其次,您应该确保安全嵌套,以遵循XML的架构,而不是随意测试事件名称的相等性,并一路在各处创建Macro对象。 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. 如果您还打算检索除宏名称之外的其他数据,那么仅检查STRING事件是否发生就无法摆脱。

Third, it's useless to nest the same checks, eg event.isStartElement() . 第三,嵌套相同的检查是没有用的,例如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. 第四,您应该为诸如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();
            }
        };
    }
}

First notice that Macro1 is not XML attribute, so event attributes will be empty. 首先请注意Macro1不是XML属性,因此事件属性将为空。 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. 一些提示:永远不要使用==使用equals方法比较字符串。 If you need full working example I could post my solution, but it is bit more complicated. 如果您需要完整的工作示例,我可以发布我的解决方案,但这要复杂一些。

You have to change macro.setMacroName(event.asCharacters().getData()); 您必须更改macro.setMacroName(event.asCharacters()。getData());

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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