Je recherche un évaluateur XPath qui ne reconstruit pas tout le document DOM pour rechercher les nœuds d'un document: l'objet consiste en réalité à gérer une grande quantité de données XML (idéalement plus de 2 Go) avec le modèle SAX, qui est très bon pour la gestion de la mémoire, et donne la possibilité de rechercher des nœuds.
Merci à tous pour votre aide!
Pour tous ceux qui disent que ce n'est pas possible: j'ai récemment, après avoir posé la question, trouvé un projet nommé "saxpath" ( http://www.saxpath.org/ ), mais je n'ai trouvé aucun projet de mise en oeuvre. .
Ma liste actuelle (compilée à partir des résultats de recherche Web et des autres réponses) est la suivante:
L'étape suivante consiste à utiliser les exemples de XMLDog et à comparer les performances de toutes ces approches. Ensuite, les scénarios de test doivent être étendus aux expressions XPath prises en charge.
Nous analysons régulièrement des fichiers XML complexes de plus de 1 Go à l'aide d'un analyseur SAX qui extrait des arborescences DOM partielles qui peuvent facilement être interrogées à l'aide de XPath. J'ai blogué à ce sujet ici: http://softwareengineeringcorner.blogspot.com/2012/01/conveniently-processing-large-xml-files.html - Les sources sont disponibles sur github - MIT Licence.
XPath fonctionne avec SAX, et la plupart des processeurs XSLT (en particulier Saxon et Apache Xalan) prennent en charge l’exécution d’expressions XPath dans les XSLT d’un flux SAX sans créer le dom en entier.
Ils y parviennent très grossièrement comme suit:
La manière dont ils le tamponnent est également très intéressante, car alors que certains créent simplement des fragments DOM ici et là, d’autres utilisent des tables très optimisées pour une recherche rapide et une consommation de mémoire réduite.
Leur capacité d'optimisation dépend en grande partie du type de requête XPath trouvée. Comme l'explique clairement la documentation Saxon déjà publiée, les requêtes qui se déplacent "vers le haut" puis le parcourent "horizontalement" (parent par frère) exigent évidemment que le document entier soit présent, mais la plupart d'entre elles nécessitent la conservation de quelques nœuds. RAM à tout moment.
J'en suis assez sûr, car lorsque je faisais encore chaque jour une application Web en utilisant Cocoon, nous avions le problème d'empreinte mémoire XSLT chaque fois que nous utilisions une expression "quelque chose" dans un XSLT, et nous avons souvent dû retravailler les expressions XPath pour permettre une meilleure optimisation SAX.
SAX est uniquement en avant, tandis que les requêtes XPath peuvent parcourir le document dans n’importe quelle direction (considérez les axes parent::
, ancestor::
, preceding::
et preceding-sibling::
). Je ne vois pas comment cela serait possible en général. La meilleure approximation serait une sorte de DOM à chargement paresseux, mais en fonction de vos requêtes, cela peut vous apporter un avantage quelconque - il existe toujours une requête dans le pire des cas, telle que //*[. != preceding::*]
.
Désolé, une réponse un peu tardive ici - il semble que cela soit possible pour un sous-ensemble de XPath - en général, cela est très difficile car XPath peut faire la correspondance entre le point "actuel" et le suivant. Je suis au courant de deux projets qui le résolvent en partie à l'aide de machines à états: http://spex.sourceforge.net & http://www.cs.umd.edu/projects/xsq . Je ne les ai pas examinées en détail, mais elles semblent utiliser une approche similaire.
Je vais lancer un plug-in pour un nouveau projet, AXS. C'est à https://code.google.com/p/annotation-xpath-sax/ et l'idée est que vous annotez des méthodes avec des instructions XPath l'analyseur SAX se trouve à un noeud qui lui correspond. Donc avec un document
<doc>
<nodes>
<node name="a">text of node 1</node>
<node name="b">text of node 2</node>
<node otherattr="I have attributes!">text of node 3</node>
</nodes>
</doc>
vous pouvez faire des choses comme
@XPath("/nodes/node")
void onNode(String nodeText)
{
// will be called with "text of node [123]"
}
ou
@XPathStart("//node[@name='']")
void onNode3(Attrs node3Attrs) { ... }
ou
@XPathEnd("/nodes/node[2]")
void iDontCareAboutNode3() throws SAXExpression
{
throw new StopParsingExpression();
}
Bien sûr, la bibliothèque est si nouvelle que je n’ai même pas encore publié de version, mais elle est MIT sous licence, alors n'hésitez pas à essayer et voir si elle correspond à vos besoins. (Je l'ai écritDo Écran HTML effacé avec assez de mémoire pour que je puisse l'exécuter Vieux appareils Android ...) Si vous trouvez des bogues, faites-le moi savoir en les archivant. Site .googlecode!
Désolé pour la réponse tardive, mais j’ai implémenté un expression XPath simple chemin pour les analyseurs SAX. Il ne prend en charge que les balises, les attributs avec valeur optionnelle et les index en raison de la nature de transmission de SAX. J'ai créé un delegate Handler pour évaluer l'expression donnée lorsque le gestionnaire implémente ExpressionFilter . Bien que ces classes soient intégrées au projet, il ne devrait pas être difficile de les extraire.
Exemples - Voir les classes avec le préfixe HandlerHtml
Il existe des implémentations XPath basées sur SAX/StAX, mais elles ne prennent en charge qu'un petit sous-ensemble d'expressions/axes XPath, en grande partie en raison de la nature de transmission uniquement par SAX/StAX. La meilleure alternative à ma connaissance est étendue VTD-XML =, il prend en charge l'intégralité du xpath, le chargement partiel de documents via mem-map .. et une taille de document maximale de 256 Go, mais vous aurez besoin d'une JVM 64 bits pour l'utiliser à son plein potentiel.
Ce que vous pouvez faire, c'est connecter un transformateur XSL à une source d'entrée SAX. Votre traitement sera séquentiel et le préprocesseur XSL tentera de saisir l’entrée au moment de le transformer en un résultat quelconque. Vous pouvez l'utiliser pour extraire la valeur d'un chemin du flux. Cela serait particulièrement utile si vous voulez produire plusieurs résultats XPATH différents en un seul passage.
En conséquence, vous obtiendrez (généralement) un document XML, mais vous pourriez extraire le résultat attendu de, par exemple, une StreamResult
sans trop de problèmes.
Regardez le mode de streaming du processeur Saxon-SA XSLT.
http://www.saxonica.com/documentation/sourcedocs/serial.html
"Les règles qui déterminent si une expression de chemin peut être diffusée sont les suivantes:
L'expression de chemin introduite par l'appel sur doc () ou document doit être conforme à un sous-ensemble de XPath défini comme suit:
toute expression XPath est acceptable si elle est conforme aux règles pour les expressions de chemin apparaissant dans les contraintes d'identité du schéma XML. Ces règles n'autorisent aucun prédicat; la première étape (mais seulement la première) peut être introduite avec "//"; la dernière étape peut éventuellement utiliser l'axe attributaire; toutes les autres étapes doivent être de simples étapes d'axe utilisant l'axe enfant.
L'expression doit sélectionner uniquement des éléments, ou uniquement des attributs, ou un mélange d'éléments et d'attributs.
Les filtres simples (un ou plusieurs) sont également pris en charge. Chaque filtre peut s'appliquer à la dernière étape ou à l'expression dans son ensemble, et il ne doit utiliser que la sélection descendante à partir du nœud de contexte (axes self, enfant, attribut, descendant, descendant-ou-self ou espace de nom). Il ne doit pas être positionnel (c'est-à-dire qu'il ne doit pas faire référence à position () ou last (), et ne doit pas être numérique: en fait, il doit être tel que Saxon puisse déterminer, au moment de la compilation, que ce ne sera pas numérique). Les filtres ne peuvent pas être appliqués à des syndicats ou à des branches de syndicats. Toute violation de ces conditions entraîne l'évaluation de l'expression sans l'optimisation de la diffusion en continu.
Ces règles s'appliquent après que d'autres réécritures d'optimisation ont été appliquées à l'expression. Par exemple, certaines expressions FLWOR peuvent être réécrites en une expression de chemin répondant à ces règles.
L'optimisation n'est activée que si elle est explicitement demandée, soit à l'aide de la fonction d'extension saxon: stream (), soit à l'aide de l'attribut saxon: read-once sur une instruction xSlT xsl: copy-of, ou à l'aide du flux XQuery pragma saxon:. Il est disponible uniquement si la feuille de style ou la requête est traitée à l'aide de Saxon-SA. "
Remarque: il est fort probable que dans la version commerciale, cette fonctionnalité est disponible. J'ai beaucoup utilisé Saxon un peu plus tôt, et c'est un beau travail.
Mmh je ne sais pas si je te comprends vraiment. Autant que je sache, le modèle SAX est orienté événement. Cela signifie que vous faites quelque chose si un certain nœud est rencontré lors de l'analyse. Oui, c'est mieux pour la mémoire, mais je ne vois pas comment vous aimeriez obtenir XPath. Comme SAX ne construit pas de modèle, je ne pense pas que cela soit possible.
L'API standard javax xpath fonctionne déjà techniquement avec les flux; javax.xml.xpath.XPathExpression
peut être évalué par rapport à une InputSource
, qui peut à son tour être construite avec une Reader
. Je ne pense pas qu'il construise un DOM sous les couvertures.
Avez-vous également essayé QuiXPath https://code.google.com/p/quixpath/ ?