按日期排序多个XML文件并使用XSLT将其合并为一个

按日期排序多个XML文件并使用XSLT将其合并为一个,xml,xslt,xslt-2.0,tei,Xml,Xslt,Xslt 2.0,Tei,我有几个XML文件,其中包含TEI中的历史字母。现在我想把它们合并到一个文件中,以日期为标准 A1.xml <?xml version="1.0" encoding="UTF-8"?> <TEI xml:id="1"> <teiHeader> <title>Letter 1</title> <date when="19990202" n="0"></date> </teiHeader>

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

A1.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>

信1
信1的内容

以及第二个文件A2.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>

信1
信2的内容

第三个是A3.xml:

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

信3
信3的内容

这些文件以连续的文件名“A001.xml”到“A999.xml”命名,但不是按照所需的顺序命名。因此,我首选的输出是单个文件letters.xml:

<?xml version="1.0" encoding="UTF-8"?>
<CORRESPONDENCE>

<TEI xml:id="3">
        <teiHeader>
            <title>Letter 3</title>
            <date when="18880101" n="0"></date>
        </teiHeader>
        <text>
                <p>Content of letter 3</p>
        </text>
        </TEI>

    <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>
        <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>
</CORRESPONDENCE>

信3
信3的内容

信1 信1的内容

信1 信2的内容

尽管我找到了将多个XML文件合并为一个文件的方法,但我无法使用排序标准使其正常工作。这可能吗

这可能吗

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

我将假设XSLT 3.0,因为这是演示该版本的一个新特性的极好示例:。并不是说不可能,只是没那么简单。它专门设计用于处理外部源,但可以处理任何输入,甚至任何大小(它是可流化的)

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>

由于您只想将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>

您使用哪种XSLT处理器,Saxon 9?你能给我们展示两个或三个输入样本,以及你想要为输入样本创建的合并和排序的输出吗?我使用Saxon 9。并将编辑我的初始发布。您确定要发布的输出吗?这不是一个格式良好的XML文档,因为它有三个顶级
TEI
元素,但没有一个根元素包含所有其他元素。我会手动添加的。谢谢!看起来很棒!尽管如此,我还是个新手,没法让它工作。我不得不删除xsl名称空间,因为OxygenXML抱怨xsl被保留。之后我可以进行转换,但它只是转换我开始转换时使用的第一个文件,而不是文件夹中的所有文件。“我做错了什么?”马丁安顿,如果你在用氧气,那么下面你在用萨克森。确保在XSLT文件中指定
version=“3.0”
。是的,oXygen抱怨xsl:initial template(他们知道它,他们会修复它),但您可以使用任何其他向后兼容的名称。另外,(使用(集合“您的文件规范”)的xpath
副本进行测试)
@martinanton还请注意,您需要Saxon的付费许可证-基本级别XSLT 3.0支持的“PE”版本,如果您想要流式传输,则需要“EE”。免费的“HE”版本只支持XSLT 2.0。请尝试类似于
collection('files?select=A*.xml')
XSLT3的出色解释,再加上一个。我同意,如果不需要额外的调整,各个文件的键和文档的结构相同,那么这也同样简单
teiHeader
可能应该在TEI名称空间中,但他的原始问题是
<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>