2017-02-13 85 views
-1

注意:這不是 Merge 2 XML files based on attribute values using XSLT? 的重複,但是它是其擴展。由於後面的輸入文件使用XSLT根據屬性值合併2個XML文件(包括節點屬性)

file1.xml

<config> 
<state version="10"> 
    <root value="100" group="5"> 
    <leaf number = "2"/> 
    </root> 
    <root value="101" group="6" overrideAttr="oldval"> 
    <leaf number = "3"/> 
    </root> 
</state> 
</config> 

file2.xml

<config> 
<state version="10"> 
    <root value="100" group="5"> 
    <leaf number = "6"/> 
    </root> 
    <root value="101" group="6" overrideAttr="newval" addtionalAttr="hello"> 
    <leaf number = "4"/> 
    </root> 
</state> 
</config> 

我想有這樣的Output.xml

<config> 
<state version="10"> 
    <root value="100" group="5"> 
    <leaf number = "2"/> 
    <leaf number = "6"/> 
    </root> 
    <root value="101" group="6" overrideAttr="newval" addtionalAttr="hello"> 
    <leaf number = "3"/> 
    <leaf number = "4"/> 
    </root> 
</state> 
</config> 

所需擴展名是

  • 屬性(例如overrideAttr)關於「相同的節點」(例如元件與值根=「101」和基團=「6」)應覆蓋
  • 新屬性(例如addtionalAttr)應加

可以這樣來實現由xsl?

+1

** 1 **什麼定義「相同」的節點? - ** 2。**請說明是否使用XSLT 1.0或2.0。 –

+0

> 1.什麼定義了「相同」節點? 查看上述線程的「解決方案」 > 2。請指出是否使用XSLT 1.0或2.0 無論javax.xml.transform。TransformerFactory支持 – Clemens

回答

1

在您已鏈接到的答案中,有一個xsl:apply-templates從第二個文件跨子元素複製。

<xsl:apply-templates 
    select="document('file2.xml') 
      /config/state[@version = current()/../@version] 
       /root[@value = current()/@value and 
         @group = current()/@group]/*" /> 

所有你需要做的就是增加一個類似線跨越屬性複製

<xsl:apply-templates 
    select="document('file2.xml') 
      /config/state[@version = current()/../@version] 
       /root[@value = current()/@value and 
         @group = current()/@group]/@*" /> 

儘管這將需要任何現有的子節點的複製之前完成(如屬性必須小孩前加入節點)。

另外,您可能希望使用變量來避免重複xpath表達式。

試試這個XSLT ...

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

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

    <xsl:template match="root"> 
     <xsl:variable name="file2root" select="document('file2.xml') 
       /config/state[@version = current()/../@version] 
        /root[@value = current()/@value and 
          @group = current()/@group]" /> 
    <xsl:copy> 
     <xsl:apply-templates select="@*" /> 
     <xsl:apply-templates select="$file2root/@*" /> 
      <xsl:apply-templates select="node()" /> 
     <xsl:apply-templates select="$file2root/*" /> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

注意,這需要一個事實,即利用「添加到該元素的屬性替換該元素具有相同擴展名任何現有屬性」。 (見https://www.w3.org/TR/xslt#creating-attributes

0

如果你想延長這種解決方案,那麼你可以如下做到這一點,更改root元素(http://xsltransform.net/gWEamLR/1)該模板

 <xsl:template match="root"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="$doc2 
       /config/state[@version = current()/../@version] 
        /root[@value = current()/@value and 
          @group = current()/@group]/@*" /> 
     <xsl:apply-templates select="node()"/> 
     <xsl:apply-templates select=" 
     $doc2 
       /config/state[@version = current()/../@version] 
        /root[@value = current()/@value and 
          @group = current()/@group]/*" /> 
    </xsl:copy> 
    </xsl:template> 

,並確保您定義<xsl:param name="doc2" select="document('file2.xml')"/>

可能有更好的方式使用按鍵或分組這樣做合併,當然在XSLT 3.0,我們現在有xsl:merge

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math" 
    version="3.0"> 

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

    <xsl:template match="/" name="main"> 
     <config> 
      <xsl:merge> 
       <xsl:merge-source select="doc('file1.xml')/config/state"> 
        <xsl:merge-key select="@version"/> 
       </xsl:merge-source> 
       <xsl:merge-source select="doc('file2.xml')/config/state"> 
        <xsl:merge-key select="@version"/> 
       </xsl:merge-source> 
       <xsl:merge-action> 
        <xsl:copy> 
         <xsl:copy-of select="@*"/> 
         <xsl:merge> 
          <xsl:merge-source select="current-merge-group()[1]/root"> 
           <xsl:merge-key select="@value"/> 
           <xsl:merge-key select="@group"/> 
          </xsl:merge-source> 
          <xsl:merge-source select="current-merge-group()[2]/root"> 
           <xsl:merge-key select="@value"/> 
           <xsl:merge-key select="@group"/> 
          </xsl:merge-source> 
          <xsl:merge-action> 
           <xsl:copy> 
            <xsl:copy-of select="current-merge-group()[2]/@*"/> 
            <xsl:copy-of select="current-merge-group()/node()"/> 
           </xsl:copy> 
          </xsl:merge-action> 
         </xsl:merge> 
        </xsl:copy> 
       </xsl:merge-action> 
      </xsl:merge> 
     </config> 
    </xsl:template> 

</xsl:stylesheet>