Domanda
Sto eseguendo una ricerca e sostituzione sul carattere di avanzamento riga (
) e sostituendolo con i tag di chiusura paragrafo e di apertura paragrafo utilizzando il seguente codice:
<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="' '" />
<xsl:with-param name="by" select="'</p><p>'" />
</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>
Funziona quasi perfettamente, tranne per il fatto che ne ho davvero bisogno per deduplicare gli avanzamenti di riga poiché i paragrafi tendono ad essere separati da 2 o più, risultando in </p><p></p><p>
.
È possibile ottenerlo in modo che lo sostituisca solo una volta per paragrafo?
Soluzione
disable-output-escaping
non è malvagio in sé, ma ci sono solo pochi casi in cui dovresti usarlo e questo non è uno di questi.In XSLT lavori con alberi, non con stringhe di markup.Ecco una soluzione XSTL 1.0:
<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="' '"/>
<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>
Altri suggerimenti
Prova questo (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> ( |\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>
In genere è una cattiva idea utilizzare stringhe letterali per inserire markup XML, poiché non è possibile garantire che i risultati siano bilanciati.
Date le funzioni XPath che stai chiamando e di cui non ricordo di aver avuto il lusso nel mio lavoro su MSXSL, sembra che tu stia utilizzando un processore compatibile con XPath 2.
In tal caso, XPath 2 non ha una funzione di sostituzione (stringa, modello, sostituzione) che accetta una regex come secondo parametro?
<xsl:value-of
select="replace(string(.), ' (\s| )*', '</p><p>')" />
Potrebbe essere utile avere qualche input Xml di esempio e sapere quale processore intendi utilizzare.
Dal tuo esempio originale, sembra che i paragrafi duplicati abbiano tutti un prefisso di soli spazi bianchi.Quindi qualcosa come questa leggera modifica potrebbe eliminare gli imbroglioni.
<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>