Какой XML-парсер использовать здесь? - PullRequest
7 голосов
/ 14 августа 2011

Я получаю XML-файл в качестве входных данных, размер которого может варьироваться от нескольких килобайт до гораздо большего. Я получаю этот файл по сети. Мне нужно извлечь небольшое количество узлов в соответствии с моим использованием, поэтому большая часть документа для меня довольно бесполезна. У меня нет настроек памяти, мне просто нужна скорость.

Учитывая все это, я пришел к выводу:

  1. Здесь не используется DOM (из-за возможного огромного размера документа, без требования CRUD и источника, являющегося сетью)

  2. Нет SAX, так как мне нужно только получить небольшое подмножество данных.

  3. StaX может быть подходом, но я не уверен, что это самый быстрый путь.

  4. JAXB выступил в качестве другого варианта - но какой синтаксический анализатор он использует? Я читал, что по умолчанию используется Xerces (какой тип - push или pull?), Хотя я могу настроить его для использования со Stax или Woodstock согласно этой ссылке

Я много читаю, все еще путаюсь с таким количеством опций! Любая помощь будет оценена.

Спасибо!

Редактировать: я хочу добавить еще один вопрос здесь: что не так в использовании JAXB здесь?

Ответы [ 5 ]

6 голосов
/ 14 августа 2011

Самым быстрым решением является анализатор StAX, тем более что вам нужен только определенный поднабор XML-файла, и вы можете легко игнорировать все, что на самом деле не нужно, используя StAX, тогда как вы все равно получите событие, если используете SAX-парсер.

Но это также немного сложнее, чем использование SAX или DOM. На днях мне пришлось написать парсер StAX для следующего XML:

<?xml version="1.0"?>
<table>
    <row>
        <column>1</column>
        <column>Nome</column>
        <column>Sobrenome</column>
        <column>email@gmail.com</column>
        <column></column>
        <column>2011-06-22 03:02:14.915</column>
        <column>2011-06-22 03:02:25.953</column>
        <column></column>
        <column></column>
    </row>
</table>    

Вот как выглядит окончательный код парсера:

public class Parser {

private String[] files ;

public Parser(String ... files) {
    this.files = files;
}

private List<Inscrito> process() {

    List<Inscrito> inscritos = new ArrayList<Inscrito>();


    for ( String file : files ) {

        XMLInputFactory factory = XMLInputFactory.newFactory();

        try {

            String content = StringEscapeUtils.unescapeXml( FileUtils.readFileToString( new File(file) ) );

            XMLStreamReader parser = factory.createXMLStreamReader( new ByteArrayInputStream( content.getBytes() ) );

            String currentTag = null;
            int columnCount = 0;
            Inscrito inscrito = null;           

            while ( parser.hasNext() ) {

                int currentEvent = parser.next();

                switch ( currentEvent ) {
                case XMLStreamReader.START_ELEMENT: 

                    currentTag = parser.getLocalName();

                    if ( "row".equals( currentTag ) ) {
                        columnCount = 0;
                        inscrito = new Inscrito();                      
                    }

                    break;
                case XMLStreamReader.END_ELEMENT:

                    currentTag = parser.getLocalName();

                    if ( "row".equals( currentTag ) ) {
                        inscritos.add( inscrito );
                    }

                    if ( "column".equals( currentTag ) ) {
                        columnCount++;
                    }                   

                    break;
                case XMLStreamReader.CHARACTERS:

                    if ( "column".equals( currentTag ) ) {

                        String text = parser.getText().trim().replaceAll( "\n" , " "); 

                        switch( columnCount ) {
                        case 0:
                            inscrito.setId( Integer.valueOf( text ) );
                            break;
                        case 1:                         
                            inscrito.setFirstName( WordUtils.capitalizeFully( text ) );
                            break;
                        case 2:
                            inscrito.setLastName( WordUtils.capitalizeFully( text ) );
                            break;
                        case 3:
                            inscrito.setEmail( text );
                            break;
                        }

                    }

                    break;
                }

            }

            parser.close();

        } catch (Exception e) {
            throw new IllegalStateException(e);
        }           

    }

    Collections.sort(inscritos);

    return inscritos;

}

public Map<String,List<Inscrito>> parse() {

    List<Inscrito> inscritos = this.process();

    Map<String,List<Inscrito>> resultado = new LinkedHashMap<String, List<Inscrito>>();

    for ( Inscrito i : inscritos ) {

        List<Inscrito> lista = resultado.get( i.getInicial() );

        if ( lista == null ) {
            lista = new ArrayList<Inscrito>();
            resultado.put( i.getInicial(), lista );
        }

        lista.add( i );

    }

    return resultado;
}

}

Сам код написан на португальском, но вам должно быть легко понять, что это такое, вот репозиторий на github .

4 голосов
/ 14 августа 2011

Если вы извлекаете только небольшое количество, рассмотрите возможность использования XPath, поскольку это несколько проще, чем пытаться извлечь весь документ.

2 голосов
/ 14 августа 2011

Примечание: Я - EclipseLink JAXB (MOXy) , и член JAXB 2 ( JSR-222 * 1008)*) экспертная группа.

StAX ( JSR-173) - это, как правило, самый быстрый способ синтаксического анализа XML, а Woodstox известен как быстрый анализатор StAX.В дополнение к синтаксическому анализу вам необходимо собирать данные XML.Здесь вам пригодится комбинация StAX и JAXB.

Чтобы гарантировать, что наша реализация JAXB использует реализацию Woodstox StAX.Сконфигурируйте свою среду для использования Woodstox (это так же просто, как добавление Woodstox в ваш путь к классам).Создайте экземпляр XMLStreamReader и передайте его в качестве источника, который JAXB должен разобрать.

1 голос
/ 14 августа 2011

Либо SAX, либо StAX могут справиться с этим, выполняя сложную работу, выясняя, что вы чего-то хотите, но для извлечения небольшого набора вещей по явному пути вам лучше всего использовать XPath .

Еще одна потенциальная тактика - сначала отфильтровать только те части, которые вы хотите использовать, используя XSLT , а затем проанализируйте все, что вам нравится, в результате этого фильтра будет документ намного меньшего размера.

0 голосов
/ 14 августа 2011

Я думаю, что вы должны использовать SAX или парсер на основе SAX. Я бы порекомендовал вам Apache Digester. SAX управляется событиями и не хранит состояние. Это то, что вам нужно здесь, потому что вы должны извлечь только небольшую часть документа (я думаю, один тег).

...