合并多个XML文件并根据属性值

时间:2016-04-02 11:56:19

标签: xml xslt

我有几个具有不同结构的XML文件,我想根据指示日期(@when)的公共属性以时间轴的形式合并。

file1的。 XML

<persons>

<person id="p0001">
<name>John Skelton</name>
<born when="1782-05-01">John Skelton born</born>
<died when="1866-01-05">John Skelton died</died>
</person>

...

</persons>

file2.xml

<events>

<event id="e0001" when="1782">
<name>Publication of <hi>Transactions</hi></name>
</event>

<event id="e0002" when="1866">
<name>Boston meeting of Generals</name>
</event>

...

</events>

这些XML文件可能还有更多。

我想要的输出将是:

<div id="timeline">

<div class="year">1782</div>
<p data-when="1782-05-01" data-id="p0001">John Skelton born</p>
<p data-when="1782" data-id="e0001">Publication of <em>Transactions</em></p>

<div class="year">1866</div>
<p data-when="1866-01-05" data-id="p0001">John Skelton died</p>
<p data-when="1866" data-id="e0002">Boston meeting of Generals</p>

</div>

有没有办法在XSLT2中实现这一点:

  1. 允许包含未来的其他文件,
  2. 可以引入具有@when属性的其他元素
  3. 并考虑到这些项目尚未按日期在XML文件中进行排序?
  4. 我并不太担心输出的实际格式,但我正在努力弄清楚(a)合并,(b)分组,以及(c)排序所涉及的步骤第一名。我已尝试对文档进行分组

    <xsl:param name="lookup-documents" select="document('file1.xml'),document('file2.xml')"/>
    

    然后在for-each循环中使用基于dates的{​​{1}}键,但我可能完全走错了轨道并且没有真正显示的XSLT。

    如果可能的话,我更喜欢“拉”式XSLT2解决方案。非常感谢您提前提供任何帮助!

1 个答案:

答案 0 :(得分:0)

我会尝试将文件作为集合提取,然后使用for-each-group按年份进行分组和排序,然后我将组群推送到模板,以考虑元素的不同结构:< / p>

<?xml version="1.0" encoding="UTF-8"?>
<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="input-pattern" as="xs:string" select="'file*.xml'"/>
    <xsl:variable name="input-docs" select="collection(concat('.?select=', $input-pattern))"/>

    <xsl:output method="html" indent="yes"/>

    <xsl:template name="main">
        <div>
            <xsl:for-each-group select="$input-docs//*[@when]" group-by="xs:integer(substring(@when, 1, 4))">
                <xsl:sort select="current-grouping-key()"></xsl:sort>
                <div class="year">
                    <xsl:value-of select="current-grouping-key()"/>
                </div>
                <xsl:apply-templates select="current-group()">
                    <xsl:sort select="@when"/>
                </xsl:apply-templates>
            </xsl:for-each-group>
        </div>
    </xsl:template>

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

    <xsl:template match="born | died">
        <p data-when="{@when}" data-id="{../@id}">
            <xsl:apply-templates/>
        </p>
    </xsl:template>

    <xsl:template match="event">
        <p data-when="{@when}" data-id="{@id}">
            <xsl:apply-templates select="name/node()"/>
        </p>
    </xsl:template>

    <xsl:template match="hi">
        <em>
            <xsl:apply-templates/>
        </em>
    </xsl:template>
</xsl:stylesheet>

那样我得到了

<div>
   <div class="year">1782</div>
   <p data-when="1782" data-id="e0001">Publication of <em>Transactions</em></p>
   <p data-when="1782-05-01" data-id="p0001">John Skelton born</p>
   <div class="year">1866</div>
   <p data-when="1866" data-id="e0002">Boston meeting of Generals</p>
   <p data-when="1866-01-05" data-id="p0001">John Skelton died</p>
</div>

您需要更改我猜的群组项目的种类,目前尚不清楚如何确定具有完整日期的项目是否在@when中只有一年的项目之前结束。

该收集方法是特定于Saxon的(http://saxonica.com/html/documentation9.6/sourcedocs/collections.html),但我认为Altova和XmlPrime具有类似的URI收集语法,允许从模式中读取大量文件。