1

I have an XSL defining several functions.

I want to write Java code that takes the name of an XSL function (and a List of arguments) and runs that function (and, of course, binds the arguments to the function's formal parameters).

So far the only solution that I have is to generate, on the fly, XSL code with a main template that runs the chosen function. This is quite awkward. I am looking for a solution that lets me run a function directly thru the Saxon API.

0

4 Answers 4

1

The way the XPath Visualizer does this (regardless of the XSLT processor used), is to load the main XSL stylesheet as an XML document and dynamically modify just one select attribute with the necessary XPath expression.

Something like this:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:import href="yourTrueMainStylesheetModule"/>
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vResult" select="."/>

 <xsl:template match="/">
     <xsl:sequence select="$vResult"/>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
  1. Load the above stylesheet module as an XmlDocument.

  2. Issue: SelectNodes("/*/xsl:variable[@name='vResult']/@select")

  3. Using your DOM API modify the value of the selected attribute to the desired one, say: my:foo(1,2,3).

  4. Initiate the transformation using the already loaded (and dynamically modified stylesheet.

I have been using for years my XPath Visualizer 2 (for XSLT 2.0 -- unpublished) as a command-line - like interpreter for FXSL functions. I can freely write:

f:fold(f:mult(), 1, 1 to 4)

and get the correct result displayed:

24

Here is a screenshot of using the XPath Visualizer 2 as an FXSL interpreter:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

0

You probably can't directly, but couldn't you just have the main template having calling different templates based on one of your parameters, like a big switch statement.

Comments

0

There's an API that does this for XQuery (XQueryEvaluator.callFunction() in the s9api package), but nothing comparable for XSLT. It would probably be possible to achieve it by calling the right sequence of low-level internal methods, but you would probably have to study the source code to get it to work.

Comments

0

XSLT already has a feature to to run different instructions based on the contents of your input document: templates. I believe it is far too bothersome to mess with Saxon's internal API if you are already running an XSLT, just compile this large XSLT once and re-use it.

Just take the time to get to know XSLT and it's functional nature and convert those functions to templates with the right match expression.

I'll give an example. Let's suppose we have two input XMLs:

<myxml>
  <doctype>recipe</doctype>
  <descr>Bread 'n jam sandwich</descr>
  <var>jam</var>
  <var>bread</var>
</myxml>

<myxml>
  <doctype>shoppinglist</doctype>
  <descr>Monday</descr>
  <var>honey</var>
  <var>butter</var>
  <var>loaf of bread</var>
  <var>jam</var>
</myxml>

Now let's say that we want to generate HTMLs for these XMLs with the right formatting. The first XML should generate an HTML with "Recipe: " and a list of ingredients. The second should contain a shopping list.

Here's the XSLT to generate both:

<xsl:stylesheet version="2.0"    
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:saxon="http://saxon.sf.net/" 
    exclude-result-prefixes="xs saxon">

<xsl:output method="html" indent="yes"/>

<!-- Generate basic html -->
<xsl:template match="/">
        <html>
            <body><xsl:apply-templates /></body>
        </html>
</xsl:template>

<!-- Only call template doctype element, not for vars -->
<xsl:template match="myxml">
    <xsl:apply-templates select="doctype"/>
</xsl:template>

<xsl:template match="doctype[.='shoppinglist']">
    <h1>Shopping list for <xsl:value-of select="../descr"/></h1>
    <span><b>Stuff to bring:</b></span>
    <ul>
        <xsl:for-each select="../var">
            <li><xsl:value-of select="."/></li>
        </xsl:for-each>
    </ul>
</xsl:template>

<xsl:template match="doctype[.='recipe']">
    <h1>Recipe: <xsl:value-of select="../descr"/></h1>
    <span><b>Ingredients:</b></span>
    <ul>
        <xsl:for-each select="../var">
            <li><xsl:value-of select="."/></li>
        </xsl:for-each>
    </ul>
</xsl:template>

</xsl:stylesheet>

Now look at the match argument of the last templates. In this case I picked based on the contents of an element, but you could just use any XPath filter expression you like (i.e. to choose based on an XML argument).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.