60 votes

Pourquoi XML::Simple est-il découragé ?

D'après la documentation de XML::Simple :

L'utilisation de ce module dans un nouveau code est déconseillée. D'autres modules sont disponibles et fournissent des interfaces plus simples et plus cohérentes. En particulier, XML::LibXML est fortement recommandé.

Les principaux problèmes de ce module sont le grand nombre d'options et les façons arbitraires dont ces options interagissent - souvent avec des résultats inattendus.

Quelqu'un peut-il m'expliquer les raisons principales de cette situation ?

1 votes

Il peut également être intéressant d'entendre les pour et les contre pour metacpan.org/pod/XML::Fast

0 votes

Êtes-vous en train de créer un article de base de connaissances auquel vous pourrez faire référence dans votre quête pour tuer XML::Simple ? :D

0 votes

Qui moi ? Cependant, si quelqu'un sait comment demander l'ajout ou le retrait d'un élément du "noyau", ce serait intéressant..... (Puisque 'c'est le noyau' est l'argument majeur pour XML::Simple. Tout comme CGI avant lui, je pense que cela devrait changer).

55voto

Sobrique Points 19573

Le vrai problème est que ce qui XML::Simple essaie avant tout de prendre XML et de le représenter comme une structure de données en perl.

Comme vous le savez sans doute perldata les deux structures de données clés que vous avez à disposition sont le hash y el array .

  • Les tableaux sont des scalaires ordonnés.
  • Les hachages sont des paires clé-valeur non ordonnées.

Et XML ne fait pas vraiment l'un ou l'autre. Il a des éléments qui sont :

  • un nom non unique (ce qui signifie que les hachages ne "collent" pas).
  • .... mais sont "ordonnés" dans le fichier.
  • peut avoir des attributs (que vous pourriez insérer dans un hash)
  • peut avoir un contenu (mais peut ne pas en avoir, mais pourrait être une balise unaire)
  • peut avoir des enfants (de n'importe quelle profondeur)

Et ces éléments ne correspondent pas directement aux structures de données perl disponibles - à un niveau simpliste, un hachage imbriqué de hachages pourrait convenir - mais il ne peut pas gérer les éléments avec des noms dupliqués. Vous ne pouvez pas non plus faire facilement la différence entre les attributs et les nœuds enfants.

Así que XML::Simple essaie de deviner le contenu du XML, et prend des "indices" à partir des différents paramètres d'option, puis lorsque vous essayez et que vous vous rendez compte que vous n'êtes pas en mesure de le faire, le système vous demande d'essayer de le faire. sortie le contenu, il (tente) d'appliquer le même processus en sens inverse.

Par conséquent, pour tout ce qui n'est pas le plus important, il n'y a pas d'autre solution. simple XML, il devient au mieux lourd, au pire il perd des données.

Pensez-y :

<xml>
   <parent>
       <child att="some_att">content</child>
   </parent>
   <another_node>
       <another_child some_att="a value" />
       <another_child different_att="different_value">more content</another_child>
   </another_node>
</xml>

Ceci - lorsqu'il est analysé par XML::Simple vous donne :

$VAR1 = {
          'parent' => {
                      'child' => {
                                 'att' => 'some_att',
                                 'content' => 'content'
                               }
                    },
          'another_node' => {
                            'another_child' => [
                                               {
                                                 'some_att' => 'a value'
                                               },
                                               {
                                                 'different_att' => 'different_value',
                                                 'content' => 'more content'
                                               }
                                             ]
                          }
        };

Note - maintenant vous avez sous parent - juste des hachages anonymes, mais sous another_node vous avez un tableau de hachages anonymes.

Ainsi, afin d'accéder au contenu de child :

my $child = $xml -> {parent} -> {child} -> {content};

Remarquez que vous avez un nœud "enfant", avec un nœud "contenu" en dessous, ce qui n'est pas parce qu'il s'agit de ... contenu.

Mais pour accéder au contenu sous le premier another_child élément :

 my $another_child = $xml -> {another_node} -> {another_child} -> [0] -> {content};

Notez comment - en raison de l'existence de plusieurs <another_node> le XML a été analysé dans un tableau, alors qu'il ne l'était pas avec un seul élément. (Si vous aviez un élément appelé content en dessous, alors vous vous retrouvez avec autre chose encore). Vous pouvez changer cela en utilisant ForceArray mais on se retrouve alors avec un hachage de tableaux de hachages de tableaux de hachages de tableaux - bien qu'il soit au moins cohérent dans sa gestion des éléments enfants. Edit : Note, suite à la discussion - c'est un mauvais défaut, plutôt qu'un défaut de XML::Simple.

Vous devriez régler :

ForceArray => 1, KeyAttr => [], ForceContent => 1

Si vous appliquez ceci au XML comme ci-dessus, vous obtenez à la place :

$VAR1 = {
          'another_node' => [
                            {
                              'another_child' => [
                                                 {
                                                   'some_att' => 'a value'
                                                 },
                                                 {
                                                   'different_att' => 'different_value',
                                                   'content' => 'more content'
                                                 }
                                               ]
                            }
                          ],
          'parent' => [
                      {
                        'child' => [
                                   {
                                     'att' => 'some_att',
                                     'content' => 'content'
                                   }
                                 ]
                      }
                    ]
        };

Vous obtiendrez ainsi une certaine cohérence, car les éléments à nœud unique ne seront plus traités différemment des éléments à nœuds multiples.

Mais tu le fais quand même :

  • Avoir un arbre profond de 5 références pour obtenir une valeur.

Par exemple :

print $xml -> {parent} -> [0] -> {child} -> [0] -> {content};

Vous avez toujours content y child Les éléments de hachage sont traités comme s'ils étaient des attributs, et comme les hachages ne sont pas ordonnés, il est tout simplement impossible de reconstruire l'entrée. Donc, en gros, vous devez l'analyser, puis le faire passer dans la commande Dumper pour savoir où vous devez regarder.

Mais avec un xpath requête, vous arrivez à ce nœud avec :

findnodes("/xml/parent/child"); 

Ce que vous n'obtenez pas dans XML::Simple que vous faites dans XML::Twig (et je présume XML::LibXML mais je le connais moins bien) :

  • xpath soutien. xpath est une façon XML d'exprimer un chemin vers un nœud. Vous pouvez donc "trouver" un nœud dans l'exemple ci-dessus avec get_xpath('//child') . Vous pouvez même utiliser des attributs dans le xpath - comme get_xpath('//another_child[@different_att]') qui sélectionnera exactement celui que vous vouliez. (Vous pouvez également itérer sur les correspondances).
  • cut y paste pour déplacer des éléments
  • parsefile_inplace pour vous permettre de modifier XML avec un montage sur place.
  • pretty_print options, pour formater XML .
  • twig_handlers y purge - qui vous permet de traiter des fichiers XML très volumineux sans avoir à les charger entièrement en mémoire.
  • simplify si vous devez vraiment le rendre rétrocompatible avec XML::Simple .
  • le code est généralement beaucoup plus simple que d'essayer de suivre des chaînes de références à des hachages et des tableaux, ce qui ne peut jamais être fait de manière cohérente en raison des différences fondamentales de structure.

Il est également largement disponible - facile à télécharger à partir de l'adresse suivante CPAN et distribué sous forme de paquetage installable sur de nombreux systèmes d'exploitation. (Malheureusement, il ne s'agit pas d'une installation par défaut).

Voir : XML::Twig référence rapide

A titre de comparaison :

my $xml = XMLin( \*DATA, ForceArray => 1, KeyAttr => [], ForceContent => 1 );

print Dumper $xml;
print $xml ->{parent}->[0]->{child}->[0]->{content};

Vs.

my $twig = XML::Twig->parse( \*DATA );
print $twig ->get_xpath( '/xml/parent/child', 0 )->text;
print $twig ->root->first_child('parent')->first_child_text('child');

5 votes

Malheureusement, ce n'est pas une installation par défaut. Si par "installation par défaut" vous entendez le module de base, alors oui, je suis d'accord avec vous. Mais si vous voulez plutôt dire "intégré à une distribution Perl", Perl aux fraises comprend des modules XML préinstallés (XML::LibXML, XML::Parser, XML::Twig, etc.) depuis au moins Mai 2014 peut-être plus longtemps.

7 votes

Selon moi, le problème se résume essentiellement au fait que la valeur par défaut de ForceArray aurait dû être de 1 (et que cela ne peut pas être modifié sans casser la plupart des utilisations existantes). Si XML::Simple répond à vos besoins, il n'y a aucune raison de ne pas l'utiliser.

0 votes

Je suis d'accord, mais en limitant la portée de "répondre à mes besoins" à "si je ne peux pas installer l'un des autres modules", et si un hack d'expressions régulières ne fera pas l'affaire. Parce qu'honnêtement, je le considère comme très similaire aux expressions régulières, pour la même raison. Cela fonctionnera à condition que vous ayez une portée très contrôlée de votre XML d'entrée. Et il peut se casser un jour, sans raison apparente. Il résout un problème, et c'est un module de base. Mais c'est une mauvaise solution alors qu'il existe de bien meilleures options.

33voto

ikegami Points 133140

XML::Simple est l'analyseur syntaxique XML le plus complexe disponible.

Le principal problème avec XML::Simple est que la structure résultante est extrêmement difficile à naviguer correctement. $ele->{ele_name} peut retourner l'un des éléments suivants (même pour les éléments qui suivent la même spécification) :

[ { att => 'val', ..., content => [ 'content', 'content' ] }, ... ]
[ { att => 'val', ..., content => 'content' }, ... ]
[ { att => 'val', ..., }, ... ]
[ 'content', ... ]
{ 'id' => { att => 'val', ..., content => [ 'content', 'content' ] }, ... }
{ 'id' => { att => 'val', ..., content => 'content' }, ... }
{ 'id' => { att => 'val', ... }, ... }
{ 'id' => { content => [ 'content', 'content' ] }, ... }
{ 'id' => { content => 'content' }, ... }
{ att => 'val', ..., content => [ 'content', 'content' ] }
{ att => 'val', ..., content => 'content' }
{ att => 'val', ..., }
'content'

Cela signifie que vous devez effectuer toutes sortes de vérifications pour savoir ce que vous avez réellement obtenu. Mais la complexité même de ce processus encourage les développeurs à faire de très mauvaises hypothèses. Cela conduit à toutes sortes de problèmes qui se glissent dans la production, provoquant l'échec du code en direct lorsque des cas particuliers sont rencontrés.

Les possibilités d'obtenir un arbre plus régulier sont insuffisantes.

Vous pouvez utiliser les options suivantes pour créer un arbre plus régulier :

ForceArray => 1, KeyAttr => [], ForceContent => 1

Mais même avec ces options, de nombreuses vérifications sont encore nécessaires pour extraire des informations d'un arbre. Par exemple, obtenir le /root/eles/ele Les nœuds d'un document sont une opération courante qui devrait être triviale à réaliser, mais ce qui suit est requis lors de l'utilisation de XML::Simple :

# Requires: ForceArray => 1, KeyAttr => [], ForceContent => 1, KeepRoot => 0
# Assumes the format doesn't allow for more than one /root/eles.
# The format wouldn't be supported if it allowed /root to have an attr named eles.
# The format wouldn't be supported if it allowed /root/eles to have an attr named ele.
my @eles;
if ($doc->{eles} && $doc->{eles}[0]{ele}) {
    @eles = @{ $doc->{eles}[0]{ele} };
}

Dans un autre analyseur syntaxique, on utiliserait ce qui suit :

my @eles = $doc->findnodes('/root/eles/ele');

XML::Simple impose nombreux des limitations, et il manque des caractéristiques communes

  • C'est complètement inutile pour produire du XML. Même avec ForceArray => 1, ForceContent => 1, KeyAttr => [], KeepRoot => 1 il y a beaucoup trop de détails qui ne peuvent pas être contrôlés.

  • Il ne préserve pas l'ordre relatif des enfants ayant des noms différents.

  • Le support des espaces de noms et des préfixes d'espaces de noms est limité (avec le backend XML::SAX) ou inexistant (avec le backend XML::Parser).

  • Certains backends (par exemple XML::Parser) sont incapables de gérer les encodages non basés sur l'ASCII (par exemple UTF-16le).

  • Un élément ne peut pas avoir un élément enfant et un attribut portant le même nom.

  • Il ne peut pas créer de documents XML avec des commentaires.

En ignorant les problèmes majeurs mentionnés précédemment, XML::Simple pourrait encore être utilisable avec ces limitations. Mais pourquoi se donner la peine de vérifier si XML::Simple peut gérer votre format de document et risquer de devoir passer à un autre analyseur par la suite ? Vous pourriez simplement utiliser un meilleur analyseur pour tous vos documents dès le départ.

Non seulement certains autres analyseurs syntaxiques ne vous soumettent pas à ces limitations, mais ils offrent en outre de nombreuses autres fonctionnalités utiles. Voici quelques fonctionnalités qu'ils peuvent avoir et que XML::Simple n'a pas :

  • Vitesse. XML::Simple est extrêmement lent, surtout si vous utilisez un backend autre que XML::Parser. Je parle de plusieurs ordres de grandeur de lenteur par rapport aux autres analyseurs.

  • Sélecteurs XPath ou similaires.

  • Prise en charge de documents extrêmement volumineux.

  • Prise en charge de l'impression de jolis dessins.

XML::Simple est-il jamais utile ?

Le seul format pour lequel XML::Simple est le plus simple est celui où aucun élément n'est facultatif. J'ai eu l'expérience d'innombrables formats XML, et je n'ai jamais rencontré un tel format.

Cette fragilité et cette complexité sont à elles seules des raisons suffisantes pour se tenir à l'écart de XML::Simple, mais il y en a d'autres.

Alternatives

J'utilise XML::LibXML. C'est un analyseur extrêmement rapide et complet. Si j'avais besoin de manipuler des documents qui ne tiennent pas dans la mémoire, j'utiliserais XML::LibXML::Reader (et son module d'extension copyCurrentNode(1) ) ou XML::Twig (en utilisant twig_roots ).

0 votes

XML::TreePP ne me semble pas avoir la magie de deviner XML::Simple. Mais vous pouvez lui dire comment se comporter exactement. Il est également beaucoup plus simple à utiliser que XML::LibXML et sa famille. Pour créer du XML, j'utiliserais XML::TreePP, pour analyser du contenu XML externe, peut-être XML::LibXML si vous avez des XML géants et que la vitesse est un problème.

1 votes

@nicomen, En supposant que vous utilisez $tpp->set( force_array => [ '*' ] ); vous avez besoin d'au moins my @eles; if ($doc->{root} && $doc->{root}[0]{eles} && $doc->{root}[0]{eles}[0]{ele}) { @eles = @{ $doc->{root}[0]{eles}[0]{ele} } } pour obtenir le /root/eles/ele et cela en supposant qu'il ne peut pas y avoir de multiples eles des nœuds. Ce n'est pas différent d'un XML::Simple configuré de manière optimale. (C'est bien pire sans force_array => [ '*' ] .)

1 votes

@nicomen, Vous dites que vous utiliseriez XML::TreePP plutôt que XML::LibXML pour les gros documents. Pourquoi ???? Cela me semble absurde, mais il se peut que quelque chose m'échappe. Je n'ai pas fait d'évaluation comparative de XML::TreePP, mais je pense qu'il est loin de s'approcher de XML::LibXML, qu'il s'agisse de gros documents ou non. Le problème avec les gros documents est la mémoire, pas la vitesse. XML::LibXML propose une option pour les gros documents (un analyseur pull) alors que XML::TreePP ne le fait pas. Cela dit, XML::Twig est bien meilleur pour cela.

4voto

Evan Carroll Points 13420

Je ne suis pas d'accord avec les docs

Je vais faire dissidence et dire que XML::Simple est juste ça simple. Et il a toujours été facile et agréable à utiliser pour moi. Testez-le avec les données que vous recevez. Tant que l'entrée ne change pas, c'est bon. Les mêmes personnes qui se plaignent d'utiliser XML::Simple se plaignent de l'utilisation JSON::Syck pour sérialiser Moose. La documentation est erronée car elle prend en compte la correction au détriment de l'efficacité. Si vous ne vous souciez que de ce qui suit, c'est bon :

  • ne pas jeter les données
  • construire selon un format fourni et non un schéma abstrait

Si vous faites un analyseur abstrait qui n'est pas défini par l'application mais par la spécification, j'utiliserais autre chose. J'ai travaillé dans une entreprise à une époque où nous devions accepter 300 schémas XML différents, dont aucun n'avait de spécification. XML::Simple a fait le travail facilement. Les autres options nous auraient obligés à embaucher quelqu'un pour faire le travail. Tout le monde pense que le XML est quelque chose qui est envoyé dans un format rigide et universel, tel que si vous écrivez un parseur, vous êtes bon. Si c'est le cas, n'utilisez pas le logiciel XML::Simple . Le XML, avant JSON, n'était qu'un format de transfert d'un langage à un autre. Les gens utilisaient en fait des choses comme XML::Dumper . Personne ne savait réellement ce qui était produit. Pour faire face à ce scénario XML::Simple c'est génial ! Les gens sains d'esprit continuent à utiliser JSON sans spécification pour accomplir la même chose. C'est comme ça que le monde fonctionne.

Vous voulez lire les données sans vous soucier de leur format ? Vous voulez traverser des structures Perl et non des possibilités XML ? Allez sur XML::Simple .

Par extension...

De même, pour le plus applications JSON::Syck est suffisant pour jeter ça et partir. Mais si vous envoyez à beaucoup de gens, je hautement suggère de ne pas être un connard et de faire une spécification que vous exportez. Mais, vous savez quoi Parfois, vous allez recevoir un appel de quelqu'un à qui vous ne voulez pas parler et qui veut ses données que vous n'exportez pas normalement. Et, vous allez le canaliser à travers JSON::Syck et les laisser s'en occuper. S'ils veulent du XML ? Faites-leur payer 500 $ de plus et mettez le feu aux poudres. XML::Dumper .

A emporter

C'est peut-être moins que parfait, mais XML::Simple est sacrément efficace. Chaque heure gagnée dans cette arène peut potentiellement être dépensée dans une arène plus utile. C'est une considération du monde réel.

Les autres réponses

Regardez XPath a des avantages. Toutes les réponses se résument ici à préférer XPath sur Perl. Cela ne pose aucun problème. Si vous préférez utiliser un langage standardisé spécifique au domaine XML pour accéder à votre XML, allez-y !

Perl ne prévoit pas de mécanisme facile pour accéder à des structures optionnelles profondément imbriquées.

var $xml = [ { foo => 1 } ];  ## Always w/ ForceArray.

var $xml = { foo => 1 };

Obtenir la valeur de foo ici dans ces deux contextes peut s'avérer délicat. XML::Simple sait cela et c'est pourquoi vous pouvez forcer le premier Cependant, que même avec ForceArray si l'élément n'est pas présent, une erreur sera signalée

var $xml = { bar => [ { foo => 1 } ] };

maintenant, si bar est optionnel, vous devez y accéder. $xml->{bar}[0]{foo} y @{$xml->{bar}}[0] entraînera une erreur. De toute façon, c'est juste du perl. Cela n'a rien à voir avec XML::Simple imho. Et, j'ai admis que XML::Simple n'est pas bon pour construire selon les spécifications. Montrez-moi des données, et je peux y accéder avec XML::Simple.

0 votes

Les commentaires ne sont pas destinés à une discussion approfondie ; cette conversation a été déplacé vers le chat .

0 votes

0 votes

J'ai supprimé le méta-commentaire inutile visant un autre utilisateur. Cela n'a pas vraiment besoin de faire partie de la réponse, et si vous voulez en discuter, allez-y en chat.

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