XSLT 将两个输入文件处理成一个输出文件

XSLT Processing two input files into one output file

我正在尝试处理 xml 个文件(docbook 个文档)。文档中有重复的结构,我会从两个文档中提取,参数化,并存储在一个单独的文档中。

为了简化,这里有一个例子:

file1.xml:

<?xml version="1.0" encoding="UTF-8"?>
<input>
    <structure>foo</structure>
    <structure>bar</structure>
    <structure>baz</structure>
</input>

file2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<input>
    <structure>abc</structure>
    <structure>xyz</structure>
    <structure>123</structure>
</input>

这是我想要生成的首选输出。 output.xml:

<?xml version="1.0" encoding="UTF-8"?>
<output>
    <structure origin="doc1">foo</structure>
    <structure origin="doc1">bar</structure>
    <structure origin="doc1">baz</structure>
    <structure origin="doc2">abc</structure>
    <structure origin="doc2">xyz</structure>
    <structure origin="doc2">123</structure>
</output>

现在我不知道如何在 XSLT 中转换两个或多个文档(URI 可以硬编码)和一个附加参数(doc1、doc2 - 这些也可以硬编码)。

如有任何提示,我将不胜感激。

是转换 file1.xml 并仅使用 fn:doc() 读取 file2.xml,还是设置两个参数并读取两者是一个选择问题,但该概念适用于任何一种方式。加载完这两个文档后,您可以将 XPath 指向 /input/structure,然后应用模板。

使用 XSLT 2.0,您可以获得 base-uri() 并将其解析为要在 @origin:

中使用的文件名
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions" 
    exclude-result-prefixes="fn">
    <xsl:output indent="yes" />
    
    <xsl:param name="file1" select="'file1.xml'" />
    <xsl:param name="file2" select="'file2.xml'" />
    
    <xsl:template match="/">
        <output>
            <xsl:apply-templates select="(fn:doc($file1) | fn:doc($file2))/input/structure"/>
        </output>
    </xsl:template>
    
    <xsl:template match="structure">
        <xsl:copy>
          <xsl:attribute name="origin" select="concat('doc', replace(base-uri(), '.*(\d+).xml', ''))"/>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

如果您需要 XSLT 1.0,您可以将文件名作为参数发送:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions" 
    exclude-result-prefixes="fn">
    <xsl:output indent="yes" />
    
    <xsl:param name="file1" select="'file1.xml'" />
    <xsl:param name="file2" select="'file2.xml'" />
    
    <xsl:template match="/">
        <output>
            <xsl:call-template name="load-file">
                <xsl:with-param name="file" select="$file1"/>
            </xsl:call-template>
            <xsl:call-template name="load-file">
                <xsl:with-param name="file" select="$file2"/>
            </xsl:call-template>
        </output>
    </xsl:template>
    
    <xsl:template name="load-file">
        <xsl:param name="file"/>
        <xsl:apply-templates select="doc($file)/input/structure">
            <xsl:with-param name="file" select="$file"/>
        </xsl:apply-templates>
    </xsl:template>
    
    <xsl:template match="structure">
        <xsl:param name="file"/>
        <xsl:copy>
            <xsl:attribute name="origin">
              <xsl:value-of select="concat('doc', substring-after(substring-before($file, '.xml'), 'file'))"/>
        </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>