如何修复这两个xml文件的串联?

时间:2012-05-13 02:47:22

标签: xml xslt merge concatenation

我想要连接两个xml文件。 这是input1.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中,我们将它组合起来,如果不存在,我们会根据它们出现的顺序将它放在底部。

非常感谢。

约翰

1 个答案:

答案 0 :(得分: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>

当我使用Saxon 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>

我认为这就是你想要的。