Nirmalya
Nirmalya

Reputation: 420

Looking for saxon:evaluate() example code

I have a transform.xsl file with will process a input.xml. But there is also an additional config.xml file which will define additional clauses. For e.g. this is the content of the config.xml.

<Location >
  <DisplayName>
     <Attribute1>ABC</Attribute1>
     <Attribute2>XYZ</Attribute2>
     <action>concat($Attribute1,$Attribute2)</action>
  </DisplayName>
</Location >

So when transform.xsl will encounter the DisplayName variable within the input.xml, then it will form the value with the RESULT of the action expression defined in the config.xml file. transform.xml will call the config.xml just to get the result. (The action can be modified by the end user and hence these are placed outside the xsl file, within the config.xml).

We are using saxon xml processor version 9 and xslt 2.0. So we need to use saxon:evaluate(). I tried to find more examples of saxon:evaluate(), but couldn't find it more. Can anyone show me some examples of how to use it?

Thanks in advance.

***** This is an edited query to highlight the need of saxon:evaluate *****

Upvotes: 1

Views: 1465

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167716

Here is an example to use an XSLT 3 processor supporting xsl:evaluate (https://www.w3.org/TR/xslt-30/#dynamic-xpath) (i.e. Saxon 9.8 or later with the commercial PE or EE editions or Altova 2017 or later) to process your "config" file:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:param name="config-url" as="xs:string">test2018121301.xml</xsl:param>
    <xsl:param name="config-doc" select="doc($config-url)"/>

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:key name="element" match="*" use="node-name()"/>

    <xsl:function name="mf:config-evaluation" as="item()*">
        <xsl:param name="config-doc" as="document-node()"/>
        <xsl:param name="element-name" as="xs:QName"/>
        <xsl:variable name="display" select="key('element', $element-name, $config-doc)/DisplayName"/>
        <xsl:evaluate xpath="$display/regex" with-params="map:merge($display!(* except regex)!map { QName('', local-name()) : string() })"/>
    </xsl:function>

    <xsl:template match="*[key('element', node-name(), $config-doc)]">
        <xsl:copy>
            <xsl:value-of select="mf:config-evaluation($config-doc, node-name()), ."/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

So with a config.xml

<Location >
    <DisplayName>
        <Attribute1>ABC</Attribute1>
        <Attribute2>XYZ</Attribute2>
        <regex>concat($Attribute1,$Attribute2)</regex>
    </DisplayName>
</Location >

this would transform an input sample with e.g.

<Root>
    <Items>
        <Item>
            <Data>data 1</Data>
            <Location>location 1</Location>
        </Item>
        <Item>
            <Data>data 2</Data>
            <Location>location 2</Location>
        </Item>
    </Items>
</Root>

into

<Root>
    <Items>
        <Item>
            <Data>data 1</Data>
            <Location>ABCXYZ location 1</Location>
        </Item>
        <Item>
            <Data>data 2</Data>
            <Location>ABCXYZ location 2</Location>
        </Item>
    </Items>
</Root>

That gives you a great flexibility to allow XPath expressions in the configuration files but as pointed out in https://www.w3.org/TR/xslt-30/#evaluate-effect, also is a security problem: "Stylesheet authors need to be aware of the security risks associated with the use of xsl:evaluate. The instruction should not be used to execute code from an untrusted source.".

As for using the saxon:evaluate function supported in older versions of Saxon not supporting the XSLT 3 xsl:evaluate instruction, a simple example is

<xsl:stylesheet 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="#all"
    version="2.0">

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

    <xsl:template match="example">
        <xsl:copy>
            <xsl:value-of select="saxon:evaluate(@expression, @foo, @bar)"/>
        </xsl:copy>
    </xsl:template>   

</xsl:stylesheet>

which transforms the input

<root>
    <example expression="concat($p1, $p2)" foo="This is " bar="an example."/>
    <example expression="replace(., $p1, $p2)" foo="\p{L}" bar="X">This is example 2.</example>
</root>

into the result

<root>
    <example>This is an example.</example>
    <example>XXXX XX XXXXXXX 2.</example>
</root>

Upvotes: 1

Evandro Teixeira
Evandro Teixeira

Reputation: 370

Try checking the xsl-attribute tag along with the xsl-value-of tag. If I get what you're asking for, you could probably read the config.xml using the transform.xsl (or a second xsl for an intermediate file) to set the text inside the regex tag to correspond to the value of an tag attribute within the xsl.

https://www.w3schools.com/xml/ref_xsl_el_attribute.asp

Also, check this tutorial for regex in XSLT 2, it may help:

https://www.xml.com/pub/a/2003/06/04/tr.html

Upvotes: 0

Related Questions