2012-05-02 29 views
0

如果我對XML的輸入文件:如何簡化兄弟間的XML節點以確保使用XSLT不存在重複的節點?

<root> 
    <node id="N1"> 
     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Orange</color> 
        <year>2000</year> 
       </attribute> 
      </orange>       
     </fruit>   

     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Orange</color> 
        <condition>good</condition> 
       </attribute> 
      </orange>       
     </fruit>   
    </node> 
</root> 

,這裏是預期輸出:

<root> 
    <node id="N1"> 
     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Orange</color> 
        <year>2000</year> 
        <condition>good</condition> 
       </attribute> 
      </orange>       
     </fruit>   

     <fruit id="1">         
     </fruit> 
    </node> 
</root> 

如何將兩個兄弟之間的簡化:

  1. 檢查如果家長相同(水果ID = 1)
  2. 檢查節點ID和動作是否相同(橙色ID = X動作=創建)
  3. 如果子元素先前已定義且值相同(橙色),我們將其刪除。
  4. 如果第二個兄弟的子元素沒有被明確定義,我們將第二個節點添加到第一個節點。 (條件良好)
  5. 如果節點先前已經被定義,但是具有不同的值(比如顏色爲紅色),我們將節點保持原樣。

另一種情形: 輸入2:

<root> 
    <node id="N1"> 
     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Orange</color>     
       </attribute> 
      </orange>       
     </fruit>   

     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Red</color> 
        <condition>good</condition> 
       </attribute> 
      </orange>       
     </fruit>   
    </node> 
</root> 

預期輸出中:

<root> 
    <node id="N1"> 
     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Orange</color> 
        <condition>good</condition> 
       </attribute> 
      </orange>       
     </fruit>   

     <fruit id="1"> 
      <orange id="x" action="create"> 
       <attribute> 
        <color>Red</color> 
       </attribute> 
      </orange>       
     </fruit>   
    </node> 
</root> 

另一種情形:

<root> 
    <nodeA id="A"> 
     <fruit id="1"> 
      <orange id="x" action="delete" /> <!-- no attributes here -->           
     </fruit>   

     <fruit id="1"> 
      <orange id="x" action="delete"/> 
      <orange id="y" action="delete" />            
     </fruit>   
    </nodeA> 
</root> 

預期輸出:

<root> 
    <nodeA id="A"> 
     <fruit id="1"> 
      <orange id="x" action="delete" /> 
     </fruit>   

     <fruit id="1"> 
      <orange id="y" action="delete" />           
     </fruit>   
    </nodeA> 
</root> 

我希望例子給出清晰的想法,請幫助我與轉換文件。 謝謝。

約翰

+1

到目前爲止,你有什麼XSL? – Torious

+0

我想這是這一個的下一章:http://stackoverflow.com/questions/10368853/merge-two-or-more-xml-node-using-xslt。實際上,如果他認爲他需要通過id匹配並構建子節點的超集,我實際上在評論中詢問了@John對Dimitre的回答。看起來像他,事實上,需要它:) –

+0

@John,我得到第一個例子,但我掙扎着第二個。你能否詳細說一下爲什麼'condition'移動到'create orange'的第一個聲明?如果將它合併爲「紅色」並且「條件良好」並且只有一次,那麼基本上,「最近」值最多的超集優先於先前定義的集合。我錯過了什麼嗎? –

回答

2

約翰,這是一個有效的版本。它有些殘酷和程序性,所以我想知道你是否真的想在XSLT中做這種邏輯。在這裏你去:

以下樣式:

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

    <xsl:key name="entity" match="node/*/*" use="concat(parent::*/@id, '_', @id, '_', @action)"/> 

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

    <xsl:template match="node/*/*[not(attribute)][generate-id() != generate-id(key('entity', concat(parent::*/@id, '_', @id, '_', @action))[1])]"/> 

    <xsl:template match="node/*/*[attribute]"> 
     <xsl:variable name="attributes"> 
      <xsl:copy> 
       <xsl:apply-templates select="@* | node()"> 
        <xsl:with-param 
          name="mode" 
          select="generate-id() = generate-id(key('entity', concat(../@id, '_', @id, '_', @action))[1])"/> 
       </xsl:apply-templates> 
      </xsl:copy> 
     </xsl:variable> 
     <xsl:if test="$attributes/*/attribute/*"> 
      <xsl:copy-of select="$attributes"/> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="node/*/*/attribute"> 
     <xsl:param name="mode"/> 
     <xsl:variable name="all-attributes" select="key('entity', concat(../../@id, '_', ../@id, '_', ../@action))/attribute/*"/> 
     <xsl:copy> 
      <xsl:if test="$mode = true()"> 
       <xsl:for-each-group select="$all-attributes" group-by="local-name()"> 
        <xsl:copy> 
         <xsl:apply-templates select="@* | node()"/> 
        </xsl:copy> 
       </xsl:for-each-group> 
      </xsl:if> 
      <xsl:if test="$mode = false()"> 
       <xsl:for-each select="*"> 
        <xsl:variable 
         name="same-name-attr" 
         select="$all-attributes[local-name() = current()/local-name()][count(. | current()/preceding::*) = count(current()/preceding::*)]"/> 
        <xsl:if test="$same-name-attr and not(. = $same-name-attr)"> 
         <xsl:copy-of select="."/> 
        </xsl:if> 
       </xsl:for-each> 
      </xsl:if> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

產生以下結果

<root> 
    <node id="N1"> 
     <fruit id="1"> 
     <orange id="x" action="create"> 
      <attribute> 
       <color>Orange</color> 
       <year>2000</year> 
       <condition>good</condition> 
       <new>!!</new> 
      </attribute> 
     </orange> 
     </fruit> 
     <fruit id="1"> 
     <orange id="x" action="create"> 
      <attribute> 
       <color>Red</color> 
      </attribute> 
     </orange> 
     </fruit> 
     <fruit id="1"> 
     <orange id="x" action="create"> 
      <attribute> 
       <color>Blue</color> 
      </attribute> 
     </orange> 
     </fruit> 
     <fruit id="1"> 
     <orange id="x" action="create"> 
      <attribute> 
       <condition>ugly</condition> 
      </attribute> 
     </orange> 
     </fruit> 
     <fruit id="1"/> 
    </node> 
</root> 

所有獨特屬性只拉入create行動中第一次出現,那些具有不同值的屬性保留在following::節點中。如果節點沒有任何新東西可以添加它,那就留下來。以下是我如何確定該屬性是否值得在後續事件中保留的方法。如果之前沒有看到該屬性,那麼它已經被拉到第一次出現,所以我們跳過它。如果之前已經看到它(=它在preceding軸上的同名屬性的集合中)並且具有不同的文本值,那麼只有我們保留它。

你想做的選擇器越來越複雜,所以我不得不使用臨時變量來基本上讓模板對它進行拍攝,然後檢查是否有任何結果,然後決定是否值得複製到結果樹。可能有一種方法可以將此邏輯轉換爲匹配謂詞,但我不確定它會更具可讀性。我希望這是有道理的。

UPDATE我更新的解決方案,也爲你無屬性角落的情況下工作。我基本上不得不保持重複的no-attribute節點,並且使主模板更加具體一些,以便僅在具有attribute的節點上工作。使用主要屬性合併邏輯,將「重複」with-attribute節點的無屬性節點將保持沉默。需要保留的no-attribute節點將使用默認標識轉換進行復制。

+0

非常感謝!這是我需要的確切要求。 – John

+0

我想知道你是如何用xslt學習所有這些東西的。 – John

+0

嗨,你介意更新的解決方案,以便它可以應用到其他子元素(在這個例子中:''),雖然它可以是任何和不同的每個節點。感謝這麼多。 – John

相關問題