joy: Text Absätze markieren

Hallo,

ich möchte gerne bei einem XML Text mithilfe eines XSL Stylesheets die Absätze mit <Text> Elementen umschließen, d.h.

Eingabe:
<?xml version="1.0"?>
<TextArea>
Titel

Das ist ein Text mit mehreren Abschnitten.

Hier kommt wieder ein Abschnitt, welcher auch noch einzelne
Zeilenumbrüche enthält, die ebenfalls erhalten bleiben
sollen.

Und zum Schluss noch ein Absatz.
</TextArea>

Ausgabe soll sein:
<?xml version="1.0"?>
<TextArea>
<Text>Titel
</Text>
<Text>
Das ist ein Text mit mehreren Abschnitten.
</Text>
<Text>
Hier kommt wieder ein Abschnitt, welcher auch noch einzelne
Zeilenumbrüche enthält, die ebenfalls erhalten bleiben
sollen.
</Text>
<Text>
Und zum Schluss noch ein Absatz.
</Text>
</TextArea>

Ich habe es schon versucht mit diesem XSL:
<xsl:template match="text()">
  <xsl:call-template name="cr2br">
 <xsl:with-param name="text" select="." />
  </xsl:call-template>
</xsl:template>

<xsl:template name="cr2br">
  <xsl:param name="text" />
  <xsl:variable name="textafterbreak" select="substring-after($text, '&#10;')" />
  xsl:choose
   <xsl:when test="contains($text, '&#10;')">
         <xsl:element name="text">
      <xsl:value-of select="substring-before($text, '&#10;')" />
         </xsl:element>
      <xsl:call-template name="cr2br">
         <xsl:with-param name="text" select="$textafterbreak" />
      </xsl:call-template>
    </xsl:when>
    xsl:otherwise
     <xsl:value-of select="$text" />
    </xsl:otherwise>
 </xsl:choose>
</xsl:template>

Das brachte aber nicht das gewünscht Ergebnis, da es bei jedem Zeilenumbruch die <Text> Elemente setze.
Und die Suche nach "substring-after($text, '&#10;&#10;') bzw. "substring-before($text, '&#10;&#10;')" hat mir gar keine Ergebnisse geliefert.

Kann mir bitte jemand von euch vielleicht helfen?

Gruß
Joy

  1. Hallo joy,

    XPath 2.0 bietet die Funktion "tokenize". Wenn Du einen XSLT-Prozessor verwendest, der das kann, würde ich das damit machen.

    Dann sollte wohl in der Art gehen:

      
    <xsl:foreach select="tokenize(/TextArea, '\n')">  
      <xsl:if test=".">  
        <text><xsl:value-of select="."/></text>  
      </xsl:if>  
    </xsl:foreach>  
    
    

    Oder vielleicht auch:

      
    <xsl:foreach select="tokenize(/TextArea, '\s*\n\s*')">  
      <xsl:value-of select="."/>  
    </xsl:foreach>  
    
    

    Leere abschnitte mit einem xsl:if zu ignorieren, sollte aber auch bei Deinem Hack mit dem rekursiven Template funktionieren.

    Grüße

    Daniel

    1. Hallo Daniel,

      danke für die schnelle Antwort. Leider verwende ich kein XPath 2.0 sondern ich nehme XPath 1.0. Dadurch kann ich die "tokenize" Funktion nicht anwenden. Gibt es vielleicht noch eine andere Möglichkeit?

      Gruß
      joy

      1. Hallo joy,

        Gibt es vielleicht noch eine andere Möglichkeit?

        Ich habe doch noch vorgeschlagen, leere Abschnitte einfach zu ignorieren:
        [code lang=xml]
        <xsl:template name="cr2br">
          <xsl:param name="text" />
          <xsl:variable name="textafterbreak" select="substring-after($text, '&#10;')" />
          xsl:choose
           <xsl:when test="contains($text, '&#10;')">
              <xsl:if test="substring-before($text, '&#10;')">
                <xsl:element name="text">
                  <xsl:value-of select="substring-before($text, '&#10;')" />
                </xsl:element>
              </xsl:if>
              <xsl:call-template name="cr2br">
                 <xsl:with-param name="text" select="$textafterbreak" />
              </xsl:call-template>
            </xsl:when>
            xsl:otherwise
             <xsl:value-of select="$text" />
            </xsl:otherwise>
         </xsl:choose>
        </xsl:template>
        [code]
        Funktioniert das nicht?

        Grüße

        Daniel

        1. Hallo Daniel,

          Gibt es vielleicht noch eine andere Möglichkeit?
          Ich habe doch noch vorgeschlagen, leere Abschnitte einfach zu ignorieren:
          [code lang=xml]
          <xsl:template name="cr2br">
            <xsl:param name="text" />
            <xsl:variable name="textafterbreak" select="substring-after($text, '&#10;')" />
            xsl:choose
             <xsl:when test="contains($text, '&#10;')">
                <xsl:if test="substring-before($text, '&#10;')">
                  <xsl:element name="text">
                    <xsl:value-of select="substring-before($text, '&#10;')" />
                  </xsl:element>
                </xsl:if>
                <xsl:call-template name="cr2br">
                   <xsl:with-param name="text" select="$textafterbreak" />
                </xsl:call-template>
              </xsl:when>
              xsl:otherwise
               <xsl:value-of select="$text" />
              </xsl:otherwise>
          </xsl:choose>
          </xsl:template>
          [code]
          Funktioniert das nicht?

          Das funktioniert leider nicht, das es mir um jeden Text der zwischen Zeilenumbrüchen liegt das <Text> Element setzt. Ich will aber das er das um einen ganzen Absatz macht (also Text der zwischen jeweils 2 Zeilenumbrüchen liegt), welcher an sich auch Zeilenumbrüche enthalten kann.

          Gruß
          joy

          1. Hallo,

            falls es noch nicht gelöst ist sollte nachfolgendes stylesheet deine Aufgabe lösen. Allerdings ist es wichtig zu wissen, wie das xml erstellt wurde, da keine schriftcodierung vorhanden ist, kann man nur raten. Du must also wissen wie die zeilenumbrüchen gesetzt werden, hier das sheet:

            <?xml version="1.0" encoding="UTF-8"?>
            <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
                <xsl:output method="xml" indent="yes"/>
                <xsl:template match="/">
                    xsl:apply-templates/
                </xsl:template>
                <xsl:template match="TextArea">
                    <TextArea>
                    <!-- tokenize trigger nicht nur '&#10;' sondern ' &#10;' -->
                        <xsl:for-each select="tokenize(text(),' &#10;')">
                            <xsl:if test="not(normalize-space(.) ='')">
                                <Text>
                                    <xsl:value-of select="normalize-space(.)"/>
                                </Text>
                            </xsl:if>
                        </xsl:for-each>
                    </TextArea>
                </xsl:template>
            </xsl:stylesheet>

            Ergibt bei mir:
            <?xml version="1.0" encoding="UTF-8"?>
            <TextArea>
               <Text>Titel</Text>
               <Text>Das ist ein Text mit mehreren Abschnitten.</Text>
               <Text>Hier kommt wieder ein Abschnitt, welcher auch noch einzelne Zeilenumbrüche enthält, die ebenfalls erhalten bleiben sollen.</Text>
               <Text>Und zum Schluss noch ein Absatz.</Text>
            </TextArea>