0

如果我有这个文件: 输入 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>

文件 2.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>

对于连接,它将取决于文件顺序,因此 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、nodeB、SomeNode 等),因此需要一些可以概括此问题的东西。

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

非常感谢。约翰

4

3 回答 3

3

@John,这是一个更通用的解决方案:

<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:ida:id只需将函数放入谓词中,就可以回退到 XSLT 1.0 。

我的假设:

  • 您在“领先”文档上运行转换并在该to-merge变量中对合并进行排序
  • 您有一个匹配点,位于要合并的每个文档的同一位置。自定义解决方案以从每个文档的不同点进行合并应该不难。
  • 节点通过local-name()and匹配@id
于 2012-05-09T20:08:33.257 回答
1

这是另一个答案。这在 schema/sequence/* 级别连接,而不仅仅是 nodeA 和 NodeB。

 <?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 * 我将 id 属性添加到等。

更新 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>
于 2012-05-08T08:19:57.463 回答
0

尝试:

 <?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>

使 file1 成为您的主要文档输入。将 file2 的文件名作为参数“file2”传递。类似地扩展多个输入文件。

于 2012-05-08T02:26:56.380 回答