Разбор XML в Java с использованием STax - PullRequest
2 голосов
/ 01 марта 2012

Это, даже для меня, кажется глупым вопросом, но тогда это один из тех, на которые я не могу найти ответ.

Я пытаюсь проанализировать XML, используя STax в Java, и XMl, который я пытаюсьparse выглядит следующим образом -

<?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 ]

3 голосов
/ 07 марта 2013

Извините, что говорю, но ваш код имеет много проблем и даже не компилируется.

Прежде всего, тип возвращаемого значения должен быть List<Macro>, поскольку класс Macro не наследует и не реализует Item.

Во-вторых, вы должны обеспечить безопасное вложение, следовать схеме вашего XML, не произвольно проверять равенство имен событий и создавать Macro объекты тут и там по пути. Если вы планируете получать и другие данные, кроме имени макроса, вам не помешает просто проверить наличие события STRING.

В-третьих, бесполезно вкладывать одни и те же чеки, например. event.isStartElement().

В-четвертых, вы должны предоставить Source, Reader или Stream классу, такому как StaxParser, а не непосредственно имени файла, но я не включил это изменение, чтобы избежать нарушения вашего API. 1018 *

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();
            }
        };
    }
}
2 голосов
/ 02 марта 2012

Сначала обратите внимание, что Macro1 не является атрибутом XML, поэтому атрибуты события будут пустыми.Код после изменений ( Я только показал строки кода, которые могут представлять интерес ):

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

Несколько советов: никогда не сравнивайте строки, используя == используйте метод equals.Если вам нужен полный рабочий пример, я мог бы опубликовать свое решение, но оно немного сложнее.

0 голосов
/ 13 октября 2014

Вам необходимо изменить macro.setMacroName (event.asCharacters (). GetData ());

на macro.setMacroName (attribute.getvalue (). ToString ());

...