Quand devrais-je choisir SAX sur StAX?

Les parsingurs xml en continu tels que SAX et StAX sont plus rapides et plus efficaces en termes de mémoire que les parsingurs construisant une arborescence comme les parsingurs DOM. SAX est un parsingur push, ce qui signifie qu’il s’agit d’une instance du motif de l’observateur (également appelé modèle d’écoute). SAX était là en premier, mais ensuite est venu StAX – un parsingur d’extraction, ce qui signifie qu’il fonctionne essentiellement comme un iterator.

Vous pouvez trouver des raisons de préférer StAX over SAX partout, mais cela se résume généralement à: “c’est plus facile à utiliser”.

Dans le tutoriel Java sur JAXP, StAX est présenté de manière vague comme le milieu entre DOM et SAX: “c’est plus simple que SAX et plus efficace que DOM”. Cependant, je n’ai jamais trouvé d’indices indiquant que StAX serait plus lent ou moins efficace en mémoire que SAX.

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

Pour généraliser, 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’parsing syntaxique SAX serait préférable, à moins de travailler avec du code hérité.

EDIT : D’après ce blog, Java SAX vs StAX StAX n’offrent aucune validation de schéma.

Vue d’ensemble
Les documents XML sont des documents hiérarchiques, où les mêmes noms d’éléments et espaces de noms peuvent se trouver à plusieurs endroits, ayant une signification différente et une profondeur infinie (récursive). Comme d’habitude, la solution aux gros problèmes consiste à les diviser en petits problèmes. Dans le contexte de l’parsing XML, cela signifie parsingr des parties spécifiques de XML dans des méthodes spécifiques à ce XML. Par exemple, un élément logique parsingra une adresse:

 
Odins vei 4 b

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

 AddressType parseAddress(...); // A 

ou

 void parseAddress(...); // B 

quelque part dans votre logique, en prenant des arguments d’entrées XML et en renvoyant un object (le résultat de B peut être extrait d’un champ plus tard).

SAXO
SAX «pousse» les événements XML , vous laissant le soin de déterminer où les événements XML appartiennent à votre programme / données.

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

Dans le cas d’un élément de démarrage ‘Building’, vous devez déterminer si vous parsingz réellement une adresse, puis acheminez l’événement XML vers la méthode dont le travail consiste à interpréter Address.

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

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

Bien sûr, vous voudrez toujours recevoir un événement «Bâtiment» dans la méthode dont le travail consiste à interpréter l’adresse.

Discussion
La différence entre SAX et StAX est celle de la poussée et de la traction. Dans les deux cas, l’état d’parsing doit être traité d’une manière ou d’une autre.

Cela se traduit par la méthode B comme typique pour SAX et la méthode A pour StAX. De plus, SAX doit donner des événements XML individuels B, alors que StAX peut donner plusieurs événements A (en passant une instance XMLStreamReader).

Ainsi, B vérifie d’abord l’état précédent de l’parsing, puis gère chaque événement XML individuel, puis stocke l’état (dans un champ). La méthode A peut simplement gérer les événements XML en une seule fois en accédant à XMLStreamReader plusieurs fois jusqu’à ce qu’elle soit satisfaite.

Conclusion
StAX vous permet de structurer votre code d’parsing (liaison de données) en fonction de la structure XML ; Donc, en ce qui concerne SAX, l’état est implicite du stream de programme pour StAX, alors que dans SAX, vous devez toujours conserver une sorte de variable d’état + router le stream selon cet état, pour la plupart des appels d’événement.

Je recommande StAX pour tous les documents sauf les plus simples. Plutôt passer à SAX comme une optimisation plus tard (mais vous voudrez probablement aller binary à ce moment-là).

Suivez ce modèle lors de l’parsing avec 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 atsortingbutes 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; } 

La méthode utilise donc à peu près la même approche, c’est-à-dire le niveau de comptage:

 private MySubTreeObject parseSubTree(XMLStreamReader reader) throws XMLStreamException { MySubTreeObject object = new MySubTreeObject(); // read element atsortingbutes 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 ssortingct 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 allez lire les types de base.

 private MySetterGetterObject parseSubTree(XMLStreamReader reader) throws XMLStreamException { MySetterGetterObject myObject = new MySetterGetterObject(); // read element atsortingbutes if any int level = 1; do { int event = reader.next(); if(event == XMLStreamConstants.START_ELEMENT) { level++; // assume Thomas: if(reader.getLocalName().equals("FirstName")) { // read tag contents Ssortingng 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; } 

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

A. après que vous vous attendiez à des caractères mais que vous aviez un END_ELEMENT dans une balise qui devrait contenir des caractères (dans le modèle ci-dessus):

 Thomas 

était à la place

  

La même chose est vraie pour un sous-arbre manquant, vous avez l’idée.

B. après avoir appelé les méthodes de sous-repérage, appelées sur les éléments de départ, et retourne APRES l’élément de fin correspondant, c’est-à-dire que l’parsingur est à un niveau plus bas qu’avant l’appel de méthode (modèle ci-dessus).

Notez que cette approche ignore totalement les espaces «ignifiables» pour une implémentation plus robuste.

Parsers
Aller avec Woodstox pour la plupart des fonctionnalités ou Aaalto-xml pour la vitesse.

@Rinke: Je pense que le seul moment où je pense à préférer SAX à STAX au cas où vous n’auriez pas besoin de gérer / traiter du contenu XML; par exemple, la seule chose que vous voulez faire est de vérifier le formatage du XML entrant et de simplement gérer les erreurs s’il existe. Dans ce cas, vous pouvez simplement appeler la méthode parse () sur l’parsingur SAX et spécifier le gestionnaire d’erreur problème d’parsing syntaxique …. donc essentiellement STAX est un choix nettement préférable dans les scénarios où vous voulez gérer le contenu parce que le gestionnaire de contenu SAX est trop difficile à coder …

Un exemple pratique de ce cas peut être que si votre système d’entreprise comporte une série de nœuds SOAP et qu’un nœud SOAP d’entrée de gamme ne laisse passer que les étapes SOAP XML suivantes, alors je ne vois aucune raison de le faire. utiliserait STAX. Je voudrais juste utiliser SAX.

Tout est un équilibre.

Vous pouvez transformer un parsingur syntaxique SAX en un parsingur d’extraction en utilisant une queue bloquante et quelques trucs de threads. Pour moi, il y a beaucoup moins de différence qu’il n’y paraît.

Je crois que StAX doit actuellement être intégré dans un fichier jar tiers, alors que SAX est gratuit dans javax.

J’ai récemment choisi SAX et développé un parsingur de tirage pour ne pas avoir à compter sur un pot tiers.

Les futures versions de Java contiendront presque certainement une implémentation StAX afin que le problème disparaisse.

StAX vous permet de créer des parsingurs XML bidirectionnels rapides. Cela s’avère être une meilleure alternative aux autres méthodes, telles que DOM et SAX, à la fois en termes de performances et de convivialité.

Vous pouvez en savoir plus sur StAX dans les tutoriels Java StAX

La plupart des informations fournies par ces réponses sont quelque peu obsolètes … il y a eu une étude complète de toutes les librairies d’parsing XML dans ce document de recherche de 2013 … lisez-le et vous verrez facilement le gagnant évident (conseil: il n’y en a qu’un vrai gagnant) …

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