Find and replace with unique

I search and replace the line character ( 
 ) and replace it with paragraph and paragraph closing tags with the following code:

 <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> 

This works almost fine, except that I really need to nullify the lines, because paragraphs are usually divided into 2 or more, which leads to </p><p></p><p> .

Is it possible to get it so that it replaces it only once in a paragraph?

+4
source share
3 answers

disable-output-escaping not evil in itself, but there are only a few cases where you should use it, and this is not one of them. In XSLT, you work with trees, not markup. Here is the XSTL 1.0 solution:

 <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> 
+5
source

Given the XPath functions that you call that I don’t remember, having the luxury of MSXSL in my work, it looks like you are using an XPath 2-compatible processor.

If so, does XPath 2 have a replacement function (string, pattern, replacement) that takes a regular expression as the second parameter?

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

This can help get an Xml sample and find out which processor you plan to use.

From your initial example, it seems that all repeating paragraphs have only a prefix with a space. So, something like this small modification can clip crooks.

 <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> 

+1
source

Try this (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> 

It is usually a bad idea to use literal strings for XML markup, as you cannot guarantee balanced results.

+1
source

Source: https://habr.com/ru/post/1276459/


All Articles