2010-06-01 142 views
7

我需要一個XSL解決方案來用新節點替換XML節點。使用XSL替換具有新節點的XML節點

說我有以下現有的XML結構:

<root> 
    <criteria> 
     <criterion>AAA</criterion> 
    </criteria> 
</root> 

而且我想,以取代與一個標準的節點:

<criterion>BBB</criterion> 
<criterion>CCC</criterion> 
<criterion>DDD</criterion> 

,使最終XML的結果是:

<root> 
    <criteria> 
     <criterion>BBB</criterion> 
     <criterion>CCC</criterion> 
     <criterion>DDD</criterion> 
    </criteria> 
</root> 

我已經嘗試過使用substring-before和substring-after來複制結構的前半部分,然後ju st複製下半部分(爲了填充兩個半部分之間的新節點),但似乎子字符串函數只識別節點標記之間的文本,而不是像我希望的那樣標記本身。 :(:(

任何其他解決辦法?

+0

好問題(+1)。看到我的答案是一個正確和簡短的解決方案。請注意,目前接受的解決方案存在邏輯缺陷(它恰好適用於您的XML文檔,但通常會與其他XML文檔產生錯誤的結果)。 – 2010-06-01 21:59:18

回答

21

XSL不能代替任何,你能做的最好的就是要保留部分複製,再輸出要代替改變零件的零件你不想讓


例:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 

    <!-- This is an identity template - it copies everything 
     that doesn't match another template --> 
    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <!-- This is the "other template". It says to use your BBB-DDD elements 
     instead of the AAA element --> 
    <xsl:template match="criterion[.='AAA']"> 
    <xsl:element name="criterion"> 
     <xsl:text>BBB</xsl:text> 
    </xsl:element> 
    <xsl:element name="criterion"> 
     <xsl:text>CCC</xsl:text> 
    </xsl:element> 
    <xsl:element name="criterion"> 
     <xsl:text>DDD</xsl:text> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

模板匹配@* | node()匹配任何屬性或任何其他類型的節點。訣竅是模板匹配具有優先級。你可以認爲這條規則是「更具體的比賽勝利」。 任何東西將比「任何屬性或其他節點」更具體。這使得「身份」的匹配度非常低。

當它與匹配時,它只是複製它在匹配屬性或節點內找到的任何節點。

您擁有的任何其他模板將具有更高的優先級。無論它們匹配什麼,它都是更具體的模板中的代碼,它將會起作用。例如,如果您只是簡單地刪除了criterion[.='AAA']模板中的所有內容,則會發現您完全複製了輸入,除了「AAA」元素。

+0

@iheartgreek對John設置的模板進行了仔細研究。匹配XML元素的模板是有效使用XSLT的關鍵。 – 2010-06-01 19:33:57

+0

感謝您提供代碼示例..這正是我想要實現的! 雖然這個解決方案適用於我,但我也很想了解它。我用第二個模板(match =「criterion ['AAA']」)做了類似的事情,但我不知道(或意識到)要做的關鍵部分是複製與另一個模板不匹配的所有內容的模板。因此....你能解釋一下XPath match =「@ * | node()」是如何實現這個的?我是XPath和XSL的新手,所以我仍然不知道這些細節。 – developer 2010-06-01 19:48:59

+0

謝謝!現在我知道模板具有優先權了! :D – developer 2010-06-01 20:23:47

0

下更比一的方式對皮膚一貓的一般規律

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml"/> 
    <xsl:template match="/"> 
     <xsl:apply-templates /> 
    </xsl:template> 
    <!-- 
     when you capture a node with the text 'AAA' 
      emit the BBB, CCC, DDD nodes 
    --> 
    <xsl:template match="criterion[text() = 'AAA']"> 
     <xsl:element name="criterion"> 
      <xsl:text>BBB</xsl:text> 
     </xsl:element> 
     <xsl:element name="criterion"> 
      <xsl:text>CCC</xsl:text> 
     </xsl:element> 
     <xsl:element name="criterion"> 
      <xsl:text>DDD</xsl:text> 
     </xsl:element> 
    </xsl:template> 
    <!-- identity template --> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

您能否詳細說明這與我的解決方案有何不同? – 2010-06-01 19:36:07

+0

@John:沒有什麼不同,你對此有更多的解釋。我想我已經發布了它,然後/更新了......你只是打敗了我:-) – 2010-06-01 21:11:36

6

這是一個正確的解決方案,這可能是最短的之一:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="criterion[. = 'AAA']"> 
    <criterion>BBB</criterion> 
    <criterion>CCC</criterion> 
    <criterion>DDD</criterion> </xsl:template> 
</xsl:stylesheet> 

當這個變換所提供的XML文檔應用,有用結果產生

<root> 
    <criteria> 
     <criterion>BBB</criterion> 
     <criterion>CCC</criterion> 
     <criterion>DDD</criterion> 
    </criteria> 
</root> 

請注意

  1. 使用該身份模板的。

  2. 身份模板如何被特定模板重寫 - 僅適用於criterion元素,其字符串值爲'AAA'

+0

「相當不準確」?我相信你已經指出了一個錯誤,馬茨漢森不僅指出,而且還解釋和糾正。 – 2010-06-02 00:00:16

+0

@ John-Saunders:我很高興錯誤被糾正了。將嘗試取消我的downvote。希望這會有助於你下次更多關注。我的原則是對包含(至少是明顯的)錯誤的任何事情進行倒計時。不幸的是,我不能花時間糾正他人答案中的錯誤。 – 2010-06-02 00:54:04

+2

@Dimitre:你的態度沒有幫助。我試圖回答這個問題。我犯了一個錯誤。我的未修正代碼中的測試評估爲「true()」。結果,樣式表似乎工作。沒有理由對您的「更多關注」評論。如果你不能在這裏參與社區(這涉及幫助糾正錯誤答案),那麼你可能會考慮一個不同的問題,那就是無聲無息的無禮貢獻將被忽略。 – 2010-06-02 01:06:49