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');
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).
7 votes
XML::Simple n'est pas dans le noyau de Perl et ne l'a jamais été. En fait, il n'y a pas de module d'analyse XML dans le noyau de Perl.
0 votes
OK. Bon point. J'aimerais bien avoir un analyseur XML "de base". Mais ça ne sera peut-être pas si facile.
0 votes
@EvanCarroll - Je me réfère à une citation de la docs sur
XML::Simple
. Mais j'accepte volontiers les opinions divergentes sur les raisons pour lesquelles la documentation est erronée, et c'est ne devrait pas être "découragés". (Je suis de cet avis pour les fils de perl).0 votes
J'ai soumis une réponse à la place, parce que vous demandez une explication, je suppose que vous la considérez comme une réponse à la question.
0 votes
Oui, c'est merveilleux. Merci.
15 votes
En tant qu'auteur de XML::Simple, je déconseille son utilisation car il existe de meilleures solutions qui sont en fait plus faciles à utiliser. Personnellement, j'utilise et recommande XML::LibXML et j'ai écrit un tutoriel pour aider les gens à démarrer. XML::LibXML par exemple
1 votes
Je suis revenu ici et j'ai lu les commentaires. Si vous voulez que quelque chose soit inclus dans le noyau, vous pouvez toujours le suggérer sur la liste de diffusion p5p. Si vous avez de bons arguments, il se peut qu'ils l'acceptent.