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

À Partir de la documentation de XML::Simple:

L'utilisation de ce module dans le nouveau code est découragé. 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 avec ce module sont le grand nombre d'options et les manières arbitraires dont ces options interagissent - souvent avec des résultats inattendus.

Quelqu'un peut-il clarifier pour moi quelles sont les principales raisons pour cela, sont?

50
demandé sur Sobrique 2015-10-21 22:36:43

3 réponses

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 de perldata les deux structures de données clés dont vous disposez sont hash et 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 a des éléments qui sont:

  • nom non unique (ce qui signifie les hachages ne "correspondent"pas).
  • .... mais sont "ordonnés" dans le fichier.
  • peut avoir des attributs (que vous pouvez insérer dans un hachage)
  • peut avoir du contenu (mais peut-être pas, mais peut-ê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 peut convenir-mais il ne peut pas gérer les éléments avec des noms dupliqués. Vous ne pouvez pas non plus différencier facilement entre les attributs et les nœuds enfants.

Donc XML::Simple essaie de deviner en fonction du contenu XML, et prend des 'conseils' à partir des différents paramètres d'option, puis lorsque vous essayez et sortie le contenu, il (essaie de) Appliquer le même processus en sens inverse.

Par conséquent, pour autre chose que le XML le plus simple, Il devient lourd au mieux, ou perd des données au pire.

Considérons:

<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 donne vous:

$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.

Afin d'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 le cas ... 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 d'avoir 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: Note, suite à la discussion - c'est un mauvais défaut, plutôt qu'un défaut avec XML::Simple.

Vous devriez définir:

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

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

Cela vous donnera de la cohérence, car vous n'aurez plus d'éléments de nœud unique à gérer différemment des multi-nœuds.

Mais vous encore:

  • avoir un arbre profond de référence 5 pour obtenir une valeur.

Par exemple:

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

Vous avez toujours content et child éléments de hachage traités comme s'ils étaient des attributs, et parce que les hachages ne sont pas ordonnés, vous ne pouvez tout simplement pas reconstruire l'entrée. Donc, fondamentalement,, vous devez l'analyser, puis de l'exécuter via Dumper pour comprendre où vous devez regarder.

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 n'en XML::Twig (et je présume XML::LibXML, mais je connais moins bien):

  • xpath soutien. {[26] } est une manière XML d'exprimer un chemin vers un nœud. Ainsi, vous pouvez "trouver" un nœud dans ce qui précède avec get_xpath('//child'). Vous pouvez même utiliser des attributs dans xpath - Comme get_xpath('//another_child[@different_att]') qui sélectionnez exactement celui que vous vouliez. (Vous pouvez aussi itérer sur les correspondances).
  • cut et paste pour déplacer des éléments
  • parsefile_inplace pour vous permettre de modifier XML, avec un lieu de modifier.
  • pretty_print options, pour formater XML.
  • twig_handlers et purge - ce 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 des chaînes de références aux hachages et aux tableaux, cela 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. Encore)

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

À 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');
50
répondu Sobrique 2015-12-21 12:00:31

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. {[4] } 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. Mais la complexité de cela encourage les développeurs à faire de très mauvaises hypothèses à la place.

Les options pour faire un arbre plus régulier tombe à court

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'un arbre. 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 des caractéristiques communes

  • C'est complètement inutile pour produire 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 un support limité (avec XML::Sax backend) ou Aucun (avec XML::Parser backend) pour les espaces de noms et les préfixes d'espaces de noms.

  • Il ne peut pas gérer les é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 un élément enfant et un attribut portant le même nom.

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

Ignorant les problèmes majeurs 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ébut.

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 avoir que XML::Simple ne le fait pas:

  • Vitesse. XML:: Simple est extrêmement lent, surtout si vous utilisez un backend autre que XML:: Parser. Je parle d'ordres de grandeur plus lents que les autres analyseurs.

  • Sélecteurs XPath ou similaire.

  • Prise en charge de documents extrêmement volumineux.

  • Soutien pour jolie impression.

XML::Simple est-il toujours 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é seules sont 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 jamais j'avais besoin de gérer des documents qui ne rentraient pas dans la mémoire, j'utiliserais XML::LibXML::Reader (et son copyCurrentNode(1)) ou XML:: Twig (en utilisant twig_roots).

32
répondu ikegami 2017-10-16 00:08:34

Je ne suis pas d'accord avec les docs

Je vais dissident et dire que XML::Simple est juste cela.. simple. Et, il a toujours été facile et agréable pour moi d'utiliser. 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 docs sont faux parce qu'ils prennent en compte l'exactitude sur l'efficacité. Si vous ne vous souciez que de ce qui suit, vous êtes bon:

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

Si vous créez un analyseur abstrait qui n'est pas défini par application mais par spec, j'utiliserais autre chose. J'ai travaillé dans une entreprise une fois et nous avons dû accepter 300 schémas différents de XML 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 tout rigide englobant le format spec'ed tel que si vous écrivez un analyseur, vous êtes bon. Si c'est le cas, n'utilisez pas XML::Simple. XML, avant JSON, était juste un format "dump this and walk" d'une langue à l'autre. Les gens utilisaient des choses comme XML::Dumper. Personne ne savait réellement ce qui était sorti. Faire face à ce scénario XML::Simple est génial! Les gens sains d'esprit vident encore à JSON sans spécification pour accomplir la même chose. C'est juste la façon dont le monde fonctionne.

Voulez lire les données et ne vous inquiétez pas de la format? Vous voulez traverser des structures Perl et non des possibilités XML? Allez XML::Simple.

Par extension...

De même, pour la plupart des applications JSON::Syck sont suffisantes pour vider ceci et marcher. bien que si vous envoyez à beaucoup de gens, jesuggère fortement de ne pas être une buse de douche 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 qui veut ses données que vous n'avez pas normalement exportation. Et, vous allez le diriger à travers le vaudou de JSON::Syck et les laisser s'inquiéter à ce sujet. Si ils veulent XML? Chargez-leur 500 $ de plus et lancez ye ' ole XML::Dumper.

À emporter

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

Les autres réponses

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

Perl ne fournit pas de mécanisme facile 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 délicat. XML::Simple le sait et c'est pourquoi vous pouvez forcer l'ancien.. Cependant, même avec ForceArray, si l'élément n'est pas là, vous lancerez un erreur..

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

Maintenant, si {[17] } est facultatif, vous y accédez $xml->{bar}[0]{foo} et @{$xml->{bar}}[0] lancera une erreur. De toute façon, c'est juste perl. Cela a 0 à voir avec XML::Simple imho. Et, j'ai admis que XML::Simple n'est pas bon pour construire à spec. Montrez-moi les données, et je peux y accéder avec XML:: Simple.

4
répondu Evan Carroll 2015-10-26 17:31:52