XSLT très lent

XSLT très lent - XML/XSL - Programmation

Marsh Posté le 27-02-2017 à 20:42:54    

Bonjour,
Je reproduis une carte SVG en modifiant certains attribuer (pour la colorier) mais c'est très lent (avec libsaxonb-java).
Sachant que mon fichier svg possède quelques dizaines de milliers de polygones, et que mon fichier "communes.xml" contient à peu près le même nombre d'entrées.
Il peut prendre plus de 10 minutes à s'exécuter...  
Des idées ?
 
Merci d'avance!
 

Code :
  1. <xsl:stylesheet version="2.0"
  2.    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.    xmlns:xs="http://www.w3.org/2001/XMLSchema"
  4.    xmlns:doc="http://jlm2017.fr"
  5.    xmlns:fn="http://www.w3.org/2005/xpath-functions"
  6.    xmlns:dc="http://purl.org/dc/elements/1.1/"
  7.   xmlns:cc="http://creativecommons.org/ns#"
  8.   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  9.   xmlns:svg="http://www.w3.org/2000/svg"
  10.   xmlns="http://www.w3.org/2000/svg"
  11.   xmlns:xlink="http://www.w3.org/1999/xlink"
  12.   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  13.   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  14.   inkscape:version="0.48.2 r9819"
  15.   sodipodi:docname="circonscriptions.svg"
  16.    exclude-result-prefixes="xs doc">
  17.    <xsl:output method="xml" indent="yes"/>
  18.    <xsl:param name="communes" select="document('../communes.xml')"/>
  19.    <xsl:template match="@*|node()">
  20.        <xsl:copy>
  21.            <xsl:apply-templates select="@*|node()"/>
  22.        </xsl:copy>
  23.    </xsl:template>
  24.    <xsl:template match="svg:polygon">
  25.       <xsl:variable name="insee" select="substring-before(./@id, ' ')" />
  26.       <xsl:variable name="red" select="$communes//fn:map[@key=$insee]/fn:number[@key='HOLL_PRES_2012']" />
  27.        <xsl:copy>
  28.          <xsl:choose>
  29.            <xsl:when test="$red">
  30.              <xsl:attribute name="fill">rgb(255, <xsl:value-of select="255-round(255 * $red div 100)" />, <xsl:value-of select="255-round(255 * $red div 100)" /> )</xsl:attribute>
  31.            </xsl:when>
  32.            <xsl:otherwise>
  33.              <xsl:attribute name="fill">rgb(100, 100, 100)</xsl:attribute>
  34.            </xsl:otherwise>
  35.          </xsl:choose>
  36.          <xsl:apply-templates select="@*|node()" />
  37.        </xsl:copy>
  38.    </xsl:template>
  39. </xsl:stylesheet>

Reply

Marsh Posté le 27-02-2017 à 20:42:54   

Reply

Marsh Posté le 28-02-2017 à 14:41:55    

C'est clairement l'appel
select="$communes//fn:map[@key=$insee]/fn:number[@key='HOLL_PRES_2012']"
qui reparcourt ton arbre a chaque svg:polygon qui va être lent. Les // c'est coûteux en temps.
 
Il y a peut-être moyen de ne faire qu'une passe et indexer avec un xsl:key.
Par contre, il y a manifestement des bouts de code que tu n'as pas donné, car je ne comprends pas des choses comme:
fn:number[@key='HOLL_PRES_2012']
fn:number est une fonction, donc ca devrait etre qque chose comme fn:number(...)
Si tu expliques un peu mieux ce que tu veux faire, je devrais être en mesure de t'aider (si je trouve le temps, car la j'ai moi aussi plein de code xsl a écrire.)
On dirait du MarkLogic, tes fn:map et fn:number.
 
A+,


Message édité par gilou le 28-02-2017 à 16:55:50

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 28-02-2017 à 18:57:10    

Merci pour ta réponse gilou,
 
En réponse à ta première remarque, j'ai modifié un peu le code  

Code :
  1. <xsl:stylesheet version="2.0"
  2.    <xsl:variable name="communes" select="document('../communes.xml')/fn:map"/>
  3. ...
  4.       <xsl:variable name="red" select="$communes/fn:map[@key=$insee]/fn:number[@key='NON_TCE']" />


 
Le code de communes.xml est généré automatiquement (de json en XML via basex)
 

Code :
  1. <map xmlns="http://www.w3.org/2005/xpath-functions">
  2.  <map key="89370">
  3.    <number key="NONISTES_DROITE_PRES_2007">15.33</number>
  4.    <number key="POUT_PRES_2012">1.92</number>
  5.    <number key="BOVE_PRES_2007">0.70</number>
  6.    <number key="NONISTES_2012">35.61</number>
  7.    <number key="LEPE_PRES_2007">11.50</number>
  8.    <number key="SCHI_PRES_2007">0.93</number>
  9.    <number key="LAGU_PRES_2007">1.86</number>
  10.    <number key="NON_TCE">59.08</number>
  11.    <number key="SARK_PRES_2007">37.17</number>
  12.    <number key="CHEM_PRES_2012">0.12</number>
  13.    <number key="BAYR_PRES_2007">16.26</number>
  14.    <number key="HOLL_PRES_2012">23.38</number>
  15.    <number key="ARTH_PRES_2012">0.36</number>
  16.    <number key="DUPO_PRES_2012">1.92</number>
  17.    <number key="BUFF_PRES_2007">2.09</number>
  18.    <number key="NIHO_PRES_2007">1.16</number>
  19.    <number key="MELE_PRES_2012">10.67</number>
  20.    <number key="BESA_PRES_2007">4.41</number>
  21.    <number key="LEPE_PRES_2012">20.74</number>
  22.    <number key="BAYR_PRES_2012">7.55</number>
  23.    <number key="NONISTES_2007">22.76</number>
  24.    <number key="VOYN_PRES_2007">0.70</number>
  25.    <number key="OUI_TCE">40.92</number>
  26.    <number key="NONISTES_DROITE_PRES_2012">22.66</number>
  27.    <number key="ROYA_PRES_2007">20.56</number>
  28.    <number key="JOLY_PRES_2012">2.16</number>
  29.    <number key="SARK_PRES_2012">31.18</number>
  30.    <number key="NONISTES_GAUCHE_PRES_2012">12.95</number>
  31.    <number key="NONISTES_GAUCHE_PRES_2007">7.43</number>
  32.    <number key="VILL_PRES_2007">2.67</number>
  33.  </map>
  34. etc.


 
Du coup comme tu le vois il y a un namespace dedans et si je n'utilise pas ce namespace fn: mes requêtes xpath échouent.
Du coup si c'est une partie du problème, je ne sais pas trop comment le régler :s

Reply

Marsh Posté le 28-02-2017 à 22:26:14    

Ah! OK!
Mais ton namespace est bizarre alors: http://www.w3.org/2005/xpath-functions est le namespace des fonctions standard xpath, et a priori tu as ici des éléments, pas des fonctions.
Comme j'utilise SaxonEE et non Saxonb, je ne sais pas trop ce que c'est dans ton cas.
 
Bon, tu aurais xslt 3, tu pourrais utiliser les xsl:map, mais en xslt2, tu n'as que les xsl:key, et ils ne peuvent indexer que la source.
 
Ce que je ferais:
- importer tes deux fichier dans un englobant (technique  comme ici par exemple) et passer celui ci comme source de données a ta feuille de style
- passer a la trappe ce qui vient de ../communes.xml qui ne sert qu'a créer un index dans ta feuille de style, index qui associe la valeur de fn:key au sous arbre fn:map
- faire une xsl:key qui indexe les elements map avec comme cle leur attribut key
<xsl:key name="citykey" match="lfn:map[@key]" use="@key"/>
- utiliser cette xsl:key dand ton <xsl:variable name="red" select="... afin de ne chercher la donnée que sur sa liste de number, ce qui est petit, et non sur tout $communes a chaque fois
<xsl:variable name="city" select="key('citykey', substring-before(@id, ' '))"/>
<xsl:variable name="red" select="$city/fn:number[@key='HOLL_PRES_2012']" />
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 01-03-2017 à 01:13:24    

Merci beaucoup, super cette histoire de key, je fais ça demain!

Reply

Marsh Posté le 01-03-2017 à 23:57:50    

Autre chose: éviter l'emploi de //
Dans le code initial,
$communes//fn:map[@key=$insee]/fn:number[@key='HOLL_PRES_2012']
passe en
$communes/fn:map/fn:map[@key=$insee]/fn:number[@key='HOLL_PRES_2012']
aurait sans doute été un poil plus efficace
 
Sinon, après avoir parlé avec le guru XML de ma boite, il y a une astuce avec key permettant de l'utiliser sur un document précis: c'est pas avec la définition xsl:key, mais a la première invocation avec le 3e paramètre.
Ça permet de se passer des contorsions indiquées vis a vis des fichiers comme indique dans mon post précédent.  
Il suffit juste de transformer ton code comme suit:
 

Code :
  1. <xsl:stylesheet version="2.0"
  2.         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.         xmlns:xs="http://www.w3.org/2001/XMLSchema"
  4.         xmlns:doc="http://jlm2017.fr"
  5.         xmlns:fn="http://www.w3.org/2005/xpath-functions"
  6.         xmlns:dc="http://purl.org/dc/elements/1.1/"
  7.         xmlns:cc="http://creativecommons.org/ns#"
  8.         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  9.         xmlns:svg="http://www.w3.org/2000/svg"
  10.         xmlns="http://www.w3.org/2000/svg"
  11.         xmlns:xlink="http://www.w3.org/1999/xlink"
  12.         xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  13.         xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  14.         inkscape:version="0.48.2 r9819"
  15.         sodipodi:docname="circonscriptions.svg"
  16.         exclude-result-prefixes="xs doc">
  17.  <xsl:output method="xml" indent="yes"/>
  18.  <xsl:param name="communes" select="document('../communes.xml')"/>
  19.  <xsl:key name="citykey" match="fn:map[@key]" use="@key"/>
  20.  <xsl:template match="@*|node()">
  21.    <xsl:copy>
  22.      <xsl:apply-templates select="@*|node()"/>
  23.    </xsl:copy>
  24.  </xsl:template>
  25.  <xsl:template match="svg:polygon">
  26.    <xsl:variable name="insee" select="substring-before(./@id, ' ')" />
  27.    <xsl:variable name="city" select="key('citykey', substring-before(@id, ' '), $communes)"/>
  28.    <xsl:variable name="red" select="$city/fn:number[@key='HOLL_PRES_2012']" />
  29.    <xsl:copy>
  30.      <xsl:choose>
  31.     <xsl:when test="$red">
  32.       <xsl:attribute name="fill">rgb(255, <xsl:value-of select="255-round(255 * $red div 100)" />, <xsl:value-of select="255-round(255 * $red div 100)" /> )</xsl:attribute>
  33.     </xsl:when>
  34.     <xsl:otherwise>
  35.       <xsl:attribute name="fill">rgb(100, 100, 100)</xsl:attribute>
  36.     </xsl:otherwise>
  37.      </xsl:choose>
  38.      <xsl:apply-templates select="@*|node()" />
  39.    </xsl:copy>
  40.  </xsl:template>
  41. </xsl:stylesheet>


Et tu peux peut etre encore gagner un chouia de perf en ne calculant qu'une fois, dans une variable la valeur 255-round(255 * $red div 100) et en la réutilisant.
 
A+,


Message édité par gilou le 14-12-2017 à 23:30:05

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-03-2017 à 01:36:52    

Merci beaucoup! Tu as répondu avant que je puisse m'y atteler à nouveau.
Ça marche du tonnerre!  
J'avais jamais utilisé les key, XSL m'étonne toujours, vraiment très puissant :)

Reply

Marsh Posté le 02-03-2017 à 02:11:25    

Et xsl 3, qui devrait passer au statut de "proposed recommendation" d'ici un mois environ est bien plus puissant encore (try/catch, iterate...) en particulier avec les fonctions xpath évoluées.
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed