XSLT - 参数作为一系列节点

时间:2014-05-19 22:13:11

标签: xml xslt saxon

我的目标是将多个文件的名称传递到XSLT中,并使用document($myFile)处理文件。我尝试使用撒克逊引擎在命令行上传递参数,并且不断抛出错误。

我知道我可以写出一个清单文件,在其中处理,然后在我完成后将其删除。但这似乎是一项额外的工作,可能会使事情进一步减缓。

当参数硬编码时,XSLT会工作......

<xsl:param name="PnewArticles" as="element()*">
    <file-name>XMLFile.XML</file-name>
    <file-name>XMLFile2.XML</file-name>
</xsl:param>

从命令行分配如下所示:

XSLT -s:Source.XML -o:outfileTest.xml -xsl:"test.xsl" newArticles='<file-name>XMLFile.XML</file-name>'

<!-- xslt param changed to this: -->
<xsl:param name="newArticles"/>

但是,它似乎是将其作为字符串值读取。印刷时看起来像这样(当然,失败了):

'&lt;file-name&gt;XMLFile.XML&lt;/file-name&gt;'

我在命令行上尝试了各种引号组合(单/双),但无济于事。还尝试添加as="element()*"和硬编码示例一样 - 但后来却大肆抱怨......

  XPTY0004: Required item type of value of variable $newArticles is node(); suplied value has item type xs:untypedAtomic

有什么想法吗?似乎应该可能。


示例文件

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:oasis="//OASIS//DTD XML Exchange Table Model 19990315//EN"
xmlns:mml="http://www.w3.org/1998/Math/MathML"     xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
exclude-result-prefixes="mml oasis dc content xsi">

<xsl:output method="xml" encoding="utf8"/>
<xsl:param name="newArticles"/>

<!-- When these are used they work -- the extra letter in front is just to silence -->
<xsl:param name="PnewArticles" as="element()*">
    <file-name>XMLFile.XML</file-name>
</xsl:param>
<xsl:variable name="VnewArticles" as="element()*">
    <file-name>XMLFile.XML</file-name>
</xsl:variable>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="skipDays">
    <xsl:copy-of select="."/>
    <myParam>
        <xsl:value-of select="$newArticles"/>
    </myParam>
    <xsl:apply-templates select="document($newArticles)" mode="addArticle"/>
</xsl:template>

<xsl:template match="front" mode="addArticle">
    <item>
        <xsl:text>NEW XML, Vol. </xsl:text>
        <xsl:value-of select="volume"/>
        <xsl:text>, No. </xsl:text>
        <xsl:value-of select="issue"/>
    </item>
</xsl:template>

<xsl:template match="body" mode="addArticle"/>
</xsl:stylesheet>

源文件

<?xml version="1.0"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<language>en-us</language>
<skipDays>
 <day>Saturday</day>
 <day>Sunday</day>
</skipDays>
</channel>
</rss>

XMLFILE

<?xml version="1.0" encoding="US-ASCII"?>
<!DOCTYPE article>
<article xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" dtd-version="2.2" xml:lang="EN" article-type="abstract">
  <front>
    <volume>17</volume>
    <issue>1</issue>
  </front>
  <body>
    <sec>
      <title>This is my Title</title>
      <p>This is a Paragraph</p>
    </sec>
  </body>
 </article>

3 个答案:

答案 0 :(得分:3)

尝试5分钟,我只能通过将XML放在单独的文件中,然后在参数中引用该文件(通过在命令行上将+添加到param名称)来使其工作。< / p>

注意:XML必须格式良好,因此如果您需要多个file-name元素,则必须将它们包装在根元素中,如:

<param>
    <file-name>XMLFile.XML</file-name>
    <file-name>other</file-name>
</param>

(我引用了http://www.saxonica.com/documentation/using-xsl/commandline.html

示例:

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="newArticles"/>

    <xsl:template match="/*">
        <test>
            <xsl:copy-of select="$newArticles"/>            
        </test>
    </xsl:template>

</xsl:stylesheet>

命令行(Windows)

java -cp "C:\apps\saxon\saxon9he.jar" net.sf.saxon.Transform ^
-s:"so_test.xsl" ^
-xsl:"so_test.xsl" ^
+newArticles="newArticlesParam.xml"

<强> newArticlesParam.xml

<file-name>XMLFile.XML</file-name>

<强>输出

<test>
   <file-name>XMLFile.XML</file-name>
</test>

答案 1 :(得分:2)

如果你真的想在命令行上提供词法XML,你必须使用saxon:parse()或XPath 3.0函数parse-xml()调用样式表来解析它,这两者都需要Saxon -PE或更高。但对我而言,这似乎很奇怪。

我认为最明显的解决方案是提供一个包含文件名列表的字符串值参数,用冒号或分号之类的东西分隔,然后在样式表中使用tokenize()来分隔出各个文件名,然后可以传递给document()。实际上,document()接受URI列表,因此您可以直接执行document(tokenize($param, ';'))

答案 2 :(得分:1)

一种可能的解决方案是将参数作为字符串读取并将其转换为节点集,方法是使用document()通过data URI scheme函数加载它,这样可以将嵌入的文档读取为如果他们是外部文件。这将允许您的字符串被解析,并且您可以将模板应用于它。

许多XSLT处理器都支持此功能,但这取决于解析器的支持。如果您的解析器不识别RFC 2397数据URI方案,它将无法工作。我在我的环境中测试了它,该环境由 Oxygen XML Editor 15.2 配置。

由于您使用的是XSLT 2.0,因此可以将节点集存储在变量中:

<xsl:variable name="string-as-document">
     <xsl:copy-of select="doc(concat('data:text/xml,',$newArticles))"/>
</xsl:variable>

您可以像以前一样打印结果节点:

<myParam>
    <xsl:apply-templates select="$string-as-document"/>
</myParam>

您可以阅读文件名并获取XMLFile文档的内容:

doc($string-as-document)

以下是完整的工作模板:

<xsl:template match="skipDays">
    <xsl:copy-of select="."/>
    <xsl:variable name="string-as-document">
        <xsl:copy-of select="doc(concat('data:text/xml,',$newArticles))"/>
    </xsl:variable>
    <xsl:apply-templates select="doc($string-as-document)" mode="addArticle"/>
</xsl:template>

使用RSS源和包含字符串newArticles的{​​{1}}参数运行Saxon XSLT处理器将产生:

"<file-name>XMLFile.XML</file-name>"