查找并替换为唯一
时间:2020-03-05 18:44:09 来源:igfitidea点击:
我正在执行查找并替换换行符(`
),并使用以下代码将其替换为段落关闭和段落打开标签:
<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>
这几乎可以完美地工作,只是我真的需要它来消除换行符,因为段落之间往往被2或者更多分隔,从而导致</ p> <p> </ p> <p>
。
是否有可能获得它,使其每段只能替换一次?
解决方案
回答
鉴于我们正在调用的XPath函数,我记得在我的MSXSL工作中没有这么奢侈的功能,看起来我们正在使用兼容XPath 2的处理器。
如果是这样,XPath 2是否不具有将正则表达式作为第二个参数的replace(字符串,模式,替换)函数?
<xsl:value-of select="replace(string(.), ' (\s| )*', '</p><p>')" />
拥有一些Xml示例输入并了解我们打算使用哪种处理器可能会有所帮助。
从原始示例来看,重复的段落似乎都只有一个空格前缀。因此,像这样的细微修改可能会减少骗子。
<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>
回答
试试这个(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>
使用文字字符串放入XML标记通常是一个坏主意,因为我们不能保证结果是平衡的。
回答
禁用输出转义本身并不是邪恶的,但是在少数情况下,我们应该使用它,但这不是其中一种。在XSLT中,我们使用树,而不是标记字符串。这是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>