web-dev-qa-db-fra.com

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

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

L'utilisation de ce module dans le nouveau code est déconseillée. D'autres modules sont disponibles qui fournissent des interfaces plus simples et 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 me préciser quelles sont les principales raisons de cela?

54
Sobrique

Le vrai problème est que ce que XML::Simple Essaie principalement de faire est de prendre XML et de le représenter comme une structure de données Perl.

Comme vous le savez sans doute par perldata les deux structures de données clés dont vous disposez sont le hash et le array.

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

Et XML ne fait pas non plus vraiment. Il comporte des éléments qui sont:

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

Et ces choses 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 faire face aux éléments avec des noms dupliqués. Vous ne pouvez pas non plus différencier facilement les attributs et les nœuds enfants.

Ainsi, XML::Simple Essaie de deviner sur la base du contenu XML, et prend des "astuces" à partir des divers paramètres d'options, puis lorsque vous essayez et sortez le contenu, il (essaye) d'appliquer le même processus à l'envers.

Par conséquent, pour tout autre chose que le XML le plus simple , il devient au mieux difficile à manier ou au pire perd des données.

Considérer:

<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 - une fois 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'
                                               }
                                             ]
                          }
        };

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

Donc, pour accéder au contenu de child:

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

Notez comment vous avez un nœud "enfant", avec un nœud "contenu" en dessous, ce qui n'est pas parce que c'est ... du contenu.

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

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

Notez comment - en raison de la présence de plusieurs éléments <another_node>, Le XML a été analysé dans un tableau, où il n'était pas avec un seul. (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 vous vous retrouvez 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: Remarque, après discussion - c'est un mauvais défaut, plutôt qu'une faille avec XML :: Simple.

Vous devez définir:

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

Si vous appliquez cela 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'
                                   }
                                 ]
                      }
                    ]
        };

Cela vous donnera de la cohérence, car vous n'aurez plus de gestion des éléments à nœud unique différemment des nœuds multiples.

Mais vous:

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

Par exemple.:

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

Les éléments de hachage content et child sont toujours traités comme s'ils étaient des attributs, et comme les hachages ne sont pas ordonnés, vous ne pouvez tout simplement pas reconstruire l'entrée. Donc, fondamentalement, vous devez l'analyser, puis l'exécuter à travers Dumper pour déterminer où vous devez chercher.

Mais avec une requête xpath, vous obtenez à 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 suppose que XML::LibXML Mais je le sais moins bien):

  • xpath support. xpath est une façon XML d'exprimer un chemin vers un nœud. Ainsi, vous pouvez "trouver" un nœud ci-dessus avec get_xpath('//child'). Vous pouvez même utiliser des attributs dans la xpath - comme get_xpath('//another_child[@different_att]') qui sélectionneront exactement celui que vous vouliez. (Vous pouvez également répéter les matchs).
  • cut et paste pour déplacer des éléments
  • parsefile_inplace Pour vous permettre de modifier XML avec une modification sur place.
  • Options pretty_print, Pour formater XML.
  • twig_handlers Et purge - qui vous permet de traiter de très gros XML sans avoir à tout charger 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 les chaînes de références aux hachages et aux 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 CPAN et distribué sous forme de package installable sur de nombreux systèmes d'exploitation. (Malheureusement, ce n'est pas une installation par défaut. Pourtant)

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

Par souci 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');
53
Sobrique

XML :: Simple est l'analyseur 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 renvoyer l'un des éléments suivants (même pour les éléments qui suivent la même spécification):

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

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

Les options pour faire tomber un arbre plus régulier

Vous pouvez utiliser les options suivantes pour créer une arborescence plus régulière:

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

Mais même avec ces options, de nombreuses vérifications sont encore nécessaires pour extraire des informations d'une arborescence. Par exemple, obtenir les nœuds /root/eles/ele À partir d'un document est une opération courante qui devrait être triviale à effectuer, 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, on utiliserait ce qui suit:

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

XML :: Simple impose nombreuses limitations, et il manque de fonctionnalités 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 avec des noms différents.

  • Il a une prise en charge limitée (avec le backend XML :: SAX) ou aucune prise en charge (avec le backend XML :: Parser) des espaces de noms et des préfixes d'espace de noms.

  • Il ne peut pas gérer des éléments avec du texte et des éléments en tant qu'enfants (ce qui signifie qu'il ne peut pas gérer XHTML, entre autres).

  • Certains backends (par exemple XML :: Parser) ne peuvent pas gérer les encodages non basés sur ASCII (par exemple UTF-16le).

  • Un élément ne peut pas avoir d'élément enfant et d'attribut du même nom.

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

Ignorant les principaux problèmes mentionnés précédemment, XML :: Simple pourrait toujours ê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 plus tard? Vous pouvez simplement utiliser un meilleur analyseur pour tous vos documents dès le départ.

Non seulement certains autres analyseurs ne vous soumettent pas à ces limitations, mais ils fournissent également de nombreuses autres fonctionnalités utiles. Voici quelques fonctionnalités qu'ils pourraient ne pas avoir avec XML :: Simple:

  • La vitesse. XML :: Simple est extrêmement lent, surtout si vous utilisez un backend autre que XML :: Parser. Je parle des ordres de grandeur plus lentement que les autres analyseurs.

  • Sélecteurs XPath ou similaire.

  • Prise en charge de documents extrêmement volumineux.

  • Prise en charge de la jolie impression.

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 de l'expérience avec 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 justifier de rester à 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 gérer des documents qui ne tenaient pas en mémoire, j'utiliserais XML :: LibXML :: Reader (et sa copyCurrentNode(1)) ou XML :: Twig (en utilisant twig_roots ).

32
ikegami

Je ne suis pas d'accord avec les documents

Je vais être en désaccord et dire que XML::Simple Est juste que .. simple. Et, cela a toujours été facile et agréable à utiliser pour moi. Testez-le avec l'entrée que vous recevez. Tant que l'entrée ne change pas, vous êtes bon. Les mêmes personnes qui se plaignent d'utiliser XML::Simple Se plaignent d'utiliser JSON::Syck Pour sérialiser Moose. Les documents sont erronés car ils tiennent compte de l'exactitude plutôt que de l'efficacité. Si vous ne vous souciez que de ce qui suit, vous êtes bon:

  • ne pas jeter les données
  • la construction dans un format fourni et non un schéma abstrait

Si vous créez un analyseur abstrait qui n'est pas défini par l'application mais par des spécifications, j'utiliserais autre chose. J'ai travaillé dans une entreprise une fois et nous avons dû 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 XML est quelque chose qui est envoyé dans un format rigide et englobant tel que si vous écrivez un analyseur, vous êtes bon. Si c'est le cas, n'utilisez pas XML::Simple. XML, avant JSON, n'était qu'un format "dump this and walk" d'une langue à une autre. Les gens ont utilisé des choses comme XML::Dumper. Personne ne savait vraiment ce qui était sorti. Gérer ce scénario XML::Simple Est super! Des personnes sensées continuent de vider sur JSON sans spécifications pour accomplir la même chose. C'est comme ça que le monde fonctionne.

Vous voulez lire les données et ne pas vous soucier du format? Vous voulez traverser des structures Perl et non des possibilités XML? Allez XML::Simple.

Par extension...

De même, pour la plupart applications JSON::Syck Est suffisant pour vider ceci et marcher. Bien que si vous envoyez à beaucoup de gens, je hautement suggère de ne pas être un Douche Nozzle et de faire une spécification vers laquelle 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 passer à travers le vaudou de JSON::Syck Et laissez-les s'inquiéter. S'ils veulent du XML? Chargez-les 500 $ de plus et lancez-vous XML::Dumper.

À emporter

C'est peut-être moins que parfait, mais XML::Simple Est sacrément efficace. Chaque heure économisée dans cette arène, vous pouvez potentiellement passer dans une arène plus utile. C'est une considération réelle.

Les autres réponses

Regardez XPath a quelques avantages. Chaque réponse se résume à préférer XPath à Perl. C'est très bien. Si vous préférez utiliser un langage spécifique au domaine XML standardisé pour accéder à votre XML, essayez-le!

Perl ne fournit pas de mécanisme simple pour accéder aux 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 être difficile. XML::Simple Le sait et c'est pourquoi vous pouvez forcer le premier .. Cependant, même avec ForceArray, si l'élément n'est pas là, vous générerez une erreur ..

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

maintenant, si bar est facultatif, il vous reste à y accéder $xml->{bar}[0]{foo} et @{$xml->{bar}}[0] générera une erreur. Quoi qu'il en soit, c'est juste Perl. Cela a 0 à voir avec XML::Simple À mon humble avis. Et, j'ai admis que XML::Simple N'est pas bon pour construire selon les spécifications. Montrez-moi les données, et je peux y accéder avec XML :: Simple.

4
Evan Carroll