沿着日期排序几个XML文件,并使用XSLT将其合并为一个

时间:2015-09-17 18:41:45

标签: xml xslt xslt-2.0 tei

我有几个包含TEI历史字母的单个XML文件。现在我想将它们合并为一个文件,并以日期作为标准。

A1.xml

|         Full Path        |    File   |
|:------------------------:|:---------:|
| C:/Path/to/the/file1.ext | file1.ext |
| C:/Path/to/the/file2.ext | file2.ext |
| C:/Path/to/the/file3.ext | file3.ext |
| C:/Path/to/the/file4.ext | file4.ext |

和第二个文件,A2.xml:

|         Full Path        |    File   |
|:------------------------:|:---------:|
| C:\Path\to\the\file1.ext | file1.ext |
| C:\Path/to\the\file2.ext | file2.ext |
| C:\Path/to\the\file3.ext | file3.ext |
| C:\Path/to\the\file4.ext | file4.ext |

和第三个,A3.xml:

<?xml version="1.0" encoding="UTF-8"?>
<TEI xml:id="1">
<teiHeader>
    <title>Letter 1</title>
    <date when="19990202" n="0"></date>
</teiHeader>
<text>
        <p>Content of letter 1</p>
</text>
</TEI>

文件以连续的文件名命名&#34; A001.xml&#34;至&#34; A999.xml&#34;,但未达到所需的顺序。所以我的首选输出将是单个文件letters.xml:

<?xml version="1.0" encoding="UTF-8"?>
    <TEI xml:id="2">
    <teiHeader>
        <title>Letter 1</title>
        <date when="20010202" n="0"></date>
    </teiHeader>
    <text>
            <p>Content of letter 2</p>
    </text>
    </TEI>

即使我找到了将多个XML文件合并为一个的方法,但我还是设法使用排序标准让它工作。这甚至可能吗?

2 个答案:

答案 0 :(得分:5)

  

这甚至可能吗?

XSLT旨在能够使用XML执行任何转换任务,并且被认为是图灵完备所以是的,确实可能。

我将假设XSLT 3.0,因为这是展示该版本新功能的一个很好的例子:xsl:merge。并不是说它不可能,但它并不是那么简单。它专门设计用于外部源,但可以使用任何输入,甚至任何大小(它是可流动的)。

XSLT 3.0 xsl:merge示例

使用上面的示例,以下代码将按该文件模式获取所有XML文件,并创建一个文件,其中包含按日期排序的每个文档的副本。

<!-- xsl:initial-template, new in XSLT 3.0 is like "int main()" in C-style languages -->
<xsl:template name="xsl:initial-template">
    <!-- your other code here -->
    <result>
        <xsl:merge>

            <!-- 
            xsl:merge defines the source for merging. It is quite powerful. Here
            is a simple example with your data.

            With for-each-item you select a sequence of items that need to be merged,
            which goes in two steps, first you select a list of anchor items, then
            you use the select-attribute to select the sequence you want to merge. Here 
            a collection of documents is requested, like in OP's question

            The select statement selects, with focus on each document, the sequence
            of items to be merged. This sequence can be of any length (here it selects all
            historic letters)

            The merge-key defines the key for which items in the merge sequence are sorted,
            an incorrect order will result in an error, unless sort-before-merge 
            is also specified.
            -->
            <xsl:merge-source 
                for-each-item="collection('files/A*.xml')"
                select="/root/historic-letter/tei:TEI"
                sort-before-merge="true">
                <xsl:merge-key 
                    select="tei:teiHeader/tei:data/tei:when"
                    order="descending" 
                    data-type="number" />
            </xsl:merge-source>

            <!-- the merge action is called for each item resulting from the select 
            statement above. Only in this place can you use current-merge-key()
            and the current-merge-group() functions, which work similar to their grouping
            counterparts.
            -->
            <xsl:merge-action>
                <source original-document="{base-uri()}">
                    <xsl:copy-of select="." />
                </source>
            </xsl:merge-action>
        </xsl:merge>
    </result>
</xsl:template>

答案 1 :(得分:1)

由于您只想将XML文档与Saxon 9和XSLT 2.0连接起来,它就像

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

<xsl:param name="file-suffix" as="xs:string" select="'A*.xml'"/>

<xsl:template match="/" name="main">
  <CORRESPONDENCE>
    <xsl:perform-sort select="collection(concat('.?select=', $file-suffix))/*">
      <xsl:sort select="teiHeader/date/xs:integer(@when)"/>
    </xsl:perform-sort>
  </CORRESPONDENCE>
</xsl:template>

</xsl:stylesheet>

您可以使用命令行选项-it:main -xsl:stylesheet.xsl或者如果需要使用主输入文档来运行它,但是只需使用collection获取要处理的文档,如图所示。

如果输入样本中的元素位于命名空间http://www.tei-c.org/ns/1.0中,正如Abel所评论的那样,那么您需要将代码更改为

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xpath-default-namespace="http://www.tei-c.org/ns/1.0"
  exclude-result-prefixes="xs"
  version="2.0">

<xsl:param name="file-suffix" as="xs:string" select="'A*.xml'"/>

<xsl:template match="/" name="main">
  <CORRESPONDENCE>
    <xsl:perform-sort select="collection(concat('.?select=', $file-suffix))/*">
      <xsl:sort select="teiHeader/date/xs:integer(@when)"/>
    </xsl:perform-sort>
  </CORRESPONDENCE>
</xsl:template>

</xsl:stylesheet>