Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用xsl合并、分组和排序许多XML_Xml_Sorting_Xslt_Merge - Fatal编程技术网

使用xsl合并、分组和排序许多XML

使用xsl合并、分组和排序许多XML,xml,sorting,xslt,merge,Xml,Sorting,Xslt,Merge,我正在尝试将多个XML文件(数百个)合并到一个XML文件中,但通过标记(还添加了一个额外的容器和一个源文件名标记)对它们进行排序和分组。我曾经尝试过用C#实现这一点,但经过研究,XSLT似乎是实现这一点的最简单方法?问题是我没有足够的XSLT经验来实现这一点 我将尝试使用三个简化的XML文件进行演示: file1.xml <?xml version="1.0" encoding="UTF-8" ?> <OrigResponse> <address>

我正在尝试将多个XML文件(数百个)合并到一个XML文件中,但通过标记
(还添加了一个额外的容器和一个源文件名标记)对它们进行排序和分组。我曾经尝试过用C#实现这一点,但经过研究,XSLT似乎是实现这一点的最简单方法?问题是我没有足够的XSLT经验来实现这一点

我将尝试使用三个简化的XML文件进行演示:

file1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<OrigResponse>
     <address>
        <name1>Title1001257027</name1>
        <add1>address 1</add1>      
     </address>
<trans>
    <header>
        <h1text>mixed text</h1text>
    </header>
    <body>
       <accountno>123456789</accountno>
    </body>
</trans>
</OrigResponse>

标题1001257027
地址1
混合文本
123456789
File2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<OrigResponse>
  <address>
    <name1>Title1001257028</name1>
    <add1>address 1</add1>      
  </address>
<trans>
    <header>
      <h1text>mixed text</h1text>
    </header>
    <body>
        <accountno>000456700</accountno>
    </body>
</trans>
</OrigResponse>

标题1001257028
地址1
混合文本
000456700
File3.xml

<?xml version="1.0" encoding="UTF-8" ?>
<OrigResponse>
  <address>
    <name1>Title1001257027</name1>
    <add1>address 1</add1>      
  </address>
<trans>
    <header>
      <h1text>mixed text</h1text>
    </header>
    <body>
        <accountno>123456789</accountno>
    </body>
</trans>
</OrigResponse>

标题1001257027
地址1
混合文本
123456789
由于File1和file3.xml用于相同的帐号,因此需要将它们合并到一个唯一的容器中,而file2位于其自己的容器中。因此,对于输出xml文件,我将创建如下内容:

merged.xml

<?xml version="1.0" encoding="UTF-8" ?>          
<OrigResponse>                                   
    <mergeinvoice>                                 
      <inputfile id="{cntr}">file3.xml</inputfile> 
      <address>                                  
          <name1>Title100125777</name1>           
            <add1>address 1</add1>                     
        </address>                                 
    <trans>                                      
        <header>                                   
            <h1text>mixed text</h1text>              
        </header>                                  
        <body>                                     
            <accountno>000456700</accountno>         
      </body>                                    
    </trans>                                     
    <inputfile id="{cntr}">file1.xml</inputfile> 
      <address>                                  
          <name1>Title1001257027</name1>           
            <add1>address 1</add1>                     
        </address>                                 
    <trans>                                      
        <header>                                   
            <h1text>mixed text</h1text>              
        </header>                                  
        <body>                                     
            <accountno>123456789</accountno>         
      </body>                                    
    </trans>                                     
  </mergeinvoice>                                
    <mergeinvoice>                                 
      <inputfile id="{cntr}">file2.xml</inputfile> 
      <address>                                  
          <name1>Title1001257027</name1>            
            <add1>address 1</add1>                     
        </address>                                 
    <trans>                                      
        <header>                                   
            <h1text>mixed text</h1text>              
        </header>                                  
        <body>                                     
            <accountno>123456789</accountno>         
      </body>                                    
    </trans>                                     
</OrigResponse>

file3.xml
标题100125777
地址1
混合文本
000456700
file1.xml
标题1001257027
地址1
混合文本
123456789
file2.xml
标题1001257027
地址1
混合文本
123456789
因此,我们在容器

我还需要在父级插入
标记,该标记包含每个帐户的源xml文件的名称,最后,在同一标记中插入一个'id'属性,该标记包含每个文件的递增计数器(我已使用变量占位符
{cntr}

使用XSLT是否可以像建议的那样轻松地实现这一点?我意识到这是一个很大的问题,但如果是这样,我希望专家能给我一个正确的方向

多谢期待


Andy

假设Saxon 9和XSLT 2.0,以下样式表将使用初始模板
main
it:main
命令行选项)调用,并读取目录中的所有
*.xml
文档并对它们进行分组:

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

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

<xsl:template name="main">
  <OrigResponse>
    <xsl:for-each-group select="collection('.?*.xml')/OrigResponse" group-by="trans/body/accountno">
      <mergeinvoice>
        <xsl:variable name="group-pos" as="xs:integer" select="position()"/>
        <xsl:apply-templates select="current-group()">
          <xsl:with-param name="group-pos" select="$group-pos"/>
        </xsl:apply-templates>
      </mergeinvoice>
    </xsl:for-each-group>
  </OrigResponse>
</xsl:template>

<xsl:template match="OrigResponse">
  <xsl:param name="group-pos" as="xs:integer"/>
  <inputfile id="f{$group-pos}-{position()}">
    <xsl:value-of select="tokenize(document-uri(/), '/')[last()]"/>
  </inputfile>
  <xsl:copy-of select="node()"/>
</xsl:template>

</xsl:stylesheet>
然后输出是

<OrigResponse>
  <mergeinvoice>
     <inputfile id="1">file1.xml</inputfile>
     <address>
        <name1>Title1001257027</name1>
        <add1>address 1</add1>
     </address>
     <trans>
        <header>
           <h1text>mixed text</h1text>
        </header>
        <body>
           <accountno>123456789</accountno>
        </body>
     </trans>
     <inputfile id="2">file3.xml</inputfile>
     <address>
        <name1>Title1001257027</name1>
        <add1>address 1</add1>
     </address>
     <trans>
        <header>
           <h1text>mixed text</h1text>
        </header>
        <body>
           <accountno>123456789</accountno>
        </body>
     </trans>
  </mergeinvoice>
  <mergeinvoice>
     <inputfile id="3">file2.xml</inputfile>
     <address>
        <name1>Title1001257028</name1>
        <add1>address 1</add1>
     </address>
     <trans>
        <header>
           <h1text>mixed text</h1text>
        </header>
        <body>
           <accountno>000456700</accountno>
        </body>
     </trans>
  </mergeinvoice>
</OrigResponse>

file1.xml
标题1001257027
地址1
混合文本
123456789
file3.xml
标题1001257027
地址1
混合文本
123456789
file2.xml
标题1001257028
地址1
混合文本
000456700

您使用什么XSLT处理器?(我希望是萨克森)。嗨,Mathias-是的,我使用萨克森。我问这个问题的原因是
collection()
仅在XSLT 2.0处理器上可用。还有一个有趣的问题,如果我有时间的话,我会稍后再看。谢谢Mathias,我确实读到Saxon支持XSLT2.0和XSLT3.0部分的基本支持。如果你能有机会,真的很感激马丁已经给了你一个非常有希望的解决方案。您需要一个可以处理2.0样式表的Saxon版本,最好是9.5(或9.6,但9.5似乎更稳定)。嗨,Mathias和Martin,提供的解决方案工作得非常好!感谢你们两位的投入,这无疑促使我将来更多地使用XSLT。当做Andy@osirisja,当答案解决了您的问题时,通常的做法是接受它,以便将其标记为已解决。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">

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

<xsl:template name="main">
  <OrigResponse>
    <xsl:variable name="temp-doc">
      <xsl:for-each-group select="collection('.?*.xml')/OrigResponse" group-by="trans/body/accountno">
        <mergeinvoice>
          <xsl:apply-templates select="current-group()" mode="group"/>
        </mergeinvoice>
      </xsl:for-each-group>
    </xsl:variable>
    <xsl:apply-templates select="$temp-doc/node()"/>
  </OrigResponse>
</xsl:template>

<xsl:template match="OrigResponse" mode="group">
  <inputfile>
    <xsl:value-of select="tokenize(document-uri(/), '/')[last()]"/>
  </inputfile>
  <xsl:copy-of select="node()"/>
</xsl:template>

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

<xsl:template match="inputfile">
  <xsl:copy>
    <xsl:attribute name="id">
      <xsl:number level="any"/>
    </xsl:attribute>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>
<OrigResponse>
  <mergeinvoice>
     <inputfile id="1">file1.xml</inputfile>
     <address>
        <name1>Title1001257027</name1>
        <add1>address 1</add1>
     </address>
     <trans>
        <header>
           <h1text>mixed text</h1text>
        </header>
        <body>
           <accountno>123456789</accountno>
        </body>
     </trans>
     <inputfile id="2">file3.xml</inputfile>
     <address>
        <name1>Title1001257027</name1>
        <add1>address 1</add1>
     </address>
     <trans>
        <header>
           <h1text>mixed text</h1text>
        </header>
        <body>
           <accountno>123456789</accountno>
        </body>
     </trans>
  </mergeinvoice>
  <mergeinvoice>
     <inputfile id="3">file2.xml</inputfile>
     <address>
        <name1>Title1001257028</name1>
        <add1>address 1</add1>
     </address>
     <trans>
        <header>
           <h1text>mixed text</h1text>
        </header>
        <body>
           <accountno>000456700</accountno>
        </body>
     </trans>
  </mergeinvoice>
</OrigResponse>