我想用一个字符串替换字符串。 我发现,这是否但没有似乎工作的例子。 这是一个样本数据
<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>
下面是执行多个替换成一个字符串的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>
肖恩的解决方案producces不正确的替换 :
<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>
说明 :
身份规则的拷贝“原样”每节点的匹配对于其被选择用于executiom。
它是由一个单一的模板匹配任何的任何文本节点孩子重写LD
在更换必须完成的节点-元素。
这如果匹配的文本节点contais任何的模板检查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
。
与现有的代码的问题是,这条线
<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:更换() ,而不是XSLT 2.0的版本。
这假定code
属性值不包含像任何特殊字符.
, $
等,这将在正则表达式专门解释。
它还假定不超过一个代码将出现在任何LD /文()节点。
LarsH的解决方案是一个很好的一个。 尝试使用EXSLT是否支持它。 如果不支持,你的XSLT引擎是微软,那么这种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>
如果不是微软,你不能使用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>