2012-09-10 101 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>