这是一个 XSLT 转换,用于对字符串执行多次替换——不需要扩展函数:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:reps>
<rep>
<old>Dwelling</old>
<new>FLAT</new>
</rep>
<rep>
<old>Lodge</old>
<new>SHOP</new>
</rep>
</my:reps>
<xsl:variable name="vReps" select="document('')/*/my:reps/*"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="LD/text()" name="replace">
<xsl:param name="pText" select="."/>
<xsl:choose>
<xsl:when test="not($vReps/old[contains($pText, .)])">
<xsl:value-of select="$pText"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="multiReplace">
<xsl:with-param name="pText" select="$pText"/>
<xsl:with-param name="pReps"
select="$vReps[contains($pText, old)]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="multiReplace">
<xsl:param name="pText"/>
<xsl:param name="pReps"/>
<xsl:choose>
<xsl:when test="$pReps">
<xsl:variable name="vRepResult">
<xsl:call-template name="singleReplace">
<xsl:with-param name="pText" select="$pText"/>
<xsl:with-param name="pOld" select="$pReps[1]/old"/>
<xsl:with-param name="pNew" select="$pReps[1]/new"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="multiReplace">
<xsl:with-param name="pText" select="$vRepResult"/>
<xsl:with-param name="pReps" select="$pReps[position() >1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pText"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="singleReplace">
<xsl:param name="pText"/>
<xsl:param name="pOld"/>
<xsl:param name="pNew"/>
<xsl:if test="$pText">
<xsl:choose>
<xsl:when test="not(contains($pText, $pOld))">
<xsl:value-of select="$pText"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($pText, $pOld)"/>
<xsl:value-of select="$pNew"/>
<xsl:call-template name="singleReplace">
<xsl:with-param name="pText" select="substring-after($pText, $pOld)"/>
<xsl:with-param name="pOld" select="$pOld"/>
<xsl:with-param name="pNew" select="$pNew"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<Addy>
<Row>
<LD>Dwelling, 1</LD>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD>Lodge</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
产生了想要的正确结果:
<Addy>
<Row>
<LD>FLAT, 1</LD>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD>SHOP</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
重要:
该解决方案是完整且正确的。肖恩的比较肤浅。
当应用于以下 XML 文档时,比较两种解决方案的结果:
<Addy>
<Row>
<LD>Dwelling, Lodge, 1</LD>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD>Lodge, Dwelling</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
肖恩的解决方案产生了不正确的替换:
<Addy>
<Row>
<LD>FLAT, Lodge, 1</LD>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD>Lodge, FLAT</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
此答案的当前正确解决方案会产生正确的替换:
<Addy>
<Row>
<LD>FLAT, SHOP, 1</LD>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD>SHOP, FLAT</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
说明:
身份规则“按原样”复制每个被选择执行的匹配节点。
它被一个匹配任何元素的任何文本节点子节点的单个模板覆盖LD
——必须在其中进行替换的节点。
此模板检查匹配的文本节点是否包含全局内联元素old
中指定的任何(字符串值) 。my:reps
为方便起见,所有my:reps/rep
元素都已在名为的全局变量中选择,$vReps
并从该变量中引用。如果当前节点中不包含这些字符串,则将其复制到输出。
如果当前匹配的文本节点中至少有一个$vReps/old
元素的字符串值包含,那么我们必须进行替换。我们调用一个带有名称的模板"multiReplace"
来执行当前文本节点中的所有替换。我们将当前文本节点和所有$vReps/rep
元素的节点集作为参数传递给该模板,其子节点的字符串值old
包含在当前文本节点中——这些都是要进行的替换。
multiReplace
模板调用名为的模板进行singleReplace
第一次替换,并将结果捕获到名为 的变量中$vRepResult
。这包含用 的字符串值替换$pText
所有出现的(的字符串值)$pReps[1]/old
的结果$pReps[1]/new
。然后,multiReplace
模板递归调用自身,并将到目前为止的替换结果作为$pText
参数传递,以及排除第一个替换的要进行的替换的节点集——作为$pReps
参数。此递归的“停止条件”是当$pReps
参数变为空节点集时。
模板按照singleReplace
它的名称执行 - 它用参数中包含的字符串替换其参数中包含的字符串中与$pText
参数相等的任何子字符串。替换的数量可能大于一个,但它们都是针对单个替换规范 ==> 因此名称。替换再次以递归方式完成,当非空且仍包含时,停止条件。$pOld
pNew
singleReplace
$pText
$pOld