Announcement

Collapse
No announcement yet.

xsl:for-each-group und WordML

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • xsl:for-each-group und WordML

    Hallo liebe Gemeinde,

    wie der Titel schon verrät, geht es hier um das Gruppieren von Elementen.
    Ausgangssituation ist, das ich einen Absatz aus WordML in eine tiefer verschachtelte Struktur bringen möchte.

    Der Codeschnipsel der XML-Datei sieht folgendermaßen aus:

    Code:
    		<w:p>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    				</w:rPr>
    				<w:t>Hier </w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    				</w:rPr>
    				<w:t>ein</w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:i/>
    				</w:rPr>
    				<w:t> längerer</w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    				</w:rPr>
    				<w:t> Text: </w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:u w:val="single"/>
    				</w:rPr>
    				<w:t>e</w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:u w:val="single"/>
    				</w:rPr>
    				<w:t>i</w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:u w:val="single"/>
    				</w:rPr>
    				<w:t>nmal fett</w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    				</w:rPr>
    				<w:t>, </w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:i/>
    				</w:rPr>
    				<w:t>fett u</w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:i/>
    				</w:rPr>
    				<w:t>nd kursiv, </w:t>
    			</w:r>
    			<w:r>
    				<w:rPr>
    					<w:b/>
    					<w:i/>
    					<w:vertAlign w:val="superscript"/>
    				</w:rPr>
    				<w:t>k</w:t>
    			</w:r>
    			<w:r w:rsidRPr="00BB3F80">
    				<w:rPr>
    					<w:b/>
    					<w:i/>
    					<w:vertAlign w:val="superscript"/>
    				</w:rPr>
    				<w:t>ursiv und hochgestellt</w:t>
    			</w:r>
    		</w:p>
    Zu Erläuterung des Codes:
    In WordML ist jeder Absatz ein <w>-Element, danach folgt ein <w:r> (Text-Run) und dann der eigentliche Text <w:t>. Das Element <w:r> kann Eigenschaften in Form des Elementen <w:rPr> enthalten, hier z.B: <w:b/> = fett, <w:i/> = kursiv usw.

    Mit meinem XSLT-Skript:

    Code:
    <xsl:template match="w:p[exists(w:pPr)]">
    	<p>
    		<!-- Bedingung: Bold -->
    		<xsl:for-each-group select=".//w:r" group-adjacent="exists(*/w:b)">
    			<xsl:choose>
    				<!-- Bold ja -->
    				<xsl:when test="current-grouping-key()">
    					<b>
    					<xsl:for-each-group select="current-group()" group-adjacent="exists(*/w:i)">
    					<xsl:choose>
    						<xsl:when test="current-grouping-key()">
    							<i>
    								<xsl:apply-templates select="current-group()"/>
    										
    								</i>
    						</xsl:when>
    						<xsl:otherwise>
    							<xsl:apply-templates/>
    						</xsl:otherwise>
    					</xsl:choose>
    				</xsl:for-each-group>
    			</b>
    
    </xsl:when></xsl:choose></xsl:for-each-group></p></xsl:template>
    gruppiere ich zuerst alle Elemente <w:r>, wenn die Eigenschaft <w:b> (fett) vorhanden ist. Wenn dies der Fall ist dann überprüfe ich in der aktuellen Gruppe, ob w:i/> (kursiv vorhanden ist).

    Nach meinen Ausführungen nun das eigentliche "Problem":

    Ich möchte gern diese Abfragen in eine / oder mehrere called-Templates / Funktioen auslagern, leider weiss ich nicht so recht wie ich es anstellen soll.
    Der ober gezeigte Ausschnitt kann recht mächtig werden.
    z.B. wenn kein <w:b/> vorkommt, dann muss im otherwise-Block nach <w:i/> gesucht werden, in diesem Block wieder nach Unterstrichen (<w:u/>).
    Es können unzählige Möglichkeiten vorkommen, welche abzufangen sind:

    Fett, Kursiv und unterstrichen dann wieder nur Unterstrichen und Kursiv, dann nur kursiv usw. Das wir ein sehr großes <xsl:for-each-group-Konstrukt.

    Ich hoffe ihr könnt mir einen Denkanstoß geben.

    Viele Grüße, Z-MAN

  • #2
    Als Denkansatz: Verwende ein Identitätstemplate und weitere Templates für die individuellen Anpassungen bestimmter Elemente mit Bedingungen.

    Comment


    • #3
      Hallo Thomas,

      danke für deinen Denkansatz.

      Sollte man hier komplett auf die for-each-group-Variante verzichten?
      Wenn man mehrere Templates erstellt kann man ja nur mit following/preceding-sibling arbeiten und treffende Elemente zu greifen. Sehe ich das richtig?

      Ein Lösungsansatz wäre ja auch das schreiben der jewiligen schleißenden und öffnenten Elemente mit <xsl:text>, was, zugegeben, nicht die schönste Variante ist.

      Comment


      • #4
        Soll aus dem WordML HTML werden (ich sehe da Elemente wie b und i)? Dann bringt eine Identitätstransformation natürlich nichts. Poste am besten mal ein minimales Vorher-/Nachher-Beispiel.

        Comment


        • #5
          Also hier das WordML-Dokument (vereinfacht ohne den w:-Namespace)

          Code:
          <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <document>
          <p>
          	<r>
          		<t>Einmal </t>
          	</r>
          	<r>
          		<rPr>
          			<b/>
          		</rPr>
          		<t>fett</t>
          	</r>
          	<r>
          		<t>, </t>
          	</r>
          	<r>
          		<rPr>
          			<i/>
          		</rPr>
          		<t>kursiv</t>
          	</r>
          	<r>
          		<t>, </t>
          	</r>
          	<r>
          		<rPr>
          			<b/>
          			<i/>
          		</rPr>
          		<t>fett und kursiv</t>
          	</r>
          	<r>
          		<t>, nur </t>
          	</r>
          	<r>
          		<rPr>
          			<u val="single"/>
          		</rPr>
          		<t>unterstrichen</t>
          	</r>
          	<r>
          		<t>.</t>
          	</r>
          </p>
          </document>

          Das ergebnis soll folgendes sein:

          Code:
          <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <document>
           <p>Einmal <b>fett</b>, <b><i>fett und kursiv</i></b>, nur <u>unterstrichen</u>.</p>
          </document>
          Wie ich es bisher realisiere sieht man in meinem ersten Post zu diesem Thema.

          Comment


          • #6
            Ich verstehe die leeren Elemente nicht, was soll da transformiert werden? Gib einen echten WordML-Schnipsel an und das gesuchte Ergebnis.

            Comment


            • #7
              Eventuell reicht
              Code:
              <xsl:stylesheet
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">
                
                <xsl:strip-space elements="*"/>
                <xsl:output method="html" indent="yes"/>
                
                <xsl:template match="document | p">
                  <xsl:copy>
                    <xsl:apply-templates select="@*, node()"/>
                  </xsl:copy>
                </xsl:template>
                
                <xsl:template match="p/r[rPr/*]">
                  <xsl:apply-templates select="rPr/*[1]"/>
                </xsl:template>
                
                <xsl:template match="p/r[not(rPr/*)]">
                  <xsl:apply-templates select="t"/>
                </xsl:template>
                
                <xsl:template match="r/rPr/*">
                  <xsl:copy>
                    <xsl:variable name="fs" select="following-sibling::*[1]"/>
                    <xsl:choose>
                      <xsl:when test="$fs">
                        <xsl:apply-templates select="$fs"/>
                      </xsl:when>
                      <xsl:otherwise>
                        <xsl:value-of select="parent::rPr/parent::r/t"/>
                      </xsl:otherwise>
                    </xsl:choose>
                  </xsl:copy>
                </xsl:template>
                
              </xsl:stylesheet>

              Comment


              • #8
                Hallo Thomas,

                hier noch einmal ein "echtes Word-ML":

                Code:
                <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                <?mso-application progid="Word.Document"?>
                <w:wordDocument xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
                xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
                xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml"
                xmlns:w10="urn:schemas-microsoft-com:office:word"
                xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml"
                xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint"
                xmlns:wsp="http://schemas.microsoft.com/office/word/2003/wordml/sp2"
                xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core" w:macrosPresent="no"
                w:embeddedObjPresent="no" w:ocxPresent="no">
                <w:ignoreSubtree w:val="http://schemas.microsoft.com/office/word/2003/wordml/sp2"/>
                <w:body>
                <w:p>
                <w:r>
                <w:t>Einmal </w:t>
                </w:r>
                <w:r>
                <w:rPr>
                <w:b/>
                </w:rPr>
                <w:t>fett</w:t>
                </w:r>
                <w:r>
                <w:t>, </w:t>
                </w:r>
                <w:r>
                <w:rPr>
                <w:b/>
                <w:i/>
                </w:rPr>
                <w:t>kursiv und fett</w:t>
                </w:r>
                <w:r>
                <w:t> und nur </w:t>
                </w:r>
                <w:r>
                <w:rPr>
                <w:u w:val="single"/>
                </w:rPr>
                <w:t>unterstrichen</w:t>
                </w:r>
                <w:r>
                <w:t>.</w:t>
                </w:r>
                </w:p>
                </w:body>
                </w:wordDocument>
                ... welches aber genau das selbe ist wie zuvor, jetzt eben nur mit den ganzen Namespaces.

                Comment


                • #9
                  Guten Morgen,

                  (leider kam ich gestern nicht dazu zu antworten)

                  an Martin: das ist genau das Ergebnis welches ich haben wollte, vielen Dank.

                  Comment


                  • #10
                    So die Eingabelemente im WordML-Namensraum sind und die Ausgabelemente in keinem Namensraum sein sollen, willst du vermutlich noch
                    Code:
                    <xsl:copy>...</xsl:copy>
                    im Template 'match="r/rPr/*"' durch
                    Code:
                    <xsl:element name="{local-name()}">...</xsl:element>
                    ersetzen.

                    Comment

                    Working...
                    X