Когда мне следует выбирать SAX вместо StAX?

Потоковые xml-парсеры, такие как SAX и StAX, быстрее и эффективнее с точки зрения памяти, чем парсеры, строящие древовидную структуру, такие как DOM-парсеры. SAX - это push-синтаксический анализатор, что означает, что он является экземпляром шаблона наблюдателя (также называемого шаблоном слушателя). Сначала был SAX, но затем появился StAX - синтаксический анализатор запроса, что означает, что он в основном работает как итератор.

Вы можете найти причины, по которым везде предпочтительнее StAX, а не SAX, но обычно все сводится к следующему: «это проще в использовании».

В учебнике Java по JAXP StAX неопределенно представлен как нечто среднее между DOM и SAX: «это проще, чем SAX, и более эффективно, чем DOM». Однако я так и не нашел никаких указаний на то, что StAX будет медленнее или менее эффективно использовать память, чем SAX.

Все это заставило меня задуматься: есть ли причины выбрать SAX вместо StAX?


person Rinke    schedule 22.09.2011    source источник


Ответы (6)


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

РЕДАКТИРОВАТЬ: согласно этому блогу Java SAX vs . StAX StAXoffer без проверки схемы.

person Johan Sjöberg    schedule 22.09.2011
comment
не так уж сложно добавить проверку поверх stax. сам реализовал это на днях. - person jtahlborn; 23.09.2011
comment
Подробнее о проверке: stackoverflow.com/questions/5793087/stax-xml-validation - person Ben; 20.01.2014

Обзор
XML-документы представляют собой иерархические документы, в которых одни и те же имена элементов и пространства имен могут встречаться в нескольких местах, иметь разное значение и иметь бесконечную глубину (рекурсивно). Обычно решение больших проблем состоит в том, чтобы разделить их на маленькие проблемы. В контексте синтаксического анализа XML это означает анализ определенных частей XML в методах, специфичных для этого XML. Например, одна часть логики проанализирует адрес:

<Address>
    <Street>Odins vei</Street>    
    <Building>4</Building>
    <Door>b</Door>
</Address>

то есть у вас будет метод

AddressType parseAddress(...); // A

or

void parseAddress(...); // B

где-то в вашей логике, принимая аргументы входных XML-данных и возвращая объект (результат B можно будет извлечь из поля позже).

SAX
SAX "подталкивает" XML events, оставляя вам право определять место событий XML в вашей программе / данных.

// method in stock SAX handler
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    // .. your logic here for start element
}

В случае начального элемента «Building» вам нужно будет определить, что вы действительно анализируете Address, а затем направить событие XML методу, задача которого - интерпретировать Address.

StAX
StAX "вытягивает" XML events, оставляя вам право определять, где в вашей программе / данных получать события XML.

// method in standard StAX reader
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
    // .. your logic here for start element
}

Конечно, вы всегда хотели бы получать событие «Building» в методе, задачей которого является интерпретация Address.

Обсуждение
Разница между SAX и StAX заключается в том, что они проталкивают и вытягивают. В обоих случаях состояние синтаксического анализа необходимо как-то обрабатывать.

Это означает, что метод B является типичным для SAX, а метод A - для StAX. Кроме того, SAX должен передавать B отдельные события XML, в то время как StAX может передавать несколько событий A (путем передачи экземпляра XMLStreamReader).

Таким образом, B сначала проверяет предыдущее состояние синтаксического анализа, а затем обрабатывает каждое отдельное событие XML, а затем сохраняет состояние (в поле). Метод A может просто обрабатывать все события XML одновременно, обращаясь к XMLStreamReader несколько раз, пока не будет удовлетворен.

Заключение
StAX позволяет структурировать код синтаксического анализа (привязки данных) в соответствии со структурой XML; поэтому в отношении SAX «состояние» неявно определяется потоком программы для StAX, тогда как в SAX вам всегда нужно сохранять какую-то переменную состояния + направлять поток в соответствии с этим состоянием для большинства вызовов событий.

Я рекомендую StAX для всех документов, кроме самых простых. Лучше перейти к SAX в качестве оптимизации позже (но к тому времени вы, вероятно, захотите перейти на двоичный).

Следуйте этому шаблону при синтаксическом разборе с помощью StAX:

public MyDataBindingObject parse(..) { // provide input stream, reader, etc

        // set up parser
        // read the root tag to get to level 1
        XMLStreamReader reader = ....;

        do {
            int event = reader.next();
            if(event == XMLStreamConstants.START_ELEMENT) {
              // check if correct root tag
              break;
            }

            // add check for document end if you want to

        } while(reader.hasNext());

        MyDataBindingObject object = new MyDataBindingObject();
        // read root attributes if any

        int level = 1; // we are at level 1, since we have read the document header

        do {
            int event = reader.next();
            if(event == XMLStreamConstants.START_ELEMENT) {
                level++;
                // do stateful stuff here

                // for child logic:
                if(reader.getLocalName().equals("Whatever1")) {
                    WhateverObject child = parseSubTreeForWhatever(reader);
                    level --; // read from level 1 to 0 in submethod.

                    // do something with the result of subtree
                    object.setWhatever(child);
                }

                // alternatively, faster
                if(level == 2) {
                    parseSubTreeForWhateverAtRelativeLevel2(reader);
                    level --; // read from level 1 to 0 in submethod.

                    // do something with the result of subtree
                    object.setWhatever(child);
                }


            } else if(event == XMLStreamConstants.END_ELEMENT) {
                level--;
                // do stateful stuff here, too
            }

        } while(level > 0);

        return object;
}

Таким образом, субметод использует примерно тот же подход, то есть уровень подсчета:

private MySubTreeObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySubTreeObject object = new MySubTreeObject();
    // read element attributes if any

    int level = 1;
    do {
        int event = reader.next();
        if(event == XMLStreamConstants.START_ELEMENT) {
            level++;
            // do stateful stuff here

            // for child logic:
            if(reader.getLocalName().equals("Whatever2")) {
                MyWhateverObject child = parseMySubelementTree(reader);
                level --; // read from level 1 to 0 in submethod.

                // use subtree object somehow
                object.setWhatever(child);
            }

            // alternatively, faster, but less strict
            if(level == 2) {
              MyWhateverObject child = parseMySubelementTree(reader);
                level --; // read from level 1 to 0 in submethod.

                // use subtree object somehow
                object.setWhatever(child);
            }


        } else if(event == XMLStreamConstants.END_ELEMENT) {
            level--;
            // do stateful stuff here, too
        }

    } while(level > 0);

    return object;
}

И затем, в конце концов, вы достигнете уровня, на котором вы будете читать базовые типы.

private MySetterGetterObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySetterGetterObject myObject = new MySetterGetterObject();
    // read element attributes if any

    int level = 1;
    do {
        int event = reader.next();
        if(event == XMLStreamConstants.START_ELEMENT) {
            level++;

            // assume <FirstName>Thomas</FirstName>:
            if(reader.getLocalName().equals("FirstName")) {
               // read tag contents
               String text = reader.getElementText()
               if(text.length() > 0) {
                    myObject.setName(text)
               }
               level--;

            } else if(reader.getLocalName().equals("LastName")) {
               // etc ..
            } 


        } else if(event == XMLStreamConstants.END_ELEMENT) {
            level--;
            // do stateful stuff here, too
        }

    } while(level > 0);

    // verify that all required fields in myObject are present

    return myObject;
}

Это довольно просто, и здесь нет места недоразумениям. Только не забудьте правильно понизить уровень:

A. после того, как вы ожидали символы, но получили END_ELEMENT в некотором теге, который должен содержать символы (в приведенном выше шаблоне):

<Name>Thomas</Name>

был вместо

<Name></Name>

То же самое верно и для отсутствующего поддерева, как вы понимаете.

B. после вызова методов суб-синтаксического анализа, которые вызываются для начальных элементов, и возвращает ПОСЛЕ соответствующего конечного элемента, т.е. синтаксический анализатор находится на один уровень ниже, чем до вызова метода (шаблон выше).

Обратите внимание, как этот подход полностью игнорирует «игнорируемые» пробелы для более надежной реализации.

Парсеры
Используйте Woodstox для большинства функций или Aaalto-xml для скорости.

person Community    schedule 23.09.2011
comment
В вашем вступительном слове говорится ... тогда как в SAX ... Это опечатка? (SAX вместо StAX) В любом случае спасибо за ответ. Если я правильно вас понял, вы говорите, что неявное состояние в подходе SAX является преимуществом по сравнению с необходимостью отслеживания местоположения вашего xml-дерева в подходе StAX. - person Rinke; 23.09.2011
comment
Спасибо за (теперь еще более подробный) ответ. Боюсь, я до сих пор не понимаю, что было бы хорошей причиной для использования SAX вместо StAX. Ваш ответ - хорошее объяснение того, как работают оба процессора. - person Rinke; 27.09.2011
comment
Для простых документов они одинаковы. Взгляните, например, на эту схему: mpeg.chiariglione.org/technologies /mpeg-21/mp21-did/index.htm и StAX будут более практичными. - person ThomasRS; 28.09.2011
comment
Короче говоря, поскольку вы уже пишете свой код, вы понимаете, какую часть документа вы анализируете, то есть вся логика для сопоставления события SAX с правильным кодом, теряется. - person ThomasRS; 28.09.2011

@Rinke: Думаю, единственный раз, когда я думаю о том, чтобы предпочесть SAX STAX, если вам не нужно обрабатывать / обрабатывать XML-контент; например, для единственное, что вы хотите сделать, это проверить правильность формата входящего XML и просто захотеть обработать ошибки, если они есть ... в этом случае вы можете просто вызвать метод parse () в парсере SAX и указать обработчик ошибок для обработки любой проблемы синтаксического анализа .... так что в основном STAX определенно является предпочтительным выбором в сценариях, где вы хотите обрабатывать контент, потому что обработчик контента SAX слишком сложно кодировать ...

один практический пример этого случая может быть, если у вас есть серия узлов SOAP в вашей корпоративной системе, а узел SOAP начального уровня позволяет только тем SOAP XML пройти через следующий этап, который является правильным, тогда я не вижу причин, по которым я будет использовать STAX. Я бы просто использовал SAX.

person ag112    schedule 06.10.2011
comment
Я выбрал этот ответ как лучший на данный момент. Хотя это хороший ответ, я не считаю его на 100% авторитетным и понятным. Приветствуются новые ответы. - person Rinke; 29.11.2011

Все дело в балансе.

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

Я считаю, что в настоящее время StAX нужно упаковывать через стороннюю банку, в то время как SAX поставляется бесплатно в javax.

Я недавно выбрал SAX и построил на его основе анализатор опрашивания, поэтому мне не нужно было полагаться на стороннюю jar.

В будущих версиях Java почти наверняка будет реализована реализация StAX, поэтому проблема исчезнет.

person OldCurmudgeon    schedule 10.10.2011
comment
Java SE 6 действительно включает StAX. Но, например, реализация Android не включает его. - person Bjarne Boström; 04.11.2015

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

Вы можете узнать больше о StAX в Руководствах по Java StAX

person Annamalai Thangaraj    schedule 01.04.2015

Большая часть информации, представленной в этих ответах, несколько устарела ... в этом исследовательском документе 2013 года было проведено всестороннее исследование всех библиотек синтаксического анализа XML ... прочтите его, и вы легко увидите явного победителя (подсказка: есть только один истинный победитель) ...

http://recipp.ipp.pt/bitstream/10400.22/1847/1/ART_BrunoOliveira_2013.pdf

person vtd-xml-author    schedule 19.04.2016
comment
Я прочитал статью, победителем стал StAX, использующий API курсора, как в XMLStreamReader. - person Roland; 29.06.2016
comment
очень смешно :), вы имеете в виду победителя черепашьих гонок :) - person vtd-xml-author; 29.06.2016
comment
Я просто перечитал статью, и да, StaX превосходит vtd, быстрее и меньше потребляет память. Так в чем ваша точка зрения? - person Roland; 30.06.2016
comment
каким образом победитель - stAX? о какой части статьи вы говорите? изменение документа или выбор или дифференциация? видимо, автор статьи пришел к иному выводу. но они могли ошибаться ... - person vtd-xml-author; 30.06.2016
comment
например страница 80: Согласно результатам (рисунок 11 и рисунок 12) мы видим, что StAX - это API с лучшей производительностью, за которым следует VTD. Однако VTD потребляет значительный объем памяти. Потребление памяти может быть узким местом для сред с ограниченными возможностями. - person Roland; 30.06.2016
comment
Некоторые операции выполняются быстрее в VTD, например. разница в эксплуатации. Так что, если вам это нужно, подумайте об использовании VTD. - person Roland; 30.06.2016