Frage

Ich führe eine Suche und Ersetzung für das Zeilenvorschubzeichen durch (
) und ersetzen Sie es mit den Tags „Absatz schließen“ und „Absatz öffnen“ mithilfe des folgenden Codes:

<xsl:template match="/STORIES/STORY">   
    <component>
        <xsl:if test="boolean(ARTICLEBODY)">
            <p>
                <xsl:call-template name="replace-text">
                        <xsl:with-param name="text" select="ARTICLEBODY"  />
                        <xsl:with-param name="replace" select="'&#10;'" />
                        <xsl:with-param name="by" select="'&lt;/p&gt;&lt;p&gt;'" />
                </xsl:call-template>
            </p>
        </xsl:if>
    </component>
</xsl:template>

<xsl:template name="replace-text">
   <xsl:param name="text"/>
   <xsl:param name="replace" />
   <xsl:param name="by"  />

   <xsl:choose>
   <xsl:when test="contains($text, $replace)">
      <xsl:value-of select="substring-before($text, $replace)"/>
      <xsl:value-of select="$by" disable-output-escaping="yes"/>
      <xsl:call-template name="replace-text">
         <xsl:with-param name="text" select="substring-after($text, $replace)"/>
         <xsl:with-param name="replace" select="$replace" />
         <xsl:with-param name="by" select="$by" />
      </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
      <xsl:value-of select="$text"/>
   </xsl:otherwise>
   </xsl:choose>
</xsl:template>

Das funktioniert fast perfekt, außer dass ich es wirklich brauche, um die Zeilenumbrüche zu deduplizieren, da die Absätze dazu neigen, durch 2 oder mehr getrennt zu sein, was dazu führt </p><p></p><p>.

Ist es möglich, es so zu gestalten, dass dies immer nur einmal pro Absatz ersetzt wird?

War es hilfreich?

Lösung

disable-output-escaping ist an sich nicht böse, aber es gibt nur wenige Fälle, in denen Sie es verwenden sollten, und dies ist keiner davon.In XSLT arbeiten Sie mit Bäumen, nicht mit Markup-Strings.Hier ist eine XSTL 1.0-Lösung:

<xsl:template match="/STORIES/STORY">
  <component>
    <xsl:if test="ARTICLEBODY">
      <xsl:call-template name="wrap-text">
        <xsl:with-param name="text" select="ARTICLEBODY"/>
        <xsl:with-param name="delimiter" select="'&#10;'"/>
        <xsl:with-param name="element" select="'p'"/>
      </xsl:call-template>
    </xsl:if>
  </component>
</xsl:template>

<xsl:template name="wrap-text">
  <xsl:param name="text"/>
  <xsl:param name="delimiter"/>
  <xsl:param name="element"/>

  <xsl:choose>
    <xsl:when test="contains($text, $delimiter)">
      <xsl:variable name="t" select="substring-before($text, $delimiter)"/>
      <xsl:if test="normalize-space($t)">
        <xsl:element name="{$element}">
        <xsl:value-of select="$t"/>  
      </xsl:element>
      </xsl:if>        
      <xsl:call-template name="wrap-text">
        <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
        <xsl:with-param name="delimiter" select="$delimiter"/>
        <xsl:with-param name="element" select="$element"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="normalize-space($text)">
        <xsl:element name="{$element}">
          <xsl:value-of select="$text"/>  
        </xsl:element>
      </xsl:if>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Andere Tipps

Versuchen Sie Folgendes (XSLT 2.0):

    <xsl:template match="/STORIES/STORY">
        <component>
            <xsl:if test="boolean(ARTICLEBODY)">
                <xsl:call-template name="insert_paras">
                    <xsl:with-param name="text" select="ARTICLEBODY/text()"/>
                </xsl:call-template>
            </xsl:if>
        </component>
    </xsl:template>

    <xsl:template name="insert_paras">
        <xsl:param name="text" />

        <xsl:variable name="regex">
            <xsl:text>&#10;(&#10;|\s)*</xsl:text>
        </xsl:variable>
        <xsl:variable name="tokenized-text" select="tokenize($text, $regex)"/>

        <xsl:for-each select="$tokenized-text">
            <p>
                <xsl:value-of select="."/>
            </p>
        </xsl:for-each>
    </xsl:template>

Im Allgemeinen ist es keine gute Idee, Literalzeichenfolgen zum Einfügen in XML-Markup zu verwenden, da Sie nicht garantieren können, dass die Ergebnisse ausgewogen sind.

Angesichts der von Ihnen aufgerufenen XPath-Funktionen, von denen ich mich nicht erinnern kann, dass ich sie in meiner MSXSL-Arbeit in Anspruch genommen habe, sieht es so aus, als würden Sie einen XPath 2-kompatiblen Prozessor verwenden.

Wenn das der Fall ist, verfügt XPath 2 dann nicht über eine Funktion zum Ersetzen (Zeichenfolge, Muster, Ersatz), die einen regulären Ausdruck als zweiten Parameter akzeptiert?

<xsl:value-of 
    select="replace(string(.), '&#10;(\s|&#10;)*', '&lt;/p&gt;&lt;p&gt;')" />

Es könnte hilfreich sein, einige Beispiel-XML-Eingaben zu haben und zu wissen, welchen Prozessor Sie verwenden möchten.

Aus Ihrem ursprünglichen Beispiel geht hervor, dass die doppelten Absätze alle ein Präfix haben, das nur Leerzeichen enthält.So etwas wie diese geringfügige Änderung könnte die Duplikate kürzen.

<xsl:when test="contains($text, $replace)">
  <xsl:variable name="prefix" select="substring-before($text, $replace)" />
  <xsl:choose>
    <xsl:when test="normalize-string($prefix)!=''">
      <xsl:value-of select="$prefix"/>
      <xsl:value-of select="$by" disable-output-escaping="yes"/>
    </xsl:when>
  </xsl:choose>
  <xsl:call-template name="replace-text">
     <xsl:with-param name="text" select="substring-after($text, $replace)"/>
     <xsl:with-param name="replace" select="$replace" />
     <xsl:with-param name="by" select="$by" />
  </xsl:call-template>

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top