0

My Swift application produces an XMLDocument, which it then transforms using XSLT:

xmlDocument.object(byApplyingXSLTString: xsltString, arguments: nil)

In my XSLT stylesheet (xsltString), I’d like to access result tree fragments using XPath. This is not supported in XSLT 1.0; I tried using XSLT 2.0, but it doesn’t seem to be supported by Swift; specifying version="2.0" in the xsl:stylesheet element produces this error:

xsl:version: only 1.0 features are supported


I think I could use node-set from EXSLT. I’m not familiar with this, but I tried adding information about EXSLT to the xsl:stylesheet element. This seems to have no effect:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:exsl="http://exslt.org/common"
     extension-element-prefixes="exsl"
     version="1.0">

I get the following errors:

xmlXPathCompOpEval: function node-set not found
XPath error : Unregistered function


Is it possible to use XSL 2.0 or EXSLT in my situation, and how?

  • Consider to show us a minimal but complete sample you have tried. It is rather unusual that an XSLT 1.0 processor does not have support for `exsl:node-set` or a similar function in a proprietary namespace. So find out which XSLT processor Swift uses and there is hopefully a way to convert a result tree fragment into a node-set. – Martin Honnen Feb 11 '17 at 15:03
  • 1
    Try to run a simple test case like the stylesheet at http://xsltransform.net/3NSSEvF to your processor. – Martin Honnen Feb 11 '17 at 15:11
  • Thanks. Using the stylesheet you linked to, I saw that Swift is using libxslt. However, I’ve been unable to go further: I tried prefixing `node-set` with `libxslt:`, `xt:` and `saxon:`, as documented [here](http://xmlsoft.org/XSLT/html/libxslt-extra.html#xsltFunctionNodeSet), but always get the same error: `xmlXPathCompOpEval: function node-set not found`. – Philippe-André Lorin Feb 11 '17 at 16:46
  • 1
    So what does Swift output with the sample stylesheet for the `function-available('exsl:node-set')` check? – Martin Honnen Feb 11 '17 at 16:54
  • False, unfortunately: `` – Philippe-André Lorin Feb 11 '17 at 16:58
  • 1
    That result then indeed suggests that libxslt is used by Swift without support for `exsl:node-set`. So unless you can also call xsltproc/libxslt (with EXSLT support) from Swift as an external program it sounds as if there is indeed no way to have XSLT 1.0 with `exsl:node-set` use executed. – Martin Honnen Feb 11 '17 at 17:07

1 Answers1

1

Martin Honnen’s suggestions led me to consider using xsltproc rather than using Swift’s object(byApplyingXSLTString:arguments:) method.

Here’s what the result looks like.

Swift code

// Write XML to temporary file
xmlDocument.xmlString.write(to: temporaryXMLFileURL, atomically: false, encoding: String.Encoding.utf8)

// Use xsltproc to apply the XSLT transformation
let task = Process()
task.launchPath = "/usr/bin/xsltproc"
task.arguments = try [xsltFileURL.absoluteString, temporaryXMLFileURL.absoluteString]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let xsltResult = String(data: data, encoding: .utf8)!

XSLT code

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exslt="http://exslt.org/common"
    extension-element-prefixes="exslt"
    version="1.0">

    <xsl:variable name="stuff">
        ...
    </xsl:variable>

    <xsl:for-each select="exslt:node-set($stuff)/stuff">
        ...
    </xsl:for-each>

</xsl:stylesheet>