|
Pages: [1]
|
 |
|
Auteur
|
Sujet: [résolu]-[Perl] lenteur avec XML::XPath (Lu 2184 fois)
|
|
tetram9
|
salut,
J'ai un script qui utilise XML::XPath et je trouve ce script particulièrement lent ! Il ne réalise pourtant que 5 requêtes XPath sur un fichier XML qui ne pèse que 50 ko environ...
Est-ce qu'il serait de notoriété publique que XML::XPath soit un module lent ou bien ai-je codé avec les pieds ?
|
|
|
|
« Dernière édition: 04 Août 2005, 17:23:08 par tetram9 »
|
Journalisée
|
|
|
|
|
trinitacs
|
Pour avoir codé un parseur xml il chargeait 60ko de xml en 0,009 sec. Donc on va dire que le temps du chargement du fichier ne devrait pas poser de problème. Ensuite toutes les requêtes XPath ne sont pas équivalentes en terme d'éxécution. Un /foo/bar sera plus rapide qu'un //foo/bar tout comme un /foo/bar[1] sera plus rapide qu'un /foo/bar. Donc essaye de paufiner tes requêtes XPath pour limiter le parcours dans l'arbre xml. Par expériences les requêtes XPath peuvent vraiment plomber les perfs. Par exemple l'opérateur | est désastreux niveau performances. Pour preuve il n'y a qu'à voir oo2mangue.xsl.
Montre nous ton doc xml et tes requêtes XPath on pourra t'aider à les améliorer ;-)
|
|
|
|
|
Journalisée
|
Tonight, I'm rock'n'roll star
|
|
|
|
tetram9
|
Bon, je passe la seconde alors... Je vous explique ce que je fais, ensuite je vous donne le code que j'ai fait avec mes doigts de pieds  Il s'agit de parser un fichier XML issu d'une extension de Firefox : Bookmark synchroniser. Cette extension permet d'exporter les bookmarks de firefox sur un serveur distant et ce au format XBEL (XML Bookmark Exchange Language). il suffit ensuite d'avoir l'extension sur toutes les machines où vous avez une session et vos bookmarks sont toujours à jour. Du coup, je dispose sur mon serveur du fichier xml en question. Li'dée est que lorsque je surfe depuis une machine qui ne m'appartient pas, je puisse accéder à mes bookmarks quand même. Pour ça il me suffit de parser le fichier XML et d'afficher ça en html. J'ai donc fait ce script en Perl avec le module XML::XPath : #!/usr/bin/perl -w
use XML::XPath; use XML::XPath::XMLParser; use strict;
my $prefix = "rdf\%3A\#\$";
print "Content-type: text/html\n\n"; my $FolderId = $ENV{'QUERY_STRING'};
if($FolderId eq "") { TraiteXBEL(""); } else { TraiteXBEL($FolderId); }
exit(0);
sub TraiteXBEL { # usage: TraiteXBEL($InputFolderId); # # * SI $FolderId est defini ALORS on liste les dossiers et les liens dans le dossier correspondant ; # * SI $FolderId est vide ALORS on liste les dossiers et les liens à la racine.
my ($InputFolderId) = @_;
my $XPATH_REQUEST1; my $XPATH_REQUEST2; my $XPATH_REQUEST3; my $XPATH_REQUEST4; my $XPATH_REQUEST5;
my $XBEL = XML::XPath->new('./xbel.xml');
if($InputFolderId eq "") { $XPATH_REQUEST1='/xbel/folder/@id'; } else { $InputFolderId = $prefix.$InputFolderId; $XPATH_REQUEST1='//folder[@id=\''.$InputFolderId.'\']/folder/@id'; }
my $nodeset = $XBEL->find($XPATH_REQUEST1);
my $NbFolders = $nodeset->size(); print "<h2>Rubriques ($NbFolders)</h2>\n";
foreach my $node ( $nodeset->get_nodelist ) {
my $FolderId = XML::XPath::XMLParser::as_string( $node ); $FolderId =~ s/[ ]+?id="(.*?)"/$1/g;
# On extrait le suffixe du $FolderId pour eviter les caracteres speciaux. my $suffix = substr($FolderId,8);
# liste des dossiers $XPATH_REQUEST2='//folder[@id=\''.$prefix.$suffix.'\']/title/text()'; my $FolderName = $XBEL->find($XPATH_REQUEST2);
print "<ul>"; my $nom = XML::XPath::XMLParser::as_string( $FolderName->get_nodelist ); print "<li><a href=\"./xbel.cgi?$suffix\">$nom</a></li>\n"; print "</ul>"; }
# liste des liens if($InputFolderId eq "") { $XPATH_REQUEST3='/xbel/bookmark/@id'; } else { $XPATH_REQUEST3='//folder[@id=\''.$InputFolderId.'\']/bookmark/@id'; }
$nodeset = $XBEL->find($XPATH_REQUEST3); # on r�up�e tous les attr: id
my $NbLiens = $nodeset->size(); print "<h2>Marque-pages ($NbLiens)</h2>\n";
foreach my $node ( $nodeset->get_nodelist ) {
my $BookmarkId = XML::XPath::XMLParser::as_string( $node ); $BookmarkId =~ s/[ ]+?id="(.*?)"/$1/g;
# liste des bookmarks
$XPATH_REQUEST4='//bookmark[@id=\''.$BookmarkId.'\']/title/text()'; my $BookmarkTitles = $XBEL->find($XPATH_REQUEST4); my $BookmarkTitle = XML::XPath::XMLParser::as_string( $BookmarkTitles->get_nodelist );
$XPATH_REQUEST5='//bookmark[@id=\''.$BookmarkId.'\']/@href'; my $BookmarkUrls = $XBEL->find($XPATH_REQUEST5); my $BookmarkUrl = XML::XPath::XMLParser::as_string( $BookmarkUrls->get_nodelist ); $BookmarkUrl =~ s/[ ]+?href="(.*?)"/$1/g;
print "<a href=\"$BookmarkUrl\">$BookmarkTitle</a><br />\n"; } }
il y a deux cas de figure : - le script reçoit un id en argument par l'url (méthode GET)
- ou pas
Si aucun argument n'est passé par l'url, alors on affiche la liste des dossiers (balise folder) grâce à leur attribut id. ainsi que la liste des bookmarks à la racine. Si un id est passé en argument, alors, on fait la même démarche mais en partant du dossier correspondant. Voila...
|
|
|
|
|
Journalisée
|
|
|
|
|
trinitacs
|
Le problème ce sont tes reqêtes qui commencent par //folder. À chaque fois ça force le moteur XPath à parcourir le document en entier. Tu fais 5 requêtes avec // dont certaines dans un foreach. Je pense que le plus simple serait de faire une fonction récursive qui descend d'un niveau dans les dossiers à chaque fois. Le script parcoura tjrs le document en entier mais une seule fois et non plus plein de fois comme c'est le cas.
Mais le mieux c'est une feuille xslt ;-)
|
|
|
|
|
Journalisée
|
Tonight, I'm rock'n'roll star
|
|
|
|
tetram9
|
Le problème ce sont tes reqêtes qui commencent par //folder. À chaque fois ça force le moteur XPath à parcourir le document en entier. Tu fais 5 requêtes avec // dont certaines dans un foreach. Je pense que le plus simple serait de faire une fonction récursive qui descend d'un niveau dans les dossiers à chaque fois. Le script parcoura tjrs le document en entier mais une seule fois et non plus plein de fois comme c'est le cas.
Ca veut dire qu'il faudrait construire une requête différente à chaque appel de la fonction ? Mais le mieux c'est une feuille xslt ;-)
Peut-être mais je connait pas XSLT, vu que ton cours sur le sujet n'est pas en ligne 
|
|
|
|
|
Journalisée
|
|
|
|
|
Lawouach
|
Pourrais tu mettre en ligne ton doc xml stp ? 
|
|
|
|
|
Journalisée
|
|
|
|
|
tetram9
|
Pourrais tu mettre en ligne ton doc xml stp ?  En voila un bout (parce qu'en entier, c'est trop long...) mais ce morceau suffit pour avoir une idée précise de la structure du document <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xbel PUBLIC "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML" "http://pyxml.sourceforge.net/topics/dtds/xbel-1.0.dtd"> <xbel> <title>Marque-pages</title> <info> <metadata owner="Mozilla" BookmarksToolbarFolder="rdf:#$lBpT9"/> </info> <folder id="rdf%3A#$bHpT9"> <title>Mangue.org</title> <bookmark id="rdf%3A#$MIpT9" href="http://www.mangue.org/"> <title>Asso - Mangue.org</title> </bookmark> <bookmark id="rdf%3A#$NIpT9" href="http://communaute.mangue.org/"> <title>Communauté Mangue.Org</title> </bookmark> <bookmark id="rdf%3A#$PIpT9" href="http://forum.mangue.org/"> <title>Forum Mangue.org</title> </bookmark> </folder> <folder id="rdf%3A#$bCpT9"> <title>Livres</title> <folder id="rdf%3A#$AEpT9"> <title>O'Reilly</title> <bookmark id="rdf%3A#$KHpT9" href="http://learninglab.oreilly.com/"> <title>O'Reilly Learning Lab</title> </bookmark> <bookmark id="rdf%3A#$LHpT9" href="http://www.oreilly.com/"> <title>O'Reilly.com</title> </bookmark> <bookmark id="rdf%3A#$MHpT9" href="http://www.oreilly.fr/"> <title>O'Reilly - Site français</title> </bookmark> <bookmark id="rdf%3A#$NHpT9" href="http://www.oreilly.com/openbook/"> <title>O'Reilly Open Books Project</title> </bookmark> <bookmark id="rdf%3A#$OHpT9" href="http://www.oreillynet.com/"> <title>O'Reilly Network</title> </bookmark> <bookmark id="rdf%3A#$PHpT9" href="http://conferences.oreillynet.com/"> <title>O'Reilly Conferences</title> </bookmark> <bookmark id="rdf%3A#$QHpT9" href="http://www.onlamp.com/"> <title>O'Reilly - ONLamp.com</title> </bookmark> <bookmark id="rdf%3A#$RHpT9" href="http://www.onjava.com/"> <title>O'Reilly - ONJava.com</title> </bookmark> <bookmark id="rdf%3A#$SHpT9" href="http://www.perl.com/"> <title>O'Reilly - Perl.com</title> </bookmark> <bookmark id="rdf%3A#$THpT9" href="http://www.xml.com/"> <title>O'Reilly - XML.com</title> </bookmark> <bookmark id="rdf%3A#$UHpT9" href="http://www.windowsdevcenter.com/"> <title>O'Reilly - WindowsDevCenter.com</title> </bookmark> </folder> <bookmark id="rdf%3A#$BEpT9" href="http://www.freeprogrammingresources.com/books.html"> <title>Free Programming Books, freeprogrammingresources.com</title> </bookmark> <bookmark id="rdf%3A#$CEpT9" href="http://www.freetechbooks.com"> <title>FreeTechBooks</title> </bookmark> <bookmark id="rdf%3A#$DEpT9" href="http://www.maththinking.com/boat/booksIndex.html"> <title>Ju Rao's Homepage: Computer Books</title> </bookmark> <bookmark id="rdf%3A#$EEpT9" href="http://bookshelf.sleepnet.net/files/"> <title>Livres d'informatique</title> </bookmark> <bookmark id="rdf%3A#$FEpT9" href="http://www.numerical-recipes.com/"> <title>Numerical Recipes Home Page</title> </bookmark> <bookmark id="rdf%3A#$GEpT9" href="http://www.geocities.com/xiaolinli/FreeEBooksProg.htm"> <title>Programming Books</title> </bookmark> </folder> </xbel>
|
|
|
|
|
Journalisée
|
|
|
|
|
Lawouach
|
Hmm effectivement une feuille de style de type push serait l'ideal ici...
Je regarde ça
|
|
|
|
|
Journalisée
|
|
|
|
|
tetram9
|
Hmm effectivement une feuille de style de type push serait l'ideal ici...
C'est quoi ?
|
|
|
|
|
Journalisée
|
|
|
|
|
Lawouach
|
Voilà un exemple de feuille XSLT type PUSH: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/> <xsl:template match="/xbel"> <xsl:apply-templates select="//folder" /> </xsl:template> <xsl:template match="folder"> <ul> <xsl:apply-templates select="bookmark" /> </ul> </xsl:template> <xsl:template match="bookmark"> <li> <xsl:apply-templates select="title" /> </li> </xsl:template> <xsl:template match="title"> <xsl:apply-templates /> </xsl:template> </xsl:stylesheet>
Type PULL : <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/> <xsl:template match="/xbel"> <xsl:for-each select="//folder"> <ul> <xsl:for-each select="bookmark"> <li><xsl:value-of select="title"/></li> </xsl:for-each> </ul> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Sur l'exemple d'XML que tu donnes ça retourne ça dans les deux cas: <ul> <li>Asso - Mangue.org</li> <li>Communauté Mangue.Org</li> <li>Forum Mangue.org</li> </ul> <ul> <li>Free Programming Books, freeprogrammingresources.com</li> <li>FreeTechBooks</li> <li>Ju Rao's Homepage: Computer Books</li> <li>Livres d'informatique</li> <li>Numerical Recipes Home Page</li> <li>Programming Books</li> </ul> <ul> <li>O'Reilly Learning Lab</li> <li>O'Reilly.com</li> <li>O'Reilly - Site français</li> <li>O'Reilly Open Books Project</li> <li>O'Reilly Network</li> <li>O'Reilly Conferences</li> <li>O'Reilly - ONLamp.com</li> <li>O'Reilly - ONJava.com</li> <li>O'Reilly - Perl.com</li> <li>O'Reilly - XML.com</li> <li>O'Reilly - WindowsDevCenter.com</li> </ul>
PULL : C'est le createur de la feuille de style qui tire du document XML uniquement les éléments dont il a besoin (la boucle xsl:for-each et le xsl:value) PUSH: La feuille de style indique simplement comment traiter les éléments quand ils sont rencontrés dans le document XML. C'est le processeur XSLT qui lorsqu'il rencontre un noeud XML regarde dans la feuille de style : "est ce que j'ai un template pour la transformation de ce noeud? si oui je l'utilise, sinon je ne fais rien!" Le modèle PUSH est légèrement plus compliqué et plus verbeux mais plus modulaire aussi et plus indépendant de la structure même du document XML. La différence n'est peut etre pas flagrante ici car dans les deux cas je fais un "//folder" qui récupère dès le debut tous les noeuds folder.
|
|
|
|
« Dernière édition: 28 Juillet 2005, 14:27:50 par Lawouach »
|
Journalisée
|
|
|
|
|
trinitacs
|
Le problème ce sont tes reqêtes qui commencent par //folder. À chaque fois ça force le moteur XPath à parcourir le document en entier. Tu fais 5 requêtes avec // dont certaines dans un foreach. Je pense que le plus simple serait de faire une fonction récursive qui descend d'un niveau dans les dossiers à chaque fois. Le script parcoura tjrs le document en entier mais une seule fois et non plus plein de fois comme c'est le cas. Ca veut dire qu'il faudrait construire une requête différente à chaque appel de la fonction ? Qqch qui ressemblerait à ça. Il suffit juste de donner le noeud racine à la fonctione et le tour est joué. Vive les cgi en Perl ;-) sub display_bookmarks( $parent ) { $children = $parent->find( "folder" ); foreach my $child ( $children->get_nodelist() ) display_bookmarks( $child );
$children = $parent->find( "bookmark" ); foreach my $child ( children->get_nodelist() ) print $child->get_attribute( "href" ); }
Peut-être mais je connait pas XSLT, vu que ton cours sur le sujet n'est pas en ligne Cool Pinaise je l'avais oublié  Ce we je m'en occupe juste avant de prendre le train :-)
|
|
|
|
|
Journalisée
|
Tonight, I'm rock'n'roll star
|
|
|
|
|
|
|
|
madflo
|
salut,
J'ai un script qui utilise XML::XPath et je trouve ce script particulièrement lent ! Il ne réalise pourtant que 5 requêtes XPath sur un fichier XML qui ne pèse que 50 ko environ...
Est-ce qu'il serait de notoriété publique que XML::XPath soit un module lent ou bien ai-je codé avec les pieds ?
Si, c'est extrèmement lent. Quand je l'utilise pour du SOAP avec les webservices Amazon, c'est assez impressionnant de lenteur et ultra gourmand en cpu. Genre 1s sur un PIII 600 pour extraire une info d'un sous node (genre node1/node2/node3) sur un fichier de... quelques ko.
|
|
|
|
|
Journalisée
|
|
|
|
|
|
|
|
Pages: [1]
|
|
|
 |