Cassiopea: Mehrfach-Strukturierung eines flachen Dokuments

Beitrag lesen

Hallo,

ich habe folgende Ausgangsstruktur:

  
<root>  
   <heading1>heading1</heading1>  
   <para>para 1</para>  
   <listelement first="yes">listelement 1</listelement>  
   <listelement>listelement 2</listelement>  
   <listelement last="yes">listelement 3</listelement>  
   <para>para 2</para>  
   <para>para 3</para>  
   <heading2>heading2-1</heading2>  
   <para>para 1-1</para>  
   <para>para 1-2</para>  
   <listelement_ol first="yes">listelement 1-1OL</listelement_ol>  
   <listelement_ol last="yes">listelement 1-2 OL</listelement_ol>  
   <para>para 1-3</para>  
   <para>para 1-4</para>  
   <heading2>heading2-2</heading2>  
   <para>para 2-1</para>  
   <listelement_ol first="yes">listelement 2-1 OL</listelement_ol>  
   <listelement_ol last="yes">listelement 2-2 OL</listelement_ol>  
   <para>para 2-2</para>  
    <listelement first="yes">listelement 2-1</listelement>  
    <listelement last="yes">listelement 2-2</listelement>  
    <para>para 1-1</para>  
    <para>para 1-2</para>  
</root  

Nun soll eine Strukturierung erfolgen.
1. Jede Datei hat nur ein Element heading1 - dass heißt die erste Strukturierung kann fix mittels LRE sect1 vorgenommen werden
2. Anschließend wird mittels xsl:for-each-group gruppiert und zwar nach allen heading2-Elementen
3. Weiterhin müssen alle Elemente listelement bzw. listelement_ol zu Listen gruppiert werden

Somit ergibt sich folgender Output:

  
<test>  
   <sect1>  
      <title>heading1</title>  
      <p>para 1</p>  
      <liste_ul>  
         <li>listelement 1</li>  
         <li>listelement 2</li>  
         <li>listelement 3</li>  
         <p>para 2</p>  
         <p>para 3</p>  
      </liste_ul>  
      <sect2>  
         <title2>heading2-1</title2>  
         <p>para 1-1</p>  
         <p>para 1-2</p>  
         <liste_ol>  
            <li>listelement 1-1OL</li>  
            <li>listelement 1-2 OL</li>  
         </liste_ol>  
         <p>para 1-3</p>  
         <p>para 1-4</p>  
      </sect2>  
      <sect2>  
         <title2>heading2-2</title2>  
         <p>para 2-1</p>  
         <liste_ol>  
            <li>listelement 2-1 OL</li>  
            <li>listelement 2-2 OL</li>  
         </liste_ol>  
         <p>para 2-2</p>  
         <li>listelement 2-1</li>  
         <li>listelement 2-2</li>  
         <p>para 1-1</p>  
         <p>para 1-2</p>  
      </sect2>  
   </sect1>  
</test>  

Die XSLT baut sich wiefolgt auf:

  
<xsl:template match="/">  
        <test>  
            <sect1>  
                <title>  
                    <xsl:value-of select="//heading1"/>  
                </title>  
                <xsl:call-template name="struktur"/>  
            </sect1>  
        </test>  
    </xsl:template>  
  
    <xsl:template name="struktur">  
        <xsl:for-each-group select="//para|//heading2|//listelement|//listelement_ol"  
            group-starting-with="heading2">  
            <xsl:choose>  
                <xsl:when test="current()[self::heading2]">  
                    <sect2>  
                        <xsl:call-template name="build_liste"/>  
                    </sect2>  
                </xsl:when>  
                <xsl:otherwise>  
                    <xsl:call-template name="build_liste"/>  
                </xsl:otherwise>  
            </xsl:choose>  
        </xsl:for-each-group>  
    </xsl:template>  
  
    <xsl:template name="build_liste">  
        <xsl:for-each-group select="current-group()" group-starting-with="listelement[@first]|listelement_ol[@first]">  
            <xsl:choose>  
                <xsl:when test="current()[self::listelement|self::listelement_ol]">  
                    <xsl:for-each-group select="current-group()" group-ending-with="listelement[@last]|listelement_ol[@last]">  
                        <xsl:choose>  
                            <xsl:when test="current()[self::listelement|self::listelement_ol]">  
                                <xsl:choose>  
                                    <xsl:when  test="current()[self::listelement]">  
                                        <liste_ul>  
                                            <xsl:apply-templates select="current-group()"/>  
                                        </liste_ul>  
                                    </xsl:when>  
                                    <xsl:when  test="current()[self::listelement_ol]">  
                                        <liste_ol>  
                                            <xsl:apply-templates select="current-group()"/>  
                                        </liste_ol>  
                                    </xsl:when>  
                                </xsl:choose>  
                            </xsl:when>  
                            <xsl:otherwise>  
                                <xsl:apply-templates select="current-group()"/>  
                            </xsl:otherwise>  
                        </xsl:choose>  
                    </xsl:for-each-group>  
                </xsl:when>  
                <xsl:otherwise>  
                    <xsl:apply-templates select="current-group()"/>  
                </xsl:otherwise>  
            </xsl:choose>  
        </xsl:for-each-group>  
    </xsl:template>  
  
  
    <xsl:template match="heading1">  
        <title>  
            <xsl:apply-templates/>  
        </title>  
    </xsl:template>  
  
    <xsl:template match="heading2">  
        <title2>  
            <xsl:apply-templates/>  
        </title2>  
    </xsl:template>  
  
    <xsl:template match="para">  
        <p>  
            <xsl:apply-templates/>  
        </p>  
    </xsl:template>  
  
    <xsl:template match="listelement">  
        <li>  
            <xsl:apply-templates/>  
        </li>  
    </xsl:template>  
  
    <xsl:template match="listelement_ol">  
        <li>  
            <xsl:apply-templates/>  
        </li>  
    </xsl:template>  

Innerhalb des Templates namens struktur wird zuerst eine Gruppierung nach sect2 gemacht - somit werden die Unterkapitel erzeugt.

Das Template build_liste wird nun genutzt, um Listen zu gruppieren bzw. zu strukturieren (da Listen auch als Kindelemente von heading1 vorkommen können, erfolgt auch an dieser Stelle ein Templateaufruf von build_liste).

Die erste Gruppierung funktioniert so, dass alle Listenelemente sowie die Knoten nach den Listenelementen gefiltert werden (d.h. alle Absätze vor den Listenelementen werden ausgeschlossen). Die zweite innere Gruppierung filtert nun alle Absätze para nach den Listen aus - so dass final nur die Listenelemente übrigbleiben, welche nun gruppiert werden (inklusive der Unterscheidung, ob eine geordnete oder ungeordnete Liste vorliegt).

Das ganze funktioniert soweit auch gut - da gibts nichts zu mekern. Meine Fragen sind daher:

1. Geht das nicht einfacher? Anstatt erst die Absätze vor und dann nach Listen auszuschließen - geht es nicht, dass man sagen kann: Alle Elemente namens listelement bzw. listelement_ol zusammenfassen/gruppieren? Leider hatte ich immer das Problem, dass ich die Knoten davor und danach (genauer die Absätze) mittels apply-templates oder current-group() nicht ausgeben konnte (Denn: es können ja auch mehrere Listen zwischen zwei heading2 Elementen vorkommen).

2. Ich habe für die Funktionen group-starting-with und group-ending-with jeweils händisch das Attribut @last und @first für listelement bzw. listelement_ol hinzugefügt - um die Gruppierung durchzuführen.
  Wie kann man nun den XPath formulieren ohne diese Attribute? Ich möchte ja immer das erste Listenelement auswählen, welches als DIREKTEN Vorgänger ein Absatz para hat bzw. für @last umgekehrt (jeweils der akutellen Gruppe). Aber die Formulierungen:
listelement[psoition()=1 and preceding-sibling::para] nützt hier irgendwie nicht viel.

Ich hoffe, jemand kann mir die Fragen bzw. eine der Fragen beantworten. Gerade das zweite Problem bringt mich ein wenig zur Verzweiflung.

Hoffentlich anwortet jemand - bitte *verzweifel*

Mfg Cassiopea