我需要使用中间XML文件进行多次XSLT转换。 (我需要文件,真实案例有点棘手,因为后面的步骤会加载中间文件)
first.xml ------------> intermediate.xml ------------> final.xml
first.xsl final.xsl
我想创建一个XProc pipleline。我曾尝试编写以下代码,但这给了我一个错误:
SCHWERWIEGEND: runxslt.xpl:26:44:err:XD0011:Could not read: intermediate.xml
17.05.2012 15:15:35 com.xmlcalabash.drivers.Main error
SCHWERWIEGEND: It is a dynamic error if the resource referenced by a p:document element does not exist, cannot be accessed, or is not a well-formed XML document.
17.05.2012 15:15:35 com.xmlcalabash.drivers.Main error
SCHWERWIEGEND: Underlying exception: net.sf.saxon.s9api.SaxonApiException: I/O error reported by XML parser processing file:/<somepath>/intermediate.xml:
/<somepath>/intermediate.xml (No such file or directory)
(其中SCHWERWIEGEND的含义类似于FATAL)显然文件intermediate.xml
尚未写入。
这是我用过的xpl
文件:
<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0">
<p:input port="source">
<p:document href="first.xml"/>
</p:input>
<p:output port="result" sequence="true">
<p:empty/>
</p:output>
<p:xslt name="first-to-intermediate">
<p:input port="stylesheet">
<p:document href="first.xsl"/>
</p:input>
<p:input port="parameters">
<p:empty/>
</p:input>
</p:xslt>
<p:store href="intermediate.xml" />
<p:xslt>
<p:input port="source">
<p:document href="intermediate.xml"/>
</p:input>
<p:input port="stylesheet">
<p:document href="final.xsl"/>
</p:input>
<p:input port="parameters">
<p:empty/>
</p:input>
</p:xslt>
<p:store href="final.xml"/>
</p:declare-step>
仅为了完整性:这些是转换文件:
source.xml:
<root>
<element name="A" />
</root>
first.xsl:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="root">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="element">
<intermediate name="A" />
</xsl:template>
</xsl:stylesheet>
final.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="root">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="intermediate">
<final name="A" />
</xsl:template>
</xsl:stylesheet>
以下是关于实际应用的说明(当然,上面是简化)。
companies.xml
index.xml
)。索引文件必须手动编辑。final.xml
)索引文件必须写入磁盘,我必须能够自己运行最后一步(这是一个不同的问题 - 我会为此写一个不同的管道)
companies.xml
的输出(步骤1)是可选的,它可以保存在内存中(但可能会变大)。
答案 0 :(得分:2)
我不确定为什么XMLCalabash在这里不起作用。我认为逻辑原则上应该工作,但显然XMLCalabash暂时将文件写入磁盘直到以后,甚至可能直到最后。不知道为什么。
但是有一个优雅的解决方案,因为您不需要在继续处理之前存储中间结果。事实上,最好不要使用硬编码的负载和存储。相反,请使用以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0">
<p:input port="source" sequence="true"/>
<p:input port="parameters" kind="parameter"/>
<p:output port="result" sequence="true"/>
<p:xslt name="first-to-intermediate">
<p:input port="stylesheet">
<p:document href="first.xsl"/>
</p:input>
</p:xslt>
<p:xslt>
<p:input port="stylesheet">
<p:document href="final.xsl"/>
</p:input>
</p:xslt>
</p:declare-step>
它需要对XMLCalabash稍有不同的调用。这样称呼:
java -jar Calabash.jar -i source=first.xml -o result=final.xml runxslt.xpl
使用-i将输入源绑定到输入文件,但是从脚本外部,因此不需要硬编码。与-o类似,您将输出重定向到目标文件。
我还在代码中添加了一个'参数'输入,它自动连接到p:xslt的输入。这样您就不需要指定p:empty的那些。它还允许将命令行中的参数值传递给那些xslt。
因为我删除了p:store,所以第二个p:xslt的'source'输入也不是必需的。第一个p:xslt的结果默认直接进入下一步的(主)源输入。
- 编辑 -
要详细说明我自己的评论,你可以做一个p:store 和重复使用第一个p:xslt的输出两次而不从磁盘加载中间文档。你可以这样做:
<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0">
<p:input port="source" sequence="false"/>
<p:input port="parameters" kind="parameter"/>
<p:output port="result" sequence="false"/>
<p:xslt name="first-to-intermediate">
<p:input port="stylesheet">
<p:document href="first.xsl"/>
</p:input>
</p:xslt>
<p:store href="intermediate.xml"/>
<p:xslt>
<p:input port="source">
<p:pipe step="first-to-intermediate" port="result"/>
</p:input>
<p:input port="stylesheet">
<p:document href="final.xsl"/>
</p:input>
</p:xslt>
</p:declare-step>
请注意,我在declare-step的输入和输出上将sequence = true更改为false。存储中间结果序列需要额外注意。这应该可以防止错误。
HTH!