2012-05-13 30 views
0

我想連接兩個xml文件。 這裏是input1.xml:如何解決這個兩個XML文件的串聯?

<schema> 
    <sequence> 
     <section id="xxx"> 
      <nodeA id="a"> 
       <fruit id="small"> 
        <orange id="x" method="create">      
         <attributes> 
          <color>Orange</color> 
          <year>2000</year> 
         </attributes> 
        </orange>       
       </fruit> 
      </nodeA> 
      <nodeB id="b"> 
       <dog id="large"> 
        <doberman id="x" method="create"> 
         <condition> 
          <color>Black</color> 
         </condition> 
        </doberman> 
       </dog> 
      </nodeB> 
     </section> 
    </sequence> 
</schema> 

這裏input2.xml

<schema> 
    <sequence> 
     <section id="xxx"> 
      <nodeA id="a">     
       <fruit id="small">      
        <melon id="x" method="create"> 
         <attributes> 
          <color>Green</color>        
         </attributes> 
        </melon> 
       </fruit> 
       <lemon id="z" method="delete" /> 
      </nodeA> 
      <nodeA id="b"> 
       <fruit id="small"> 
        <lime id="x" method="create"> 
         <attributes> 
          <color>Yellow</color> 
          <year>2001</year> 
         </attributes> 
        </lime> 
       </fruit> 
      </nodeA> 
      <nodeB id="b"> 
       <dog id="small"> 
        <poodle id="x" method="create">      
         <condition> 
          <color>White</color> 
         </condition> 
        </poodle> 
       </dog>     
      </nodeB> 
      <nodeB id="c"> 
       <dog id="small"> 
        <terrier id="x" method="delete" /> 
       </dog> 
      </nodeB> 
     </section> 
    </sequence> 
</schema> 

我的輸出:

<schema> 
    <sequence> 
     <section id="xxx"> 
      <nodeA id="a"> 
       <fruit id="small"> 
        <orange id="x" method="create"> 
         <attributes> 
          <color>Orange</color> 
          <year>2000</year> 
         </attributes> 
        </orange> 
       </fruit> 
       <fruit id="small"> 
        <melon id="x" method="create"> 
         <attributes> 
          <color>Green</color> 
         </attributes> 
        </melon> 
       </fruit> 
       <lemon id="z" method="delete"/> 
      </nodeA> 
      <nodeB id="b"> 
       <dog id="large"> 
        <doberman id="x" method="create"> 
         <condition> 
          <color>Black</color> 
         </condition> 
        </doberman> 
       </dog> 
       <dog id="small"> 
        <poodle id="x" method="create"> 
         <condition> 
          <color>White</color> 
         </condition> 
        </poodle> 
       </dog> 
      </nodeB> 
     </section> 
    </sequence> 
</schema> 

雖然預期輸出是:

<schema> 
    <sequence> 
     <section id="xxx"> 
      <nodeA id="a"> 
       <fruit id="small"> 
        <orange id="x" method="create"> 
         <attributes> 
          <color>Orange</color> 
          <year>2000</year> 
         </attributes> 
        </orange> 
       </fruit> 
       <fruit id="small"> 
        <melon id="x" method="create"> 
         <attributes> 
          <color>Green</color> 
         </attributes> 
        </melon> 
       </fruit> 
       <lemon id="z" method="delete"/> 
      </nodeA> 
      <nodeB id="b"> 
       <dog id="large"> 
        <doberman id="x" method="create"> 
         <condition> 
          <color>Black</color> 
         </condition> 
        </doberman> 
       </dog> 
       <dog id="small"> 
        <poodle id="x" method="create"> 
         <condition> 
          <color>White</color> 
         </condition> 
        </poodle> 
       </dog> 
      </nodeB> 
      <nodeA id="b"> <!-- I'm missing this node --> 
       <fruit id="small"> 
        <lime id="x" method="create"> 
         <attributes> 
          <color>Yellow</color> 
          <year>2001</year> 
         </attributes> 
        </lime> 
       </fruit> 
      </nodeA> 
      <nodeB id="c"> <!-- I'm missing this node --> 
       <dog id="small"> 
        <terrier id="x" method="delete" /> 
       </dog> 
      </nodeB> 
     </section> 
    </sequence> 
</schema> 

的XSLT文件是這樣的:

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

    <xsl:param name="input2"/> 
    <xsl:variable name="to-merge" select="document($input2)" /> 

    <xsl:function name="a:id"> 
     <xsl:param name="ctx"/> 
     <xsl:value-of select="concat($ctx/local-name(), $ctx/@id)"/> 
    </xsl:function> 

    <xsl:key name="match" match="/schema/sequence/section/*" use="a:id(.)"/> 

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

    <xsl:template match="*[count(. | key('match', a:id(.))) = count(key('match', a:id(.)))]"> 
    <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 

      <xsl:variable name="id" select="a:id(.)"/> 
      <xsl:for-each select="$to-merge"> 
       <xsl:apply-templates select="key('match', $id)/*"/> 
      </xsl:for-each> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

如何修改XSLT文件來生成所需的輸出?這裏的關鍵是保持節點的順序。如果節點存在於file1中,我們將它合併,如果不是,我們會根據它們的顯示順序將它放在最下面。

非常感謝。

約翰

+0

您在您的問題中使用的XML既沒有意義也沒有基於錯誤的設計。我會一直用這樣的XML來忽略問題。特別是,它太長了,屬性沒有意義,特定元素的名稱是任意的,不重複,有多個元素具有相同的'id'。這使得很難推斷出共同的結構和/或關係。我希望你們能夠改進未來問題的例子,使它們不再是無意義的,非結構化的,違反基本原則和混亂的。 –

+0

@DimitreNovatchev我爲此道歉。這不是我打算給出令人困惑的例子,它只是它正在與我一起工作的真正的XML結構(與重複的ID和東西)。但我會在未來嘗試提供更有意義的例子。謝謝。 – John

回答

2

正如你已經使用XSLT 2.0我不會打擾按鍵,而是使用xsl:for-each-group如下:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

<xsl:param name="url2" select="'test2012051302.xml'"/> 
<xsl:variable name="doc2" select="document($url2)"/> 

<xsl:output indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="sequence"> 
    <xsl:copy> 
    <xsl:for-each-group select="section | $doc2/schema/sequence/section" group-by="@id"> 
     <section id="{current-grouping-key()}"> 
     <xsl:for-each-group select="current-group()/*" group-by="concat(local-name(), '|', @id)"> 
      <xsl:copy> 
      <xsl:apply-templates select="@*, *, (current-group() except .)/*"/> 
      </xsl:copy> 
     </xsl:for-each-group> 
     </section> 
    </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

當我使用撒克遜9.4 HE以上應用樣式表到你的輸入樣本我得到結果

<?xml version="1.0" encoding="UTF-8"?> 
<schema> 
    <sequence> 
     <section id="xxx"> 
     <nodeA id="a"> 
      <fruit id="small"> 
       <orange id="x" method="create"> 
        <attributes> 
        <color>Orange</color> 
        <year>2000</year> 
        </attributes> 
       </orange> 
      </fruit> 
      <fruit id="small"> 
       <melon id="x" method="create"> 
        <attributes> 
        <color>Green</color> 
        </attributes> 
       </melon> 
      </fruit> 
      <lemon id="z" method="delete"/> 
     </nodeA> 
     <nodeB id="b"> 
      <dog id="large"> 
       <doberman id="x" method="create"> 
        <condition> 
        <color>Black</color> 
        </condition> 
       </doberman> 
      </dog> 
      <dog id="small"> 
       <poodle id="x" method="create"> 
        <condition> 
        <color>White</color> 
        </condition> 
       </poodle> 
      </dog> 
     </nodeB> 
     <nodeA id="b"> 
      <fruit id="small"> 
       <lime id="x" method="create"> 
        <attributes> 
        <color>Yellow</color> 
        <year>2001</year> 
        </attributes> 
       </lime> 
      </fruit> 
     </nodeA> 
     <nodeB id="c"> 
      <dog id="small"> 
       <terrier id="x" method="delete"/> 
      </dog> 
     </nodeB> 
     </section> 
    </sequence> 
</schema> 

我認爲是你想要的。

+0

謝謝你它漂亮的作品!對於

「如果有更多屬性而不僅僅是id,我如何將它們打印出來? – John

+1

'

...
'你可以嘗試' ...'或' ...',根據您的需要而定(例如,第一個建議允許您在需要時使用附加模板轉換屬性,第二個建議只需複製屬性)。 –

+0

非常感謝! – John