我有一堆XML文件,其中包含基于国家/地区的固定命名架构:report_en.xml
,report_de.xml
,report_fr.xml
等。现在我想编写一个XSLT样式表,通过document()
XPath函数读取每个文件,提取一些值并生成一个带摘要的XML文件。我的问题是:如何在不知道我将处理的文件的确切名称的情况下迭代源文件?
目前,我计划生成一个包含所有文件名的辅助XML文件,并使用样式表中的辅助XML文件进行迭代。将使用小型PHP或bash脚本生成文件列表。还有更好的选择吗?
我知道XProc,但是现在投入很多时间对我来说不是一个选择。也许有人可以发布XProc解决方案。优选地,该解决方案包括工作流程步骤,其中报告以HTML格式下载并整理:)
我将使用Saxon作为我的XSLT处理器,所以如果我可以使用Saxon特定的扩展,那么这些也可以。
答案 0 :(得分:4)
您可以使用标准的XPath 2.x collection() 功能, as implemented in Saxon 9.x
Saxon实现允许在函数的string-Uri参数中使用搜索模式,因此您可以在目录路径之后指定任何以report_
开头的文件名的模式然后具有另外两个字符,然后以.xml
结尾。
示例强>:
这个XPath表达式:
collection('file:///c:/?select=report_*.xml')
选择位于c:\
的文件中的每个XML文档的文档节点,其名称以report_
开头,然后包含0个或更多字符,然后以.xml
结尾。
答案 1 :(得分: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单独应用于每个报告。
祝你好运!