以下は、文字列への複数の置換を実行するための 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 ドキュメントに適用した場合の 2 つのソリューションの結果を比較します。
<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>
Sean のソリューションでは、正しくない置換が生成されます。
<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
現在一致しているテキスト ノードに文字列値が含まれている要素が少なくとも 1 つある場合は、置換を行う必要があります。"multiReplace"
現在のテキスト ノードですべての置換を実行する名前のテンプレートを呼び出します。このテンプレートに、現在のテキスト ノードと、現在のテキスト ノードに含まれる子$vReps/rep
の文字列値を含むすべての要素のノードセットをパラメーターとして渡しold
ます。これらはすべて、置換を行うものです。
テンプレートは という名前のmultiReplace
テンプレートを呼び出しsingleReplace
て最初の置換を行い、結果を という名前の変数に取り込みます$vRepResult
。これには、出現する$pText
すべて$pReps[1]/old
の (の文字列値)を の文字列値で置き換えた結果が含まれます$pReps[1]/new
。次に、multiReplace
テンプレートは、これまでに渡された置換の結果を$pText
パラメーターとして使用して再帰的に自身を呼び出し、最初の置換が除外される置換のノードセットをパラメーターとして呼び出し$pReps
ます。この再帰の「停止条件」は、$pReps
パラメーターが空のノード セットになったときです。
singleReplace
テンプレートは、その名前が示すとおりに機能します。つまり、パラメーターに含まれる文字列内で、パラメーターに等しい部分文字列を、パラメーターに含まれる文字列に置き換え$pText
ます。置換の数は 1 つより多い場合がありますが、それらはすべて単一の置換仕様のためのものです ==> したがって、名前です。置換は、が空ではなく、まだ が含まれている場合に、停止条件を使用して再帰的に行われます。$pOld
pNew
singleReplace
$pText
$pOld