Is it possible to provide fallback behavior when a function implemented in an external XSLT object is not present (in XSLT 1.0)?
Right now, I have something similar to
<xsl:template match="an-element">
<xsl:value-of select="external-ns:ExternalFunction(.)" />
</xsl:template>
However, it's possible to generate content that makes sense if external-ns is not available, it just won't be as smart. So, I'd like to have something like
<!-- (pseudo) -->
<xsl:template match="an-element">
<xsl:try>
<xsl:value-of select="external-ns:ExternalFunction(.)" />
<xsl:catch>
<!-- do something else with the node -->
</xsl:catch>
</xsl:try>
</xsl:template>
I'm aware of xsl:fallback and element-available() but these seem to be only for elements, not functions. Is there any way to achieve this?
From http://www.w3.org/TR/xslt#function-function-available
Function: boolean function-available(string)
The argument must evaluate to a string
that is a QName. The QName is expanded
into an expanded-name using the
namespace declarations in scope for
the expression. The function-available
function returns true if and only if
the expanded-name is the name of a
function in the function library. If
the expanded-name has a non-null
namespace URI, then it refers to an
extension function; otherwise, it
refers to a function defined by XPath
or XSLT.
Related
I need to pass a node as a parameter to an XSL stylesheet. The issue is that the parameter gets sent as a string. I have seen the several SO questions regarding this topic, and I know that the solution (in XSLT 1.0) is to use an external node-set() function to transform the string to a node set.
My issue is that I am using eXist DB I cannot seem to be able to get its XSLT processor to locate any such function. I have tried the EXSLT node-set() from the namespace http://exslt.org/common as well as both the Saxon and Xalan version (I think eXist used to use Xalan but now it might be Saxon).
Are these extensions even allowed in the XSLT processor used by eXist? If not, is there something else I can do?
To reference or transform documents from the database, you should pass the path as a parameter to the transformation, and then refer to it using a parameter and variable
(: xquery :)
let $path-to-document := "/db/test/testa.xml"
let $stylesheet :=
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="source" required="no"/>
<xsl:variable name="error"><error>doc not available</error></xsl:variable>
<xsl:variable name="theDoc" select="if (doc-available($source)) then doc($source) else $error"/>
<xsl:template match="/">
<result><xsl:value-of select="$source"/> - <xsl:value-of select="node-name($theDoc/*)"/></result>
</xsl:template>
</xsl:stylesheet>
return transform:transform(<dummy/>,$stylesheet, <parameters><param name="source" value="xmldb:exist://{$path-to-document}"/></parameters>)
As per Martin Honnen's comments I don't think it is possible to pass an XML node via the <parameters> structure of the transform:transform() function in eXist. The function seems to strip away any XML tags passed to it as a value.
As a workaround I will wrap both my input XML and my parameter XML into a root element and pass that as input to the transform function.
I have an XSLT key defined. I need to access the key from within a for-each loop, where that loop is processing a node-set that is outside the scope of where the key was defined.
Snippet, where I've marked two lines, one which works and one which does not:
<xsl:value-of select="key('name', 'use')"/> <!-- works -->
<xsl:for-each select="$outOfScopeNodeSet">
<xsl:value-of select="key('name', 'use')"/> <!-- does not work -->
</xsl:for-each>
Is there a way to access the key from within the for-each loop?
XSLT 1.0, msxsl engine.
(I could not think of a reasonable way to provide a full working example for this. I'm also not sure of the correct terminology, such as "scope" - perhaps if I knew the correct terminology I'd be able to find my answer already. If the question is not clear enough please let me know and I'll try to edit it into better shape.)
In XSLT 1.0, keys do not work across documents. It seems that your $outOfScopeNodeSet contains a node-set whose root node is different from the root node of the XML document being processed (probably created by the exsl:node-set() function?) - while the key is supposed to fetch a value from the processed XML document.
To resolve this problem, you need to return the context back to the processed XML document before calling the key() function, for example:
<xsl:variable name="root" select="/" />
<xsl:for-each select="$outOfScopeNodeSet">
<xsl:variable name="use" select="some-value" />
<xsl:for-each select="$root">
<xsl:value-of select="key('name', $use)"/>
</xsl:for-each>
</xsl:for-each>
I need to generate the following output :
<x:Envelope xmlns:x='namespace1'>
<x:Root xmlns="namespace2">
<Header>
...
</Header>
</x:Root>
</x:Envelope>
I'm having trouble generating the default namespace for the x:Root element using xslt 1.0. I can get it to have no namespace ( but namespace2 will be specified on children of root - undesired behaviour ) or have it with a prefix :
<x:Root xmlns:x="namespace2">
but this fails schema validation. Any ideas ?
Edit : sorry for the ambiguous question and thanks for the answers. Root should be in namespace1 and Header should be in namespace2. However, the request is that namespace2 should not be declared in Header, but at Root level.
Regards,
It depends on how much of this is known statically. If you know everything statically, the literal result element
<x:Root xmlns="namespace2">..</x:Root>
will generate exactly what you want. In the more general case, you need to construct an element containing the required namespace node and then copy the namespace node:
<xsl:param name="ns">namespace2</xsl:param>
<xsl:variable name="temp">
<xsl:element name="dummy" namespace="{$ns}"/>
</xsl:variable>
...
<xsl:element name="Root">
<xsl:copy-of select="xx:node-set($temp)/namespace::*"/>
</xsl:element>
All so much easier in XSLT 2.0 with the xsl:namespace instruction.
You can't map two different namespaces to the same prefix "x". Instead, leave off the prefix for Root all together like this:
<Root xmlns="namespace2">
...
</Root>
I am using Saxon to perform a transformation of an XML document in my .NET application. I am passing in a parameter to my xslt document but I have no idea how to use it in my template.
Here is what I have done so far:
var zipcode = _db.AXCustomers.FirstOrDefault(x => x.ACCOUNTNUM == accNo).ZIPCODE;
transformer.SetParameter(new QName("CustomerZipCode"), new XdmAtomicValue(zipcode));
Then in my xslt document I am specifying the parameter like so:
<xsl:template match="/">
<xsl:param name="CustomerZipCode" />
But when I try to use the parameter, nothing appears. I am using it like so:
<xsl:value-of select="substring-before($CustomerZipCode, ' ')"/>
But nothing is output even though my zipcode does contain a value
You are using xsl:param inside a xsl:template element, it means that the param is for the template. The parameter you are passing from the .net code is a transformer parameter and related xsl:param must be placed at the top level of the stylesheet, into the xsl:stylesheet element.
Is it possible to get template name while inside template?
Example:
<xsl:template name="list">
<!-- Get name value (in this case "list") -->
</xsl:template>
As far as I am aware, neither XSLT 1.0 nor XSLT 2.0 offer such a feature.
As Martin says, there's probably no way to do this.
Even if such a capacity existed, surely using it couldn't be any simpler than just defining a variable with the value you want:
<xsl:template name="list">
<xsl:variable name="class" select="'list'" />
and then using that variable where you need it. This also has the benefit that you can change the template name without rewriting all your CSS, or change the class name without rewriting your XSLT.
One of the benefits of the fact that XSLT uses XML syntax is that it's easy to transform stylesheets. Modifying every named template to contain a variable holding the template name is dead easy.
#JLRishe's answer is a good approach. However, there is a trap. Any <xsl:param> must be declared before any <xsl:variable>.
This will not work:
<xsl:template name="foobarsnafu">
<xsl:variable name="foo" value="bar">
<xsl:param name="snafu"/>
But this will:
<xsl:template name="foobarsnafu">
<xsl:param name="snafu"/>
<xsl:variable name="foo" value="bar">
This might be a problem if, for example, you want the default value of your snafu <xsl:param> to be the value of your foo <xsl:variable>. The way around it would be to use <xsl:param> with a default value for your template name, i.e.:
<xsl:template name="foobarsnafu">
<xsl:param name="template_name" select="foobarsnafu"/>