我的xml如下:
<valid_path>
<document var_name="some_value">
<processControls>
<p>Lots of good text here ...</p>
<ul class="unIndentedList">
<li> Graphical display of system</li>
<li> Other bulleted items ...</li>
</ul>
<p>etc. etc. etc.</p>
</processControls>
</document>
</valid_path>
我的输入由此确定:
<xsl:variable name="processControlsValue" select="/valid_path/document[@var_name='some_value']/processControls" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"/>
我正在调用一个递归模板来替换某些输入中找到的给定字符串。电话如下。
<xsl:call-template name="bulRep">
<xsl:with-param name="text" select="$processControlsValue"/>
<xsl:with-param name="replace" select="'Graphical'"/>
<xsl:with-param name="by" select="'foofoobars'"/>
</xsl:call-template>
这是模板。
<xsl:template name="bulRep">
<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"/>
<xsl:call-template name="bulRep">
<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:apply-templates select="$text" />-->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
如果找到文本,模板就可以替换文本。 (例如'Graphical'确实被'foofoobars'取代)我遇到的问题是丢失格式的OR-copy-of。我意识到值将返回文本,而不是文本和格式,我发现许多帖子指示其他人使用副本来保留格式。但是,这不起作用。输出只是一个连续的文本行。
现在,如果我使用apply-templates行(当前已注释掉)而不是行值,我确保我正在点击模板的“其他”部分,我得到了所需的输出。我会得到段落,项目符号列表等。但是使用value-of或copy-of只能获取文本,如果有字符串匹配,则使用apply-templates会中断。
我的最终结果是使用xsl-fo。
的PDF我现在看到的是什么:
这里有很多好文... foofoobars显示系统其他项目符号......等等。
我想看到的内容:
这里有很多好文...
•foofoobars显示系统
•其他项目符号......
等。等等。
答案 0 :(得分:1)
问题在于,如果您使用的查找和替换模板仅用于处理作为参数传入的文本。如果要传入节点列表,那么当你来执行像“contains”这样的字符串函数时,它只会使用第一个节点的文本。或者,如果传入包含多个后代的单个元素,则将字符串值作为所有后代文本节点的串联。
我认为您可能需要做的是,在这里使用身份转换,这可能是您在提及 xsl:apply-templates 时已经在做的事情,但是有一个单独的用于匹配文本节点的模板,然后您可以在其中调用查找和替换模板
<xsl:template ....>
<xsl:variable name="processControlsValue"
select="/valid_path/document[@var_name='some_value']/processControls" />
<xsl:apply-templates select="$processControlsValue" mode="replace">
<xsl:with-param name="replace" select="'Graphical'"/>
<xsl:with-param name="by" select="'foofoobars'"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@*|node()[not(self::text())]" mode="replace">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="replace">
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="replace">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:call-template name="bulRep">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:template>
注意,我使用了mode="replace"
来防止您可能遇到的模板发生冲突。如果没有这种冲突,可能会删除该模式。
因此,这个想法在这两个模板中,它复制任何现有的元素和属性,但是当它找到一个文本节点时,它只对文本进行查找和替换。
顺便说一句,如果你使用的是XSLT 2.0,你可以使用替换函数代替你的命名模板
<xsl:template match="text()" mode="replace">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:value-of select="replace(., $replace, $by)" />
</xsl:template>
编辑:作为一个完整的工作示例,请尝试此XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="processControlsValue" select="/valid_path/document[@var_name='some_value']/processControls"/>
<xsl:apply-templates select="$processControlsValue" mode="replace">
<xsl:with-param name="replace" select="'Graphical'"/>
<xsl:with-param name="by" select="'foofoobars'"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@*|node()[not(self::text())]" mode="replace">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="replace">
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="replace">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:call-template name="bulRep">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="bulRep">
<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"/>
<xsl:call-template name="bulRep">
<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:apply-templates select="$text" />-->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
当应用于您的示例XML时,将输出以下内容。可以看出,“图形”一词已被文中的“foofoobars”所取代。
<processControls>
<p>Lots of good text here ...</p>
<ul class="unIndentedList">
<li> foofoobars display of system</li>
<li> Other bulleted items ...</li>
</ul>
<p>etc. etc. etc.</p>
</processControls>