【问题标题】:XSLT Processing two input files into one output fileXSLT 将两个输入文件处理成一个输出文件
【发布时间】:2021-12-30 14:38:35
【问题描述】:

我正在尝试处理 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 - 这些也可以硬编码)。

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

【问题讨论】:

    标签: xml xslt xslt-2.0


    【解决方案1】:

    您是转换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', '$1'))"/>
                <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>
    

    【讨论】:

    • 感谢@mads 的回答,并对假期的延误表示歉意。我理解您的回答,因为现在这两个文件都由xsl:copy-of 一个接一个地处理,并创建了一个输出。但我仍然不明白如何将origin 属性与doc1 / doc2 一起使用(这不应该是文件名)。抱歉,如果我的问题没有明确表达。
    • 哎呀,看起来我在输出中掩盖了那个重要的细节!我会更新答案。
    • 再次感谢您的快速回复。 origin-string 必须是单独的字符串。它与文件名没有任何共同之处,也不是从它派生的。这是我的主要问题。提取的结构应该用我自己定义的字符串来丰富,并且这个字符串(例如 doc1/doc2)应该是硬编码的。如果我没有清楚地沟通,再次抱歉。而XSLT2.0就完全够用了。
    • 同样的概念也适用。您可以为您的 @origin 值添加另一个参数,并且可以硬编码或从文件名派生。
    • 我已经更新了如何从文件名中获取数值的示例。
    猜你喜欢
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    • 2021-10-07
    • 2019-07-24
    • 1970-01-01
    • 2016-05-23
    相关资源
    最近更新 更多