我想用另一个字符串替换字符串。我发现了一个这样做的例子,但似乎没有用。这是一个示例数据
<Addy>
<Row>
<LD>Dwelling, 1</D>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD>Logde</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
我想以这种方式替换以下字符串。
Dwelling = FLAT
Lodge = SHOP
以下是我使用的代码。它只删除了LD元素中的所有值。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:lookup="lookup">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<lookup:data>
<LD code="Dwelling">FLAT</LD>
<LD code="Lodge">SHOP</LD>
</lookup:data>
<xsl:variable name="lookup" select="document('')/*/lookup:data"/>
<xsl:template match="LD/text()">
<xsl:value-of select="$lookup/LD[@code = current()]" />
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果应用于上面的输入数据,它会生成:
<Addy>
<Row>
<LD></LD>
<LN> East</LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
<Row>
<LD></LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
具有适当代码的预期结果应该产生
<Addy>
<Row>
<LD>FLAT,1</D>
<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>
答案 0 :(得分:2)
以下是用于对字符串执行多次替换的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>
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
元素的字符串值包含在当前匹配的文本节点中,那么我们必须进行替换。我们调用名为"multiReplace"
的模板,该模板在当前文本节点中执行所有替换。我们将此模板作为参数传递给当前文本节点和所有$vReps/rep
元素的节点集,其old
子元素的字符串值包含在当前文本节点中 - 这些都是要进行的替换
multiReplace
模板调用名为singleReplace
的模板进行第一次替换,并在名为$vRepResult
的变量中捕获结果。这包含使用$pText
的字符串值替换$pReps[1]/old
所有出现的$pReps[1]/new
的字符串值的结果。然后multiReplace
模板递归调用自身,其中替换的结果到目前为止作为$pText
参数传递,并且要从中排除第一个替换的替换的节点集 - 作为$pReps
参数。此递归的“停止条件”是$pReps
参数成为空节点集时。
singleReplace
模板执行它的名称 - 它在其$pText
参数中包含的字符串中替换任何等于$pOld
参数的子字符串,其中包含字符串pNew
参数。替换次数可能大于1,但所有替换次数均为单个替换规范==&gt;因此名称singleReplace
。当$pText
非空且仍包含$pOld
时,替换将以递归方式再次以停止条件完成。
答案 1 :(得分:0)
现有代码的问题在于此行
<xsl:value-of select="$lookup/LD[@code = current()]" />
如果有一个LD元素的文本等于上下文节点的全文,将只发出任何内容。因此,谓词需要使用contains()
而不是=
。
使用XSLT 2.0,您可以按如下方式更改此模板:
<xsl:template match="LD/text()">
<xsl:variable name="LD" select="$lookup/LD[contains(current(), @code)]" />
<xsl:value-of select="replace(., $LD/@code, $LD/text())" />
</xsl:template>
如果您不能使用XSLT 2.0,则可以使用EXSLT str:replace()而不是XSLT 2.0的版本。
这假定code
属性值不包含任何特殊字符,如.
,$
等,这些特殊字符将在正则表达式中进行特殊解释。
它还假设在任何LD / text()节点中不会出现多于一个代码。
答案 2 :(得分:0)
LarsH的解决方案很好。如果支持,请尝试使用EXSLT。如果不支持并且您的XSLT引擎是Microsoft,那么这个XSLT 1.0样式表......
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:l="http://stackoverflow.com/questions/12360735"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="xsl l msxsl" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="lookup">
<l:map pattern="Dwelling" replacement="FLAT" />
<l:map pattern="Lodge" replacement="SHOP" />
</xsl:variable>
<xsl:template match="LD/text()">
<xsl:choose>
<xsl:when test="contains(.,msxsl:node-set($lookup)/l:map/@pattern)">
<xsl:variable name="hay-stack" select="." />
<xsl:for-each select="(msxsl:node-set($lookup)/l:map[contains($hay-stack,@pattern)])[1]">
<xsl:value-of select="concat(
substring-before($hay-stack,@pattern),
@replacement,
substring-after($hay-stack,@pattern))" />
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
...当应用于此输入时......
<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>Lodge</LD>
<LN>North </LN>
<L>1</L>
<Tf>Abesinia Passage</Tf>
</Row>
</Addy>
如果不是Microsoft,并且您无法使用EXSLT,请使用此样式表...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:l="http://stackoverflow.com/questions/12360735"
exclude-result-prefixes="xsl l" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="lookup">
<l:map pattern="Dwelling" replacement="FLAT" />
<l:map pattern="Lodge" replacement="SHOP" />
</xsl:variable>
<xsl:template match="LD/text()">
<xsl:choose>
<xsl:when test="contains(.,document('')/*/xsl:variable[@name="lookup"]/l:map/@pattern)">
<xsl:variable name="hay-stack" select="." />
<xsl:for-each select="(document('')/*/xsl:variable[@name="lookup"]/l:map[contains($hay-stack,@pattern)])[1]">
<xsl:value-of select="concat(
substring-before($hay-stack,@pattern),
@replacement,
substring-after($hay-stack,@pattern))" />
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>