2012-09-10 109 views
3

我想用另一个字符串代替字符串。我发现了一个例子,但似乎没有工作。这是一个示例数据用xslt代替字符串

<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> 

回答

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> 

想要的,更新ECT结果产生:

<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> 

重要

该解决方案是完整和正确的。肖恩的表现很肤浅。

<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> 

目前,正确的解决办法

由两个解决方案,当下面的XML文档应用比较结果从这个答案,产生正确的替换:

<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> 

说明

  1. 身份规则 “原样” 每节点匹配它被选择用于executiom为其副本。

  2. 它由与任何LD元素的任何文本节点子元素匹配的单个模板覆盖 - 必须完成替换的节点。

  3. 该模板检查匹配的文本节点是否包含old(字符串值)中的任何一个,如全局内联my:reps元素中指定的那样。为方便起见,在全局变量$vReps中选择了所有my:reps/rep元素,并且引用此变量。如果这些字符串都不包含在当前节点中,则将其复制到输出中。

  4. 如果至少有一个$vReps/old元素的字符串值包含在当前匹配的文本节点中,那么我们必须进行替换。我们调用名称为"multiReplace"的模板,该模板执行当前文本节点中的所有替换。我们将这个模板作为参数传递给当前文本节点以及所有$vReps/rep元素的节点集,其中old子元素的字符串值包含在当前文本节点中 - 这些都是要进行的替换。

  5. multiReplace模板调用名为singleReplace的模板进行第一次替换并将结果捕获到名为$vRepResult的变量中。这包含在$pText全部替换(字符串值)$pReps[1]/old的字符串值为$pReps[1]/new的结果。然后,multiReplace模板以递归方式调用自身,以至于$pText参数迄今作为替换的结果以及排除第一个替换的替换节点集作为参数$pReps。此递归的“停止条件”是$pReps参数成为空节点集时。

  6. singleReplace模板做什么它的名字一样 - 它取代了其$pText参数包含等于$pOld参数与包含在pNew参数字符串任何字符串的的字符串中。替换次数可能会大于1次,但所有替换次数均为单个替换规格==>因此名称为singleReplace。当$pText非空且仍包含$pOld时,替换再次以递归方式进行,并带有停止条件。

0

与现有的代码的问题是,这条线

<xsl:value-of select="$lookup/LD[@code = current()]" /> 

只会在文本等于上下文节点的全文的LD元素时发出任何内容。所以谓词需要使用而不是=

使用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,您可以使用,而不是XSLT 2.0版的EXSLT str:replace()

这假定code属性值不包含任何特殊字符,如.$等,这些字符将在正则表达式中专门解释。

它还假定在任何LD/text()节点中不会出现多于一个的代码。

+0

@ LarsH不幸的是我正在使用XSLT 1.0。你可以在1.0中说明这一点吗? – lee

+0

@lee,如果你看看我链接到的页面,http://www.exslt.org/str/functions/replace/index.html,底部有一个链接,指向一个“str”的XSLT 1.0实现:替换'模板。第一页顶部附近是用于调用模板的示例代码。 – LarsH

+0

有没有另一种方法与1.0做到这一点? – lee

0

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>