85 votes

Quand devrais-je choisir SAX plutôt que StAX?

Un flux xml-analyseurs comme SAX et StAX sont plus rapide et plus efficace en terme de mémoire que des analyseurs de la construction d'une arborescence comme dans les DOM-analyseurs. SAX est une poussée de l'analyseur, ce qui signifie qu'il est une instance du pattern observer (également appelé auditeur modèle). SAX était là en premier, mais ensuite est venu StAX - un pull de l'analyseur, ce qui signifie qu'il fonctionne essentiellement comme un itérateur modèle.

Vous pouvez trouver des raisons pourquoi préférer StAX plus de SAX partout, mais en général cela se résume à: "c'est plus facile à utiliser".

Dans le Java tutoriel sur la JAXP StAX est vaguement présenté comme le milieu entre les DOM et SAX: "il est plus facile que SAX et plus efficace que les DOM". Cependant, je n'ai jamais trouvé des indices qui StAX serait plus lent ou moins efficace en terme de mémoire que SAX.

Tout cela m'a fait me demander: existe-il des raisons de choisir le SAX au lieu de StAX?

85voto

ThomasRS Points 5705

Vue d'ensemble
Les documents XML sont hiérarchique des documents, où les mêmes noms d'élément et les espaces de noms peuvent se produire à plusieurs endroits, avoir différents sens, et dans infinitif profondeur (récursif). Comme d'habitude, la solution à de gros problèmes, est de les diviser en petits problèmes. Dans le contexte de l'analyse XML, cela signifie que l'analyse des parties spécifiques du langage XML dans des méthodes spécifiques à XML. Par exemple, un morceau de la logique serait d'analyser une adresse:

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

c'est à dire que vous auriez une méthode

AddressType parseAddress(...); // A

ou

void parseAddress(...); // B

quelque part dans votre logique, en prenant XML entrées arguments et retourne un objet (le résultat de B peut être récupérée dans un champ plus tard).

SAX
SAX "pousse" XML événements, laissant à vous de déterminer où l'XML événements appartiennent dans votre programme / données.

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

Dans le cas d'un Buildning' élément de début, vous aurez besoin de déterminer que vous êtes en fait l'analyse d'un discours, puis la route de l'événement XML pour la méthode dont le travail consiste à interpréter Adresse.

StAX
StAX 'tire' XML événements, laissant à vous de déterminer où dans votre programme / données pour recevoir le XML événements.

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

Bien sûr, vous voulez toujours recevoir un " Buildning de l'événement dans la méthode dont le travail consiste à interpréter Adresse.

Discussion
La différence entre SAX et StAX est que de pousser et tirer. Dans les deux cas, l'analyse de l'état doit être traitée d'une certaine manière.

Cela se traduit par la méthode B comme typique de SAX, et Une méthode pour StAX. En outre, SAX doit donner B format XML des événements, alors que StAX peut donner de multiples événements (par le passage d'un XMLStreamReader exemple).

Ainsi B vérifiez d'abord l'état précédent de l'analyse et de gérer chaque événement XML et ensuite stocker l'état (dans un champ). Méthode Un peut juste gérer le XML événements tout à la fois par l'accès au XMLStreamReader plusieurs fois jusqu'à satisfaction.

Conclusion
StAX vous permet de structurer votre analyse (liaison de données) code en fonction de la structure XML; en rapport avec le SAX, l '"état" est implicite à partir du flux de programme pour StAX, alors que dans SAX, vous avez toujours besoin de préserver une sorte de variable d'état + route du flux en fonction de cet état, pour la plupart des cas des appels.

Je recommande StAX pour tous, mais le plus simple des documents. Plutôt passer à SAX comme une optimisation plus tard (mais vous aurez probablement envie d'aller binaire).

Suivez ce modèle lors de l'analyse à l'aide de 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;
}

Ainsi, le submethod utilise la même approche, à savoir le comptage de niveau:

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;
}

Et puis finalement vous atteignez un niveau dans lequel vous pourrez lire les types de base.

private MySetterGetterObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySetterGetterObject object = 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) {
                    object.setName(reader.getElementText())
               }
               level--;

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


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

    } while(level > 0);

    return object;
}

C'est assez simple et il n'y a pas de place pour des malentendus. Rappelez-vous juste pour décrémenter le niveau correctement:

A. après avoir attendu des personnages, mais il a obtenu un END_ELEMENT dans certains balise qui devrait contenir des caractères (dans le schéma ci-dessus):

<Name>Thomas</Name>

a la place

<Name></Name>

Le même est vrai pour un manque de sous-arborescence trop, vous obtenez l'idée.

B. après l'appel de subparsing méthodes, qui sont appelés sur démarrer éléments, et les retours APRÈS la fin de l'élément, c'est à dire l'analyseur se trouve à un niveau plus bas qu'avant l'appel de la méthode (le schéma ci-dessus).

Notez comment cette approche ignore totalement 'ignorable' les espaces en trop, pour les plus robustes de la mise en œuvre.

Edit: Ajout d'une vue d'ensemble, ajout de l'exemple, a ajouté le type de retour dans le modèle exemple. Ajouté plus robuste de la manipulation de texte.

23voto

Johan Sjöberg Points 20759

Pour généraliser un peu, je pense que StAX peut être aussi efficace que SAX . Avec la conception améliorée de StAX je ne peux pas vraiment trouver de situation où l'analyse préférentielle SAX serait préférable, à moins de travailler avec du code hérité.

EDIT : Selon ce blog, Java SAX et StAX StAX n'offrent aucune validation de schéma.

16voto

ag112 Points 2440

@Rinke: je suppose que seul le temps je pense préférant SAX sur STAX dans le cas où vous n'avez pas besoin de traiter les processus de contenu XML; pour, par exemple, la seule chose que vous voulez faire est de vérifier le bien-formation des entrants XML et vous voulez juste pour gérer les erreurs si il a...dans ce cas, vous pouvez simplement appeler la méthode parse() sur l'analyseur SAX et spécifier le gestionnaire d'erreur pour gérer toute l'analyse du problème....donc, fondamentalement, STAX est certainement préférable de choix dans les scénarios où vous souhaitez gérer le contenu becasue SAX gestionnaire de contenu est trop difficile de code...

un exemple pratique de ce cas peut-être si vous avez de la série de SAVON des noeuds dans votre entreprise et un système de niveau d'entrée de SAVON nœud permet uniquement de ceux SOAP XML pass thru prochaine étape, qui sont des documents bien-formés, alors je ne vois pas pourquoi je voudrais utiliser STAX. Je voudrais juste utiliser SAX.

1voto

OldCurmudgeon Points 16615

C'est tout un équilibre.

Vous pouvez activer un analyseur SAX dans un pull l'analyseur à l'aide d'une file d'attente de blocage et du fil de ruse donc, pour moi, il y a beaucoup moins de différence qu'il ne semble l'être.

Je crois actuellement StAX doit être emballé par l'intermédiaire d'un tiers pot alors que SAX est livré gratuitement dans javax.

J'ai récemment choisi SAX et construit un pull analyseur autour d'elle donc je n'ai pas besoin de compter sur un tiers du pot.

Les futures versions de Java sera presque certainement contenir un StAX mise en œuvre si le problème disparaît.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X