We are having an issue in regards to our system upgrade. As a result of the upgrade we have to update our XSLT code to ensure its compatible with version XSLT 2.0. The below function worked fine in XSLT 1.0 but no longer functions following the upgrade:
<xsl:if test="ACADEMIC_PROGRAM_START_DATE <= SYSDATE_90">
We can get the function to work if we remove _90 however we need to ensure the criteria is included.
Does anyone have any ideas on how to rewrite this in XSLT version 2.0?
Many thanks
You haven't said whether you're running the code in 1.0-compatible mode, that is, have you changed xsl:stylesheet/#version to say 2.0? If you leave it set to 1.0 then a 2.0 processor interprets this as a request for backwards compatible behaviour.
You also haven't said what's in the two elements ACADEMIC_PROGRAM_START_DATE and SYSDATE_90 that you are comparing. XSLT 1.0 will attempt to treat both values as numeric, whereas XSLT 2.0 will compare them as strings. If you want a numeric comparison, then either run in backwards compatible mode, or convert either or preferably both values to numbers, that is:
xsl:if test="number(ACADEMIC_PROGRAM_START_DATE) <= number(SYSDATE_90)
Alternatively, depending on the format of these elements, it might make more sense to convert them to xs:date values.
Your reference to it working if you drop the "_90" is pretty meaningless unless we know the relationship between elements SYSDATE and SYSDATE_90.
Related
As far as I understand, we can use 1 XSLT to read multiple xml files as inputs. May I know if there's a way to read multiple inputs and produce multiple outputs as well (within 1 XSLT)?
Yes, this is a standard feature of XSLT 2.0, with the xsl:result-document instruction.
Some XSLT 1.0 processors offer similar capabilities using vendor extensions, but it's not possible within the W3C standard.
We've been pulling our hair out just trying to just trying to get a basic example of the XSLT replace function to work.
I'm leaving this text in tact for context, but you may want to skip to the update
We're using Mirth to pull in HL7 messages. We're unsure whether this supports XSLT version 2, but we believe it uses SAXON - http://saxon.sourceforge.net/, which purportedly does support XSLT2 and hence the replace function.
In any case, we tried using XSLTCake to try and get even a demo replacement to work, to no avail. We've seen this either referenced as replace or fn:replace as well as a couple other suggestions using other libraries.
If XSLT2 isn't supported by Mirth, we would need a workaround for XSLT1. We found one here: XSLT string replace - but have been unable to get this to work either.
This is a tough to get down to a single question as I'm asking alot, but here goes... Can anyone provide a working example of performing a regex replacement in an XSLT? Preferably one that will run in an online parser for reference.
Here's a sample - which apparently should work.1
Update
Thanks to Michael Kay for providing code below to determine XSLT version.
<!--Transformed using 1.0 provided by Apache Software Foundation (Xalan XSLTC)-->
So It turns out we were all wrong about Mirth using SAXON and hence supporting XSLT2. I'll update with our attempt at implementing the version 1 workaround.
First find out which XSLT processor you are using. This is straightforward: insert this
<xsl:comment>Transformed using <xsl:value-of select="system-property('xsl:version')"/> provided by <xsl:value-of select="system-property('xsl:vendor')"/></xsl:comment>
into your stylesheet to output a comment in your result document.
Once you know what programming language you are using, you can start thinking about writing code.
In a reply to a post I made the other day Dimitre pointed out, correctly of course, that I had given an XSLT 2 answer to an XSLT 1 question.
However, he also upbraided me for posting an answer that hadn't been tested. I had in fact tested it and even though the version attribute was set to "1.0" and I used an XSLT 2 replace function every worked with errors or warnings.
So this raised a question - what does the version attribute mean if it doesn't restrict the language to a particular version?
I did try reading the w3 spec but my eyes started to bleed.
FWIW: I use Oxygen and Saxon 9.3 EE
Firstly, the XSLT specification says how an XSLT processor interprets the version attribute, but it doesn't constrain what pieces of software other than an XSLT processor do with it. For example, an IDE (such as XML Spy) might look at the version attribute and use it to decide whether to launch an XSLT 1.0 or XSLT 2.0 processor. Once an XSLT 1.0 or 2.0 processor is launched, its behaviour is controlled by the relevant spec.
What an XSLT 1.0 processor does with the version attribute is defined by the XSLT 1.0 specification; what a 2.0 processor does is defined by the XSLT 2.0 spec.
The XSLT 1.0 spec says that if the version is NOT 1.0, the processor runs in forwards compatibility mode. This basically means that it does its best to ignore constructs that aren't defined in the 1.0 spec. So if your stylesheet says version="2.0", and you run it with a 1.0 processor, then an attribute that is new in 2.0 like xsl:sort/#collation will be ignored. An instruction that isn't recognized causes a failure only if it is actually executed, and if it has no xsl:fallback child instruction to give a fallback behaviour for 1.0 processors. The design principle is that using 2.0 constructs should not cause a 1.0 processor to fail; wherever possible, it should cause it to run with some kind of fallback behaviour.
The XSLT 2.0 specification (which controls the behaviour of a 2.0 processor) distinguishes verion<2.0, version=2.0, and version>2.0. When version<2.0, the processor runs in "backwards compatible mode". This doesn't mean that 2.0 constructs are rejected; rather it means that 1.0 constructs are executed with semantics as close as possible to those defined in the 1.0 specification. For example, all arithmetic is carried out as double floating point, even if the operands are decimals. When version>2.0, the processor runs in forwards compatible mode, which is very like forwards compatible mode in the 1.0 specification: it means that if you use XSLT 3.0 constructs, the processor will do its best to ignore them or execute fallback instructions.
I also use oXygen for both XSLT 1.0 and 2.0 development. If I try to use an XSLT 2.0 function in a stylesheet that has a version number of 1.0, oXygen will warn me.
Check your oXygen settings and make sure you're validating XSLT 1.0 with a 1.0 processor:
Notice I'm validating 1.0 with Xalan.
Also, I always test my 1.0 answers with a 1.0 processor; usually with both Saxon 6.5.5 and Xalan.
I'm trying to generate an XML file with the my machine's hostname in some arbitrary element or attribute, e.g.
<hostname>myHostname</hostname>
I'm using Saxon 9.2. I can think of three ways to do this:
Read and parse /etc/sysconfig/network (I'm using Fedora)
Read the environment variable (as in $ echo $HOSTNAME)
Pass the hostname to saxon and then use somehow dereference a variable (not sure if this is possible)
Are any of these possible? I think the first option is most likely to work, but I think the other two options will produce less verbose XSLT.
I also have a related question:
Currently, I have an XSLT and source XML file that generates a bunch of XML files, it works like I expect it to. Is there anyway I can selectively generate one file per host? That is, I want to say 'if the hostname is myHostName then generate the XML file for myHostName, if the hostname is myOtherHostName then generate the XML file for myOtherHostName'.
I ask this because I'm trying to configure a large number of machines and if I could drop an XSLT and XML file on each and then call the same command on every machine and hten get the right XML on each it would be really convienent.
You should pass a parameter to your xslt when "calling" it. I think this is the most robust solution.
So at the top of your stylesheet you would have something like :
<xsl:param name="hostName"/>
Then you can use it in your .xslt via the usual notation : $hostName etc.
You just then need to pass those parameters when calling the xslt processor. Depending on how you use it this may vary.
You can generate an XML file containing all needed parameters, then you can either pass it as parameter to the transformation (refer to the code samples to see examples of how this is done with Saxon).
Here is a link that can help: https://www.saxonica.com/html/documentation/javadoc/net/sf/saxon/expr/instruct/GlobalParameterSet.html
Or simpler, save this XML file in the file system and just pass as parameter to the transformation the file path and name.
Then inside the transformation, use the standard XSLT function document() to load the XML document that contains the parameters.
Even further simplification is possible, if this file can be stored at a location that has exactly the same path on all machines. Then this avoids the need to pass this filepath as parameter to the transformation.
There are many possible ways of doing this: passing in parameters, reading the configuration file using the unparsed-text() function, calling an extension function.
But perhaps the most direct way is that Saxon 9.3 implements the new XPath 3.0 function get-environment-variable(). Support for XPath 3.0 requires Saxon-PE or higher.
(XPath 3.0 is of course still a draft and subject to change. In fact it has changed since Saxon 9.3 was released - the function has been renamed environment-variable()).
I am trying to execute the string contained in an XSL variable.
Umbraco has hooks for several Exslt pieces, but it seems the Exslt.dyn (Exslt.dynamic) is not one of them.
How do you add it in? Acceptable methods (in order of preference:
Writing your own XSLT extension (possibly using existing Umbraco code for Exslt Dynamic).
Uploading the XSL from http://www.exslt.org/dyn/functions/evaluate/index.html into Umbraco.
Modifying the Umbraco source to add it (possibly using existing Umbraco code for Exslt Dynamic).
The reason I mention Exslt Dyanmic is because some Umbraco XSLT sources show a reference that I am assuming existing in some versions of Umbraco. I cannot find it in the source code, however. (Example: the XSL sources pasted in here: http://our.umbraco.org/projects/starter-kits/business-website-starter-pack/general-%28bugs,-feedback,-feature-requests%29/8085-Changing-the-first-day-to-fx-monday)
Very few XSLT processors implement dyn:evaluate() and Umbraco obviously doesn't use one of these.
There isn't anything you can do in this case.
Ask the Umbraco developers to incorporate an XSLT 2.0 processor in the future -- XSLT 2.0 has a native <xsl:function> instruction for defining functions that can be referenced in any XPath expression.
Not sure if this will work, but if Exslt.ExsltDynamic is supported out of the box in the .Net implementation of XSLT, this should work. In your stylesheet add the namespace xmlns:Exslt.ExsltDynamic="urn:Exslt.ExsltDynamic" (as in the example you linked) and in the exclude-result-prefixes property add Exslt.ExsltDynamic to make it accessible in your xslt file.
Then you can just do something like in your template.