2

我有一堆具有固定的、基于国家/地区的命名模式的 XML 文件:、、、report_en.xmlreport_de.xmlreport_fr.xml现在我想编写一个 XSLT 样式表,通过document()XPath 函数读取这些文件中的每一个,提取一些值并生成一个 XML 文件带摘要。我的问题是:如何在不知道要处理的文件的确切名称的情况下迭代源文件?

目前我正计划生成一个包含所有文件名的辅助 XML 文件,并在我的样式表中使用辅助 XML 文件进行迭代。文件列表将使用一个小的 PHP 或 bash 脚本生成。有更好的选择吗?

我知道XProc,但目前对我来说不是一个选择。也许有人可以发布 XProc 解决方案。该解决方案最好包括工作流程步骤,其中报告以 HTML 格式下载并整理:)

我将使用 Saxon 作为我的 XSLT 处理器,所以如果有我可以使用的特定于 Saxon 的扩展,这些也可以。

4

2 回答 2

4

您可以使用Saxon 9.x 中实现的标准 XPath 2.x collection()函数

Saxon 实现允许在函数的 string-Uri 参数中使用搜索模式,因此您可以在目录的路径之后为任何文件名指定一个模式,该模式以任何文件名开头,report_然后是其他两个字符,然后以.xml.

示例

这个 XPath 表达式:

collection('file:///c:/?select=report_*.xml')

选择驻留在文件中的每个 XML 文档的文档节点,c:\该文件的名称以 0 或多个字符开头report_,然后以 . 结尾.xml

于 2010-06-01T16:51:12.343 回答
2

Dimitre 的答案在您的情况下看起来是最快的解决方案。但既然你问了,这里有一个 XProc 替代方案:

<p:declare-step version="1.0" xmlns:p="http://www.w3.org/ns/xproc" xmlns:c="http://www.w3.org/ns/xproc-step" exclude-inline-prefixes="#all" name="main">

<!-- create context for p:variable with base-uri pointing to the location of this file -->
<p:input port="source"><p:inline><x/></p:inline></p:input>

<!-- any params passed in from outside get passed through to p:xslt automatically! -->
<p:input port="parameters" kind="parameter"/>

<!-- configuration options for steering input and output -->
<p:option name="input-dir" select="'./'"/>
<p:option name="input-filter" select="'^report_.*\.xml$'"/>
<p:option name="output-dir" select="'./'"/>

<!-- resolve any path to base uri of this file, to make sure they are absolute -->
<p:variable name="abs-input-dir" select="resolve-uri($input-dir, base-uri(/))"/>
<p:variable name="abs-output-dir" select="resolve-uri($output-dir, base-uri(/))"/>

<!-- first step: get list of all files in input-dir -->
<p:directory-list>
    <p:with-option name="path" select="$abs-input-dir"/>
</p:directory-list>

<!-- iterate over each file to load it -->
<p:for-each>
    <p:iteration-source select="//c:file[matches(@name, $input-filter)]"/>
    <p:load>
        <p:with-option name="href" select="resolve-uri(/c:file/@name, $abs-input-dir)"/>
    </p:load>
</p:for-each>

<!-- wrap all files in a reports element to be able to hand it in to the xslt as a single input document -->
<p:wrap-sequence wrapper="reports"/>

<!-- apply the xslt (stylesheet is loaded below) -->
<p:xslt>
    <p:input port="stylesheet">
        <p:pipe step="style" port="result"/>
    </p:input>
</p:xslt>

<!-- store the result in the output dir -->
<p:store>
    <p:with-option name="href" select="resolve-uri('merged-reports.xml', $abs-output-dir)"/>
</p:store>

<!-- loading of the stylesheet.. -->
<p:load href="process-reports.xsl" name="style"/>

</p:declare-step>

例如,将上述内容存储为 process-reports.xpl。您可以使用 XMLCalabash (http://xmlcalabash.com/download/) 运行它。你可以像这样运行它:

java -jar calabash.jar process-reports.xpl input-dir=./ output-dir=./

上面的代码假设有一个 process-reports.xsl,它接受一个包含所有报告的文档,并对其进行一些处理。您也可以在纯 XProc 中进行处理,但您可能更喜欢这种方式。

您还可以将 p:xslt 步骤向上移动到 p:for-each 内(在 p:load 下方),这将导致 xslt 单独应用于每个报告。

祝你好运!

于 2011-11-11T07:42:40.087 回答