XSLT - Parameter as a series of nodes

此生再无相见时 提交于 2019-12-06 08:32:46

If you really want to supply lexical XML on the command line, you will have to parse it within the stylesheet using a call on saxon:parse() or the XPath 3.0 function parse-xml(), both of which need Saxon-PE or higher. But to me it seems an odd thing to do.

I would have thought the most obvious solution is to supply a string-valued parameter containing the list of filenames, separated by something like colon or semicolon, and then use tokenize() within the stylesheet to separate out the individual filenames, which can then be passed to document(). In fact document() accepts a list of URIs, so you could directly do document(tokenize($param, ';')).

Trying for 5 minutes, I could only get it to work by putting the XML in a separate file and then referencing that file in the param (by adding + to the param name on the command line).

Note: The XML has to be well formed so if you wanted multiple file-name elements, you'd have to wrap them in a root element like:

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

(I referenced http://www.saxonica.com/documentation/using-xsl/commandline.html)

Example:

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>

Command Line (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>

Output

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

A possible solution is to read a parameter as a string and convert it to a node-set is by loading it via the document() function using a data URI scheme, which allows embedded documents to be read as if they were external documents. That will allow your string to be parsed, and you can apply templates to it.

This is supported by many XSLT processors, but it depends on support by the parser. If your parser doesn't recognize RFC 2397 data URI schemes, it will not work. I tested it in my environment which was configured by Oxygen XML Editor 15.2.

Since you are using XSLT 2.0, you can store the node-set in a variable:

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

You can print the result node, as before:

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

And you can read the file name and get the contents of your XMLFile document:

doc($string-as-document)

Here is the full working template:

<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>

Running a Saxon XSLT processor with your RSS source and a newArticles parameter containing the string "<file-name>XMLFile.XML</file-name>" will produce:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     version="2.0">
   <channel>
      <language>en-us</language>
      <skipDays>
         <day>Saturday</day>
         <day>Sunday</day>
      </skipDays>
      <item>NEW XML, Vol. 17, No. 1</item>
   </channel>
</rss>
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!