如何使用XSLT来连接两个或多个XML文件,并维持秩序?(How to concatenate tw

2019-07-29 07:17发布

如果我有这样的文件: 输入file1.xml:

<schema>
    <sequence> 
        <nodeA id="a">
            <fruit id="small">
                <orange id="x" method="create">                    
                    <attributes>
                        <color>Orange</color>
                        <year>2000</year>
                    </attributes>
                </orange>                           
            </fruit>
            <fruit id="small">
                <apple id="x" method="create">                    
                    <attributes>
                        <color>Orange</color>
                        <year>2000</year>
                    </attributes>
                </apple>                           
            </fruit>
            <fruit id="medium">
                <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>
    </sequence>
</schema>

file2.xml:

<schema>
    <sequence>
        <nodeA id="a">
            <fruit id="small">
                <melon id="x" method="create">
                    <attributes>
                        <color>Orange</color>
                        <year>2000</year>
                    </attributes>
                </melon>
            </fruit>
        </nodeA>
        <nodeB id="b">
            <dog id="small">
                <poodle id="x" method="create">                    
                    <condition>
                        <color>White</color>
                    </condition>
                </poodle>  
            </dog>                
        </nodeB>
    </sequence>
</schema>

经过串联: 输出:concate.xml

<schema>
    <sequence>
        <nodeA id="a">
            <fruit id="small">
                <orange id="x" method="create">                    
                    <attributes>
                        <color>Orange</color>
                        <year>2000</year>
                    </attributes>
                </orange>                        
            </fruit>
            <fruit id="small">
                <apple id="x" method="create">                    
                    <attributes>
                        <color>Orange</color>
                        <year>2000</year>
                    </attributes>
                </apple>                           
            </fruit>
            <fruit id="medium">
                <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>Orange</color>
                        <year>2000</year>
                    </attributes>
                </melon>
            </fruit>
        </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>
    </sequence>
</schema>

对于concate这将取决于该文件顺序上 ,以便在file2.xml节点将file1.xml的节点下放置(在例子可见)。 我有多达5个文件。 如何使用此实现XSL转换只,即XSLT将投入5个文件在同一时间和输出1个文件?

这是文档结构和我们做合并点:

<schema>
    <sequence> 
        <nodeA id="a">
            <fruit id="small">
                <orange id="x" method="create">                    
                    ...
                </orange>                
            </fruit>
            <fruit id="small">
                ...                          
            </fruit>
            <fruit id="large"> 
                ...                          
            </fruit>

            <!-- we merge below this -->
        </nodeA>

        <nodeB id="b">
            <dog id="large">
                <doberman id="x" method="create">
                    ...
                </doberman>
            </dog>
            <dog id="small">
                <doberman id="x" method="create">
                    ...
                </doberman>
            </dog>
        <!-- we merge below this -->
        </nodeB>

        <somenode id="any">
            ...    
        </somenode>
    </sequence>
</schema>

注意:如果不能串联只有两个文件输入将被罚款,因为它总是可以重复用于其他文件。 还有一些文件中的各个节点名(nodeA上,节点B,SomeNode等),这样的东西,可以概括需要此问题。

我们可以使用xsl1.0或2.0。

非常感谢。 约翰

Answer 1:

@约翰,这里有一个更通用的解决方案:

<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:variable name="to-merge" select="document('input2.xml') | document('input3.xml')"/>

   <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/*" 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>

您可以定义在汇合点key ,你的定义合并匹配功能a:id 。 你可以只取退回到XSLT 1.0 a:id功能到您的谓词。

我的假设:

  • 您运行的“龙头”的文件转换和在该序列的合并to-merge的变量
  • 你必须要合并一个赛点位于每个文件在同一地点。 它不应该是很难定制解决方案,以从每个文档中的不同点合并。
  • 节点匹配的local-name()@id


Answer 2:

这是另一种答案。 这在连接模式/顺序/ *水平,而不仅仅是nodeA和基站。

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

 <xsl:output indent="yes" encoding="UTF-8" />
 <xsl:param name="file2" /> <!-- input file1.xml -->
 <xsl:variable name="file1-doc" select="root()" />
 <xsl:variable name="file2-doc" select="document($file2)" />


 <xsl:template  match="/">
  <schema>
   <sequence>
    <xsl:call-template name="union-point">
     <xsl:with-param name="value" select="schema/sequence/*"/>
    </xsl:call-template>
    <xsl:call-template name="union-point">
     <!-- The following predicate excludes all the node names that we
             have already processed in the first call-template.    -->
     <xsl:with-param name="value" select="$file2-doc/schema/sequence/*
      [not (fn:exists($file1-doc/schema/sequence/name()))]
      "/>
    </xsl:call-template>
   </sequence>
  </schema>
 </xsl:template>

 <xsl:template name="union-point">
   <xsl:param name="value"/>
   <xsl:for-each select="$value/name()" >
    <xsl:variable name="node-name" select="."/>
    <xsl:element name="{.}">
 <xsl:attribute name="id">
  <xsl:value-of select="($file1-doc/schema/sequence/*[name()=$node-name]/@id |
                         $file2-doc/schema/sequence/*[name()=$node-name]/@id  )[1]" />
 </xsl:attribute>
     <xsl:apply-templates select="$file1-doc/schema/sequence/*[name()=$node-name]/*" />
     <xsl:apply-templates select="$file2-doc/schema/sequence/*[name()=$node-name]/*" />
    </xsl:element>
   </xsl:for-each>
 </xsl:template>

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

 <xsl:template match="attribute()|text()|comment()|processing-instruction()">
   <xsl:copy/>
 </xsl:template>

 </xsl:stylesheet>

作为一种解决方案,它可能是一个有点笨拙和尴尬,但它基本的工作原理。 希望像Dimitre Novatchev的专家会来提供一个整洁的选择。 这是关于我的能力所及的范围。

* 更新1 * I加入的id属性的等

UPDATE 2这里是作为结果的输出:

 <?xml version="1.0" encoding="UTF-8"?>
 <schema>
    <sequence>
       <nodeA id="a">
          <fruit id="small">
                 <orange id="x" method="create">                    
                     <attributes>
                         <color>Orange</color>
                         <year>2000</year>
                     </attributes>
                 </orange>                           
             </fruit>
               <fruit id="small">
                 <apple id="x" method="create">                    
                     <attributes>
                         <color>Orange</color>
                         <year>2000</year>
                     </attributes>
                 </apple>                           
             </fruit>
          <fruit id="medium">
                 <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>Orange</color>
                         <year>2000</year>
                     </attributes>
                 </melon>
             </fruit>
       </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>
    </sequence>
 </schema>


Answer 3:

尝试:

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

 <xsl:output indent="yes" encoding="UTF-8" />
 <xsl:param name="file2" /> <!-- input file1.xml -->
 <xsl:variable name="file2-doc" select="document($file2)" />

 <xsl:template  match="/">
  <schema>
   <sequence>
    <nodeA id="a">
     <xsl:apply-templates select="schema/sequence/nodeA/*" />
     <xsl:apply-templates select="$file2-doc/schema/sequence/nodeA/*" />
    </nodeA>
    <nodeB id="b">
     <xsl:apply-templates select="schema/sequence/nodeB/*" />
     <xsl:apply-templates select="$file2-doc/schema/sequence/nodeB/*" />
    </nodeB>
   </sequence>
  </schema>
 </xsl:template>

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

 <xsl:template match="attribute()|text()|comment()|processing-instruction()">
   <xsl:copy/>
 </xsl:template>

 </xsl:stylesheet>

让文件1主文档输入。 传递文件名的文件2的参数“文件2”。 类似地延伸,用于多个输入文件。



文章来源: How to concatenate two or more xml files using xslt and maintain the order?
标签: xml xslt