J'ai toujours trouvé XML un peu lourd à traiter. Je ne parle pas d'implémenter un analyseur XML: je parle d' utiliser un analyseur basé sur un flux existant, comme un analyseur SAX, qui traite le nœud XML nœud par nœud.
Oui, il est vraiment facile d'apprendre les différentes API de ces analyseurs, mais chaque fois que je regarde du code qui traite XML, je le trouve toujours quelque peu compliqué. Le problème essentiel semble être qu'un document XML est logiquement séparé en nœuds individuels, et pourtant les types de données et les attributs sont souvent séparés des données réelles, parfois par plusieurs niveaux d'imbrication. Par conséquent, lors du traitement individuel d'un nœud particulier, de nombreux états supplémentaires doivent être maintenus pour déterminer où nous en sommes et ce que nous devons faire ensuite.
Par exemple, étant donné un extrait d'un document XML typique:
<book>
<title>Blah blah</title>
<author>Blah blah</author>
<price>15 USD</price>
</book>
... Comment pourrais-je déterminer quand j'ai rencontré un nœud de texte contenant un titre de livre? Supposons que nous ayons un analyseur XML simple qui agit comme un itérateur, nous donnant le nœud suivant dans le document XML chaque fois que nous appelons XMLParser.getNextNode()
. Je me retrouve inévitablement à écrire du code comme ceci:
boolean insideBookNode = false;
boolean insideTitleNode = false;
while (!XMLParser.finished())
{
....
XMLNode n = XMLParser.getNextNode();
if (n.type() == XMLTextNode)
{
if (insideBookNode && insideTitleNode)
{
// We have a book title, so do something with it
}
}
else
{
if (n.type() == XMLStartTag)
{
if (n.name().equals("book")) insideBookNode = true
else if (n.name().equals("title")) insideTitleNode = true;
}
else if (n.type() == XMLEndTag)
{
if (n.name().equals("book")) insideBookNode = false;
else if (n.name().equals("title")) insideTitleNode = false;
}
}
}
Fondamentalement, le traitement XML se transforme rapidement en une énorme boucle pilotée par une machine d'état, avec de nombreuses variables d'état utilisées pour indiquer les nœuds parents que nous avons trouvés plus tôt. Sinon, un objet de pile doit être conservé pour garder une trace de toutes les balises imbriquées. Cela devient rapidement sujet aux erreurs et difficile à maintenir.
Encore une fois, le problème semble être que les données qui nous intéressent ne sont pas directement associées à un nœud individuel. Bien sûr, cela pourrait être le cas si nous écrivions le XML comme:
<book title="Blah blah" author="blah blah" price="15 USD" />
... mais c'est rarement ainsi que XML est utilisé dans la réalité. Généralement, nous avons des nœuds de texte en tant qu'enfants des nœuds parents, et nous devons garder une trace des nœuds parents afin de déterminer à quoi un nœud de texte fait référence.
Alors ... je fais quelque chose de mal? Y a-t-il une meilleure façon? À quel moment l'utilisation d'un analyseur basé sur un flux XML devient-elle trop lourde, de sorte qu'un analyseur DOM à part entière devient nécessaire? J'aimerais entendre d'autres programmeurs sur le type d'idiomes qu'ils utilisent lors du traitement de XML avec des analyseurs basés sur des flux. L'analyse XML basée sur les flux doit-elle toujours devenir une énorme machine à états?
la source
Réponses:
Pour moi, la question est dans l'autre sens. À quel moment un document XML devient-il si lourd, que vous devez commencer à utiliser SAX au lieu de DOM?
Je n'utiliserais SAX que pour un très grand flux de données de taille indéterminée; ou si le comportement que le XML est censé invoquer est vraiment piloté par les événements, et donc semblable à SAX.
L'exemple que vous donnez me ressemble beaucoup à DOM.
EDIT: J'utiliserais également SAX pour les flux qui pourraient être mal formés, mais où je veux faire une meilleure supposition pour extraire les données.
la source
Je ne travaille pas trop avec XML, à mon avis, probablement l'un des meilleurs moyens d'analyser XML avec une bibliothèque est d'utiliser XPath.
Au lieu de parcourir l'arborescence pour trouver un nœud spécifique, vous lui donnez un chemin. Dans le cas de votre exemple (en pseudocode), ce serait quelque chose comme:
XPath est beaucoup plus puissant que cela, vous pouvez rechercher en utilisant des conditions (à la fois sur des valeurs et des attributs), sélectionner un nœud spécifique dans une liste, déplacer des niveaux dans l'arborescence. Je vous recommande de chercher des informations sur la façon de l'utiliser, il est implémenté dans de nombreuses bibliothèques d'analyse (je l'utilise la version .Net Framework et lxml pour Python)
la source
Habituellement, oui.
Pour moi, pointer pour utiliser un analyseur DOM à part entière, c'est quand j'aurais besoin d'imiter des parties de la hiérarchie des fichiers en mémoire, par exemple pour pouvoir résoudre les références croisées dans le document.
la source
L'analyse en général conduit simplement une machine à états, et l'analyse XML n'est pas différente. L'analyse basée sur les flux est toujours un problème, je finis toujours par créer une pile quelconque pour garder une trace des nœuds ancêtres, et définir de nombreux événements et une sorte de répartiteur d'événements qui vérifie un registre de balises ou de chemins et déclenche un événement si on correspond. Le code de base est assez serré, mais je me retrouve avec une énorme liasse de gestionnaires d'événements qui consistent principalement à affecter la valeur du nœud de texte suivant à un champ dans une structure quelque part. Cela peut devenir assez poilu si vous devez également y mêler la logique métier.
J'utiliserais toujours DOM à moins que des problèmes de taille ou de performance ne dictent le contraire.
la source
Pas complètement indépendant du langage, mais je désérialise généralement le XML en objets plutôt que même de penser à l'analyse. Seul le temps de vous soucier des stratégies d'analyse en soi est si vous avez un problème de vitesse.
la source
Cela devient beaucoup moins lourd si vous pouvez utiliser XPath. Et dans .Net land, LINQ to XML résume également beaucoup de choses moins glamour. ( Modifier - cela nécessite bien sûr une approche DOM)
Fondamentalement, si vous adoptez une approche basée sur les flux (donc vous ne pouvez pas utiliser de meilleures abstractions qui nécessitent un DOM), je pense que ce sera toujours assez lourd et je ne suis pas sûr qu'il existe un moyen de contourner cela.
la source
Si vous pouvez trouver un analyseur qui vous donne un itérateur, avez-vous pensé à le traiter comme un lexer et à utiliser un générateur de machine d'état?
la source