xsl-fo, pages alternatives et contenu

xsl-fo, pages alternatives et contenu - XML/XSL - Programmation

Marsh Posté le 21-05-2009 à 13:59:12    

Bonjour à tous !!
 
J'ai un tit problème de conception. Je ne cherche pas une solution clé en main, simplement quelques pistes pour arriver à mon but.
 
J'ai des données en base de données, que je récupère via php. Elles sont formattée avec une classe me retournant des fragments xml (xsl-fo) pour que j'arrive au final à un document passé à la moulinette via fop. J'obtiens en sortie un joli pdf, tout va bien. (je précise que ça fait 4 jours seulement que je fais du xsl-fo, suis encore un newbie)
 
Là ou ça se complique, c'est que l'ensemble des documents générés correspondent à un catalogue de produits. Ce catalogue présente à chaque fois un "modèle" avec 1 ou plusieurs articles découlant du modèle (spécifications techniques différentes pour chaque article). Qui dit catalogue dit pages recto-verso, et dans mon cas les marges sont différentes si c'est le recto ou le verso.  
 
Second point complexe : chaque page contient un tableau d'articles. Si le nombre d'article pour un modèle spécifique est trop grand, je dois passer ce tableau sur une seconde page (du multi-pages, selon le nombre d'éléments...)
 
Je cherche des pistes à propos des points suivants :  
 
1. lorsque le contenu doit passer sur plusieurs pages, pour chaque page il n'y a que le tableau qui change. J'aimerai, dans la mesure du possible, créer mon xsl-fo de manière à ce que toute la partie "hors" tableau soit définie pour toutes les pages... genre que ces éléments soient statiques sur toutes les pages d'un modèle.
 
2. Tous les éléments doivent être statique, mais je dois faire attention aux marges. Exemple : si c'est une page recto, la marge haute doit être de 3.5cm et la basse de 3cm. Si c'est une page verso, c'est l'inverse. Je dois également prendre en compte que chaque modèle ne commence pas forcément sur un recto. Le premier modèle d'une section sera toujours sur un recto. Mais si ce modèle s'étend sur 3 pages à cause du nombre d'article, alors le prochain modèle sera sur une page verso. C'est au niveau des modèles multi-pages que je me demande comment ça peut se gérer. J'ai vu qu'il y avait une balise "fo:repeatable-page-master-alternatives" et j'imagine que c'est de ce genre de chose dont j'aurai besoin, mais c'est au niveau de la mise en oeuvre que je coince un peu...
 
Pour le moment, le départ de mon xsl-fo est comme suivant :  

Code :
  1. <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
  2. <fo:layout-master-set>
  3.  <fo:simple-page-master master-name="simpleA4"
  4.    page-height="792px" page-width="1120px"
  5.    margin-top="138px" margin-bottom="98px" margin-left="161" margin-right="164">
  6.   <fo:region-body/>
  7.  </fo:simple-page-master>
  8. </fo:layout-master-set>
  9. <fo:page-sequence master-reference="simpleA4">
  10.  <fo:flow flow-name="xsl-region-body">


 
Puis j'ai ensuite une série de block-container dont la plupart sont en position absolue et placé exactement ou je veux dans la page.
 
Maintenant j'aurai besoin de quelques conseils pour placer statiquement mes éléments sur plusieurs pages et permettre ces fameuses marges alternées.
 
D'avance merci pour vos suggestions.

Reply

Marsh Posté le 21-05-2009 à 13:59:12   

Reply

Marsh Posté le 22-05-2009 à 01:00:40    

Re,
 
Bon, j'ai fini par réussir exactement ce que je désirais avec fo:repeatable-page-master-alternatives ainsi que les balises fo:static-content
 
En gros :  
 
1. un fo:static-content flow-name="xsl-region-before" avec tout mon contenu statique sur la page.
2. deux fo:simple-page-master, le premier nommé recto et le second nommé verso, qui déclarent chacun le fo:region-body et le fo:region-before.
3. un fo:page-sequence-master contenant un fo:repeatable-page-master-alternative contenant lui-même deux fo:conditional-page-master-reference. Le premier faisant référence au simple-page-master recto, le second faisant référence au simple-page-master verso. Enfin, chacun ayant la condition odd-or-even sur odd ou even, pour pouvoir alterner le design entre les pages paire et les pages impaires.
 
 
Il me reste un souci : lorsque je suis en multi-page, je dois afficher sur chaque page sauf la dernière une petite flèche ainsi qu'un index alphabétique qui indique que la page suivante est liée au même article. J'imagine que je vais devoir travailler avec les conditions, mais je ne vois pas encore très bien comment. Je ne me décourage pas, ça a déjà bien avancé.
 
a+

Reply

Marsh Posté le 27-05-2009 à 09:39:49    

Tu t'es bien débrouille on dirait  :jap:  
 
Un petit exemple pour une manuel d'utilisateur en guise d'illustration de ta solution, ici on définit du recto verso en mode portrait et paysage.
 

 
<xsl:template match="/">
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
 
        <!-- descriptions de pages individuelles -->
        <fo:simple-page-master master-name="cover"
              page-height="297mm" page-width="210mm"
              margin-top="10mm" margin-bottom="0mm"
              margin-left="15mm" margin-right="10mm">
          <fo:region-body margin-top="151mm"/>
          <fo:region-before extent="30mm"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="portrait_left"
              page-height="297mm" page-width="210mm"
              margin-top="10mm" margin-bottom="10mm"
              margin-left="10mm" margin-right="25mm"
              orphans="3" widows="3">
          <fo:region-body margin-top="11mm" margin-bottom="11mm"/>
          <fo:region-before extent="10mm"/>
          <fo:region-after extent="10mm"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="portrait_right"
              page-height="297mm" page-width="210mm"
              margin-top="10mm" margin-bottom="10mm"
              margin-left="15mm" margin-right="10mm"
              orphans="3" widows="3">
          <fo:region-body margin-top="11mm" margin-bottom="11mm"/>
          <fo:region-before extent="10mm"/>
          <fo:region-after extent="10mm"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="landscape_left"
              page-height="210mm" page-width="297mm"
              margin-top="15mm" margin-bottom="10mm"
              margin-left="10mm" margin-right="10mm">
          <fo:region-body margin-top="11mm" margin-bottom="11mm"/>
          <fo:region-before extent="10mm"/>
          <fo:region-after extent="10mm"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="landscape_right"
              page-height="210mm" page-width="297mm"
              margin-top="15mm" margin-bottom="10mm"
              margin-left="10mm" margin-right="10mm">
          <fo:region-body margin-top="11mm" margin-bottom="11mm"/>
          <fo:region-before extent="10mm"/>
          <fo:region-after extent="10mm"/>
        </fo:simple-page-master>
 
        <!-- description des sequences de pages -->
        <fo:page-sequence-master master-name="portrait" >
          <fo:repeatable-page-master-alternatives>
            <fo:conditional-page-master-reference master-reference="portrait_left"
                                                  odd-or-even="even"/>
            <fo:conditional-page-master-reference master-reference="portrait_right"
                                                  odd-or-even="odd"/>
          </fo:repeatable-page-master-alternatives>
        </fo:page-sequence-master>
 
        <fo:page-sequence-master master-name="landscape" >
          <fo:repeatable-page-master-alternatives>
            <fo:conditional-page-master-reference master-reference="landscape_left"
                                                  odd-or-even="even"/>
            <fo:conditional-page-master-reference master-reference="landscape_right"
                                                  odd-or-even="odd"/>
          </fo:repeatable-page-master-alternatives>
        </fo:page-sequence-master>
      </fo:layout-master-set>
 
      <!-- select the content part that has to be generated as fo -->
      <xsl:apply-templates select="id( $pId)"/>
    </fo:root>
  </xsl:template>


 
J'ai pas bien capté ton souci, un petit exemple?  

Reply

Marsh Posté le 27-05-2009 à 15:38:39    

Pour mon souci, c'est bon, c'est réglé également, j'explique quand même :  
 
J'ai un catalogue avec des "modèles". pour chaque modèle, une liste d'articles découlant du modèle, mais avec des specs différentes (taille, type de matériau, etc...).
 
Mon design de page accepte une liste jusqu'à 20 articles. Admettons maintenant que j'ai un modèle avec 200 articles. Je vais devoir générer un document xsl-fo qui va s'étendre sur plusieurs pages (10 pages). Lorsque j'ai du multi-page, je dois indiquer sur chaque page son index (a, b, c, d, etc...) ainsi qu'une indication visuelle pour que le lecteur se rende compte qu'il y a une page suivante concernant le même modèle.  
 
En gros, mes 10 pages vont avoir des indices "courant" de "a" à "j". Sur les 9 premières pages, je dois afficher dans un coin une petite flèche (en image) qui sert d'indication visuelle, et à sa droite l'indice de la page suivante.  
 
Page 1, j'aurai l'index courant "a", une flèche et l'indice "b" pour la page suivante.  
Page 2, j'aurai l'index courant "b", une flèche et l'indice "c" pour la page suivante, etc...
 
La dernière page, quant à elle, n'aura que l'indice de page courant : "j".
 
Pour ce faire, j'ai utilisé les balises fo:marker et fo:retrieve-marker.
 
Dans ma partie "statique", je déclare des balises "fo:retrieve-marker" qui vont s'occuper de récupérer la valeur à inscrire, selon la page :  
 

Code :
  1. <fo:retrieve-marker retrieve-class-name='index' retrieve-boundary='page' />
  2. <fo:retrieve-marker retrieve-class-name='next' retrieve-boundary='page'/>
  3. <fo:retrieve-marker retrieve-class-name='nextIndex' retrieve-boundary='page'/>


 
Mes 3 balises sont configurées pour récupérer la valeur des marqueur "index", "next" et "nextIndex", et ceci pour la page en cours.
 
Il ne me reste plus qu'a déclarer, sur chaque page, dans le contenu standard (fo:body) les marqueurs adéquats :  
 
exemple pour la première page :

Code :
  1. <fo:marker marker-class-name='index'>.a</fo:marker>
  2. <fo:marker marker-class-name='nextIndex'>b</fo:marker>
  3. <fo:marker marker-class-name='next'>
  4. <fo:external-graphic src='assets/arrow.png' width='26px' height='13px' content-width='scale-to-fit' content-height='scale-to-fit' />
  5. </fo:marker>


 
 
exemple pour la seconde page :

Code :
  1. <fo:marker marker-class-name='index'>.b</fo:marker>
  2. <fo:marker marker-class-name='nextIndex'>c</fo:marker>
  3. <fo:marker marker-class-name='next'>
  4. <fo:external-graphic src='assets/arrow.png' width='26px' height='13px' content-width='scale-to-fit' content-height='scale-to-fit' />
  5. </fo:marker>


 
 
exemple pour la dernière page :

Code :
  1. <fo:marker marker-class-name='index'>.j</fo:marker>
  2. <fo:marker marker-class-name='nextIndex'></fo:marker>
  3. <fo:marker marker-class-name='next'></fo:marker>


 
fop s'occupe de récupérer les données et les afficher correctement, pour chaque page. Il y a peut être un moyen plus propre de le faire, mais je n'ai pas trouvé autre chose, et ça me semblait assez adéquat pour résoudre mon problème.
 
 
Quant à ton exemple, voici le code que j'ai utilisé de mon côté (j'ai 2 versions différentes, une version papier et une version online, cette seconde n'ayant pas de différences entre les pages recto et verso :
 
 

Code :
  1. <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format' xmlns:svg='http://www.w3.org/2000/svg'>
  2. <fo:layout-master-set>
  3.  <!--
  4.   page-master for recto pages, with specific top/bottom margin
  5.  -->
  6.  <fo:simple-page-master master-name='recto'
  7.    page-height='792px' page-width='1120px'
  8.    margin-top='138px' margin-bottom='98px' margin-left='161px' margin-right='164px'>
  9.   <fo:region-body margin-top='180px' margin-left='376px' margin-right='37px' margin-bottom='145px' />
  10.   <fo:region-before precedence='true' extent='3cm' />
  11.  </fo:simple-page-master>
  12.  <!--
  13.   page-master for verso pages, with specific top/bottom margin
  14.  -->
  15.  <fo:simple-page-master master-name='verso'
  16.    page-height='792px' page-width='1120px'
  17.    margin-top='20px' margin-bottom='216216px' margin-left='161px' margin-right='164px'>
  18.   <fo:region-body margin-top='180px' margin-left='376px' margin-right='37px' margin-bottom='145px' />
  19.   <fo:region-before precedence='true' extent='3cm' />
  20.  </fo:simple-page-master>
  21.  <!--
  22.   page sequence for paper catalog, with alternate top/bottom margin
  23.   WARNING :  switch recto/verso position of the article page,
  24.      change odd/even value dynamically on generation
  25.  -->
  26.  <fo:page-sequence-master master-name='papier'>
  27.   <fo:repeatable-page-master-alternatives>
  28.    <fo:conditional-page-master-reference master-reference='recto' odd-or-even='odd' />
  29.    <fo:conditional-page-master-reference master-reference='verso' odd-or-even='even' />
  30.   </fo:repeatable-page-master-alternatives>
  31.  </fo:page-sequence-master>
  32.  <!--
  33.   page sequence for online catalog, with same margin used for each page
  34.  -->
  35.  <fo:page-sequence-master master-name='online'>
  36.   <fo:repeatable-page-master-reference master-reference='recto' />
  37.  </fo:page-sequence-master>
  38. </fo:layout-master-set>
  39. <fo:page-sequence master-reference='online' initial-page-number='1'>
  40.  <!--
  41.   declaration of all static elements displayed on each page if multi-paging is required
  42.   contains all visual blocks, excluded the central articles table
  43.  -->
  44.  <fo:static-content flow-name='xsl-region-before'>
  45.   <!--
  46.    here the static content displayed on all pages
  47.    ie : header, logo, footer (better to use "xsl-region-after" static-content tag for footer)
  48.   -->
  49.  </fo:static-content>
  50.  <fo:flow flow-name='xsl-region-body'>
  51.   <!--
  52.    here the dynamic content, use the "break-after='page'" property of block-container
  53.    to pass to next page after the block-container
  54.   -->
  55.  </fo:flow>
  56. </fo:page-sequence>
  57. </fo:root>


 
Ensuite, selon que je dois générer le catalogue papier ou le catalogue online, je passe en tant que master-reference le masterName "papier" ou "online" dans la balise fo:page-sequence et le tour est joué.  
Je dois encore alterner la valeur odd/even dans les conditions du page-sequence-master "papier", selon que mon article débute sur une page recto ou verso, mais ça c'est un autre problème qui est déjà implémenté dans mon système de génération ;-)
 
Vala, si ça peut aider quelqu'un tant mieux.
 
 
A+

Reply

Sujets relatifs:

Leave a Replay

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