我试图使用XSLT 2.0来替换任意数量的子串。让我们说我的XML看起来像这样:
<scheme_template id="job"
use_when_ref="action">
<![CDATA[
<p>
@job.fluff@ Haul is based on
<b>@job.stat@:</b>
</p>
<table class="scheme_job_table">
<tr>
<td>2 or less</td>
<td>@job.low@</td>
</tr>
<tr>
<td>3-5</td>
<td>@job.middle@</td>
</tr>
<tr>
<td>6 or more</td>
<td>@job.high@</td>
</tr>
</table>
]]>
</scheme_template>
<scheme name="JOB! CHICKEN SOUP FOR THE SOULLESS"
copies="1">
<use_scheme_template id_ref="job">
<property id="job.fluff">
Chose 1 of your monsters to make and sell
heart-warming books of life-affirming awwwww.
</property>
<property id="job.stat">Smart</property>
<property id="job.low">$4</property>
<property id="job.middle">$6</property>
<property id="job.high">$8</property>
</use_scheme_template>
</scheme>
我想使用XSL转换来放置所有&#34;属性&#34;值进入方案模板。我的(有缺陷的)XSL看起来像这样:
<xsl:template match="use_scheme_template" mode="expand_template">
<xsl:param name="template_id" select="@id_ref"/>
<xsl:param name="base_text" select="//scheme_template[@id=$template_id]"/>
<xsl:variable name="expanded_text">
<xsl:apply-templates select="property" mode="replace_props">
<xsl:with-param name="base_text" select="$base_text"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:value-of select="$expanded_text" disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="property" mode="replace_props">
<xsl:param name="base_text"/>
<xsl:value-of select="replace($base_text, concat('@', @id, '@'), text())"/>
</xsl:template>
但这只取代了第一个属性。
在同一个字符串上运行replace
任意次数需要做什么?
答案 0 :(得分:2)
我会考虑使用xsl:analyze-string
代替replace
来解决这个问题。以下内容将在文本中搜索@anything@
子字符串,并用匹配的属性值替换它们(如果存在这样的属性),保留文本的其余部分不变:
<xsl:template match="use_scheme_template" mode="expand_template">
<xsl:param name="template_id" select="@id_ref"/>
<xsl:param name="base_text" select="//scheme_template[@id=$template_id]"/>
<xsl:variable name="properties" select="property" />
<xsl:variable name="expanded_text">
<xsl:analyze-string select="$base_text" regex="@(.*?)@">
<xsl:matching-substring>
<!-- substitute the matching property value, if there is one,
or leave untouched if not -->
<xsl:value-of select="($properties[@id = regex-group(1)], .)[1]" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<!-- leave non-matching parts unchanged -->
<xsl:value-of select="." />
<xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:value-of select="$expanded_text" disable-output-escaping="yes" />
</xsl:template>
答案 1 :(得分:1)
不要将 replace_props 模板初始应用于所有属性,而应考虑将其应用于第一个属性:
<xsl:apply-templates select="property[1]" mode="replace_props">
<xsl:with-param name="base_text" select="$base_text"/>
</xsl:apply-templates>
然后,递归实际的 replace_props 模板。然后逻辑是创建一个带有当前替换文本的变量。然后,您将检查是否有以下属性元素可用。如果是这样,使用新替换的文本递归调用模板,否则输出文本:
试试这个......
<xsl:template match="property" mode="replace_props">
<xsl:param name="base_text"/>
<xsl:variable name="expanded_text" select="replace($base_text, concat('@', @id, '@'), text())"/>
<xsl:choose>
<xsl:when test="following-sibling::property">
<xsl:apply-templates select="following-sibling::property[1]" mode="replace_props">
<xsl:with-param name="base_text" select="$expanded_text"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$expanded_text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
...但是当你运行它时,你可能会发现“job.low”,“job.middle”和“job.high”值都是空的。这是因为$
符号在替换函数中具有特殊含义(替换的第二个参数可以使用正则表达式,第二个参数中的$
可以用于输出匹配模式的值)
这意味着您需要做一些额外的工作来逃避$
符号。请尝试使用此模板
<xsl:template match="property" mode="replace_props">
<xsl:param name="base_text"/>
<xsl:variable name="text" select="replace(text(), '\$', '\\\$')" />
<xsl:variable name="expanded_text" select="replace($base_text, concat('@', @id, '@'), $text)"/>
<xsl:choose>
<xsl:when test="following-sibling::property">
<xsl:apply-templates select="following-sibling::property[1]" mode="replace_props">
<xsl:with-param name="base_text" select="$expanded_text"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$expanded_text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>