IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

XSL/XSLT/XPATH XML Discussion :

[XSLT] Streaming (gros fichiers), Saxon, with-param avec apply-templates


Sujet :

XSL/XSLT/XPATH XML

  1. #1
    Futur Membre du Club
    Inscrit en
    Juin 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Juin 2008
    Messages : 8
    Points : 6
    Points
    6
    Par défaut [XSLT] Streaming (gros fichiers), Saxon, with-param avec apply-templates
    Bonjour,

    Ma question concerne le traitement de fichiers XML avec XSLT, de tres gros fichiers. Etant completement debutant (avant de commencer a toucher a xsl il y a environ 1 mois ou 2, je ne connaissais que le nom et le concept), il se peut que de fasse des erreurs de raisonnement, excusez moi par avance.
    Ainsi, on m'avait confier la tache de tester divers processeurs XSLT, et au vu de mes benchmarks, il etait evident qu'il faudrait qu'on change notre approche par rapport au traitement de gros fichiers XML, a moins qu'on passe notre temps a rajouter de la RAM sur les serveurs ^^;

    Bref, la chose est que je dois trouver donc une solution pour traiter des gros fichiers XML pour les transformer en TXT, CSV, HTML et PDF.
    Je possede des feuilles XSLT qui marchent deja parfaitement sur de petits fichiers.

    Apres m'etre apercu qu'il etait trop couteux en temps d'apprentissage et d'installation de l'environemement, j'ai ecarte la piste (qui avait helas l'air bien) des processeurs de flux bases sur des languages comme OCaml (XStream, etc.).

    STX aussi avait l'air prometteur, mais helas 3 fois plus lent compare a ce que Xalan faisait deja avec nos feuilles XSL (non optimisees ?).

    L'approche normale avec des processeurs XSLT etant impossible elle aussi, j'ai pense utiliser l'option special pour traiter en streaming avec Saxon.
    Je dois dire que j'ai resolu le probleme avec la fonction la plus recente couplant <saxon:iterate> et saxon:stream().

    Helas, on me rajoute une nouvelle condition : il faut que les feuilles XSL que je cree soient compatibles et traitables aussi avec n'importe quel autre processeur XSLT (sur des petits fichiers par exemple...). Abandon donc des fonctions saxon:iterate et saxon:stream, la seule possibilite qu'il me reste est de revenir a l'utilisation de l'attribut read-once="true" dans un element <xsl:copy>, comme explique ici : http://www.saxonica.com/documentatio...cs/serial.html

    Vient enfin le probleme : pourquoi j'utilisais l'autre fonction ? Parce que j'ai besoin que mon processeur se rappelle de choses qu'il a lu avant pour traiter la suite.

    Pour faire simple, voici le type de fichier XML que j'ai a traiter, et dont je n'ai pas le droit de changer le format :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <columnSet>
      <column>column3</column>
      <column>column1</column>
    <columnSet>
    <logs>
      <log>
        <column1>text 1</column1>
        <column2>text 2</column2>
        <column3>text 3</column3>
      </log>
      <log>
        <column1>text a</column1>
        <column2>text b</column2>
        <column3>text c</column3>
      </log>
    </logs>
    A l'interieur de <logs></logs>, il peut y avoir des centaines de mega de donnees a travers des milliers d'element <log>.

    En sortie, il faut sortir a chaque ligne le texte entre les balises <column*>, en fonction du contenu de <columnSet>. Dans le cas present, il faudrait avoir en sortie :

    text 3 text 1
    text c text a

    Pour compliquer la chose, le code que j'ai ecrit est compris dans d'autres elements, et le columnSet change donc pour d'autres <logs>.
    Avec Saxon, il faut catcher dans la commande <xsl:copy-of select="doc('source.xml')//(columnSet|log)" saxon:read-once="yes" xmlns:saxon="http://saxon.sf.net/"/> tous les elements que l'on veut traiter par la suite, et en plus il faut qu'il soit de petite taille (pour eviter le prob de OutOfmemoryError que je cherche a regler en utilisant un traitement par streaming).
    Ainsi, aucun moyen de faire catcher le contenu de <logs> d'un coup, ou meme de l'element encadrant le code XML que j'ai ecris.

    Bref, je pensais pouvoir faire qqchose avec a un certain moment dans ma feuille XSL :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <xsl:template match="log">
        <xsl:param name="columnSet" />
        <xsl:variable name="log" select="."/>
        <tr>
            <xsl:for-each select="$columnSet">
                <td nowrap="true" bgcolor="#FFFFFF" valign="top" style="font-size:8pt;">
                    <xsl:choose>
                        <xsl:when test=".='column1'">
                            <xsl:value-of select="$log/column1"/>
                        </xsl:when>
                        <xsl:when test=".='column2'">
                            <xsl:value-of select="$log/column2"/>
                        </xsl:when>
                        <xsl:when test=".='column3'">
                            <xsl:value-of select="$log/column3"/>
                        </xsl:when>
                        <xsl:otherwise/>
                    </xsl:choose>
                </td>
            </xsl:for-each>
        </tr>
        <xsl:apply-templates>
            <xsl:with-param name="tableOpened" select="$tableOpened" />
        </xsl:apply-templates>
    </xsl:template>
    Le code XML que j'ai a traiter est legerement plus complique que ce que j'ai decrit, mais en bref je n'arrive deja pas a faire ce que je veux avec la version simplifiee que j'ai explique.

    J'ai par exemple des elements <name> et <remark> a traiter de facon differente selon les endroits ou ils se trouvent.

    Par ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <report>
      <name>Rapport</name>
      <remark>Description</remark>
      <search>
        <name>Sous rapport 1</name>
        <remark>Description sous rapport 1</remark>
        <logs>
          <log>(...)</log>
          <log>(...)</log>
        </logs>
      </search>
      <search>
        <name>Sous rapport 1</name>
        <remark>Description sous rapport 1</remark>
        <logs>
          <log>(...)</log>
          <log>(...)</log>
        </logs>
      </search>
    </report>
    Ainsi, dans mon code HTML de sortie, le titre du rapport au debut est a traiter differemment des titres de sous rapports... et apparamment, si dans mon select associe a <xsl:copy-of> je cherche a catcher report/name et search/name, saxon ne semple pas pouvoir marcher en streaming pour ca...

    Je pensais donc regler tout ceci avec un copy-of genre :
    <xsl:copy-of select="doc('source.xml')//(name|remark|columnSet|log)" saxon:read-once="yes" xmlns:saxon="http://saxon.sf.net/"/>
    Puis, a l'aide de plusieurs templates et param/with-param, je comptais passer de template en template mes variables, etc..

    Voici un extrait de mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
    <xsl:function name="f:report_source">
        <xsl:copy-of select="doc($document)//(date|time|name|remark|term|columnSet)" saxon:read-once="yes" xmlns:saxon="http://saxon.sf.net/"/>
    </xsl:function>
     
    <xsl:template name="main">
        <html>
            <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
            <body>
                <xsl:apply-templates select="f:report_source()" />
            </body>
        </html>
    </xsl:template>
     
    <xsl:template match="date">
        <xsl:apply-templates>
            <xsl:with-param name="reportDate" select="." />
        </xsl:apply-templates>
    </xsl:template>
     
      <xsl:template match="time">
        <xsl:param name="reportDate" />
        <xsl:apply-templates>
            <xsl:with-param name="reportDate" select="$reportDate" />
            <xsl:with-param name="reportTime" select="." />
            <xsl:with-param name="headerProcessed" select="false()" />
        </xsl:apply-templates>
    </xsl:template>
     
    <xsl:template match="name">
        <xsl:param name="reportDate" />
        <xsl:param name="reportTime" />
        <xsl:param name="headerProcessed" />
        <xsl:text>pouet</xsl:text>
        <xsl:choose>
            <xsl:when test="$headerProcessed">
                <!-- /report/condition/search/name -->
                <xsl:apply-templates>
                    <xsl:with-param name="headerProcessed" select="$headerProcessed" />
                    <xsl:with-param name="searchName" select="." />
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <!-- /report/name -->
                <xsl:apply-templates>
                    <xsl:with-param name="headerProcessed" select="$headerProcessed" />
                    <xsl:with-param name="reportDate" select="$reportDate" />
                    <xsl:with-param name="reportTime" select="$reportTime" />
                    <xsl:with-param name="reportName" select="." />
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    Hors lorsque je l'execute, je m'apercois que mes variables ne sont pas du tout passees aux autres templates, a aucun moment. De meme, le code source XML ne semble pas se faire catcher correctement, et est rendu direct en copie dans la sortie par les templates par defaut.

    Je n'ai pas l'impression de pouvoir utiliser <xsl:call-template> vu mon architecture, du coup je dois utiliser <xsl:apply-templates>, tout en passant mes parametres aux templates suivants. Le probleme semble neanmoins bien venir de la, mais je ne comprends pas pouvoir. J'ai beau lire et relire la specification de XSLT, je n'arrive pas a comprendre pourquoi mon code ne fonctionne pas :/

    Y aurait il quelqu'un qui ait une idee sur le pourquoi du fait que cela ne fonctionne pas ?
    Ou alors une idee sur un moyen de regler ce probleme, ou le contourner, etc.

    Merci d'avance !

    Guillaume

  2. #2
    Futur Membre du Club
    Inscrit en
    Juin 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Juin 2008
    Messages : 8
    Points : 6
    Points
    6
    Par défaut
    En fait le probleme se resume a pas grand chose du tout en fait. Il n'y a meme pas besoin d'avoir saxon ou de chercher a traiter les choses en streaming bon comprendre le probleme.

    Je voudrais donc avec une base comme la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <xsl:function name="f:report_source">
        <xsl:copy-of select="doc($document)//(a|b|c)"/>
    </xsl:function>
     
    <xsl:template name="main">
        <html>
            <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
            <body>
                <xsl:apply-templates select="f:report_source()" />
            </body>
        </html>
    </xsl:template>
    Pouvoir traiter le code XML suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <a>data1</a>
    <b>data2</b>
    <c>data3</c>
    Et avoir quelquepart en memoire (variable locale, parametre, n'importe quoi) le contenu de <a>...</a> au moment ou je traite <b>...</b> et <c>...</c> (dans les template dont les select sont par exemple select="b" et select="c")

    Est-ce possible ?
    Meme s'il existe un moyen tres tordu, ca ne me derange pas, je suis interesse pour en savoir plus.
    Ou alors est-ce completement impossible au vu de la specification XSLT 2.0 ?

    Par ailleurs, je peux comprendre que ce que je cherche a faire parraisse bizarre, mais je rappelle que c'est dans un but final d'utiliser une fonction particuliere de Saxon pour traiter d'enormes fichiers en streaming, qu'il serait impossible a traiter d'une facon normale (avec tout l'arbre en memoire), a moins d'avoir 10GB de memoire memoire RAM, chose que je ne peux pas me permettre...

    Merci d'avance

  3. #3
    Expert éminent
    Avatar de GrandFather
    Inscrit en
    Mai 2004
    Messages
    4 587
    Détails du profil
    Informations personnelles :
    Âge : 54

    Informations forums :
    Inscription : Mai 2004
    Messages : 4 587
    Points : 7 103
    Points
    7 103
    Par défaut
    Bonjour,

    je ne connais pas toutes les contraintes qui te sont imposées, mais j'opterais personnellement pour un pré-traitement avec une application utilisant SAX, puis par un passage par des feuilles de style XSL pour le rendu final en PDF, TXT, etc.
    FAQ XML
    ------------
    « Le moyen le plus sûr de cacher aux autres les limites de son savoir est de ne jamais les dépasser »
    Giacomo Leopardi

Discussions similaires

  1. Réponses: 2
    Dernier message: 28/11/2009, 23h20
  2. [XSLT] Include de fichiers XML et parsing avec du XSL
    Par ElSegador66 dans le forum XSL/XSLT/XPATH
    Réponses: 9
    Dernier message: 25/10/2009, 10h19
  3. [XPath] cibler les noeuds avec apply-templates
    Par yos dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 29/01/2007, 14h34
  4. [XSLT] problème avec apply-templates
    Par ploxien dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 01/11/2006, 11h20
  5. [XSLT] Problème avec apply-templates
    Par NeoMan dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 29/12/2005, 14h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo