how to convert xslt version 2.0 to version 1.0 - xslt

i am using xslt document which uses xpath version 2 functions. I only have xalan 2.6 jar which has xslt 1.0 processor, its a constraint i cannot change it..please help me if there are any tools that convert xpath 2.0 functions to 1.0
<xsl:variable name="var1_ClinicalDocument" as="node()?" select="ns0:ClinicalDocument"/>
<DSMessage>
<DSPatient>
<xsl:for-each
select="$var1_ClinicalDocument[fn:exists(ns0:id/#root)]">
<Source>
<xsl:sequence select="fn:string(ns0:id/#root)"/>
</Source>
</xsl:for-each>
<Demographics>
<xsl:for-each select="($var1_ClinicalDocument/ns0:recordTarget/ns0:patientRole/ns0:id)[fn:exists(#extension)]">
<externalID>
<xsl:sequence select="fn:string(#extension)"/>
</externalID>
</xsl:for-each>
<xsl:for-each select="($var1_ClinicalDocument/ns0:recordTarget/ns0:patientRole/ns0:patient/ns0:name/ns0:given/node())[fn:boolean(self::text())]">
<firstName>
<xsl:sequence select="fn:string(.)"/>
</firstName>

Here is a mapping of the XPath 2.0 functions in question:
XPath 2.0 XPath 1.0 Xalan-Java XSLT-C
fn:exists() string-length(concat(., ) ) XPath 1.0 XPath 1.0
fn:string() string() XPath 1.0 XPath 1.0
fn:boolean() boolean() XPath 1.0 XPath 1.0
EXSLT, XSLTSL, FXSL, and XPath algorithms can fill in most of the remaining functionality.
XPath 2.0 FXSL XSLTSL EXSLT XPath 1.0
fn:max maximum math:max
fn:max dyn:max
fn:min minimum math:min
fn:min dyn:min
fn:sum sum math:sum sum
fn:sum dyn:sum
fn:avg sum div count
fn:floor floor
fn:ceiling ceiling
fn:round round
fn:abs math:abs
fn:collection foldl
op:concatenate append
fn:doc document
fn:count count
fn:not not
fn:true true
fn:false false
fn:boolean boolean
fn:upper-case str:to-upper
fn:lower-case str:to-lower
fn:substring substring
fn:string-length string-length
fn:normalize-space normalize-space
fn:translate translate
fn:concat str:concat concat
fn:substring-before substring-before
fn:substring-after substring-after
fn:reverse str:backward
fn:insert-before str:insert-at
fn:matches str:string-match
fn:tokenize str:tokenize
fn:resolve-uri uri:resolve-uri
fn:distinct-values set:distinct
op:union |
op:intersect set:intersection
op:except cmp:diff set:difference
op:is-same-node cmp:cmp
fn:position node:xpath position
fn:last last
fn:data node:type
fn:lang lang
fn:current-dateTime date:date-time
fn:dateTime dt:format-date-time date:format-date
fn:year-from-date dt:get-xsd-datetime-year date:day-in-year
fn:month-from-dateTime dt:get-xsd-datetime-month date:month-name
fn:day-from-dateTime dt:get-xsd-datetime-day date:day-name
fn:hours-from-dateTime dt:get-xsd-datetime-hour date:hour-in-day
fn:minutes-from-dateTime dt:get-xsd-datetime-minute date:minute-in-hour
fn:seconds-from-dateTime dt:get-xsd-datetime-second date:second-in-minute
fn:timezone-from-dateTime dt:get-xsd-datetime-timezone
if (...) then (...) else(...) $dynamic[$var] | $default[not($var)]
References
Xalan-Java Extensions Library
XSLTC Extensions Library
FXSL
XSieve
XSLTSL
Common XSLT Utilities
Web XSLT: XSLT and JavaScript code intended mostly for manipulating MathML and OpenMath.
XSLT Stylesheets for MathML
XPath Wikibook
XQuery 1.0 and XPath 2.0 Functions and Operators (Second
Edition)
XQuery 1.0 and XPath 2.0 Formal Semantics (Second Edition)
XQuery 1.0 and XPath 2.0 Data Model (XDM) (Second Edition)

I will try, but this is untested:
<xsl:variable name="var1_ClinicalDocument" select="ns0:ClinicalDocument"/>
<DSMessage>
<DSPatient>
<xsl:for-each
select="$var1_ClinicalDocument[ns0:id/#root]">
<Source>
<xsl:value-of select="ns0:id/#root"/>
</Source>
</xsl:for-each>
<Demographics>
<xsl:for-each select="($var1_ClinicalDocument/ns0:recordTarget/ns0:patientRole/ns0:id)[#extension]">
<externalID>
<xsl:value-of select="#extension"/>
</externalID>
</xsl:for-each>
<xsl:for-each select="($var1_ClinicalDocument/ns0:recordTarget/ns0:patientRole/ns0:patient/ns0:name/ns0:given/node())[self::text()]">
<firstName>
<xsl:value-of select="."/>
</firstName>
Basically the use of fn:exists, fn:string and fn:boolean can be replaced, of course if there is use of XPath/XSLT 2.0 stuff like tokenize or for-each-group you need more work and maybe Xalan specific extension functions.

This should be a not-bad translation:
<xsl:variable name="var1_ClinicalDocument" select="ns0:ClinicalDocument"/>
<DSMessage>
<DSPatient>
<xsl:for-each select="$var1_ClinicalDocument[ns0:id/#root]">
<Source>
<xsl:value-of select="ns0:id/#root"/>
</Source>
</xsl:for-each>
<Demographics>
<xsl:for-each select=
"($var1_ClinicalDocument/ns0:recordTarget
/ns0:patientRole/ns0:id)[#extension]">
<externalID>
<xsl:value-of select="concat(#extension, ' ')"/>
</externalID>
</xsl:for-each>
<xsl:for-each select=
"$var1_ClinicalDocument/ns0:recordTarget/ns0:patientRole
/ns0:patient/ns0:name/ns0:given/text()">
<firstName>
<xsl:value-of select="."/>
</firstName>
</xsl:for-each>
</Demographics>
</DSPatient>
</DSMessage>

Related

string-to-codepoints(string) equivalent in XSLT 1.0

I need to get ASCII value of character and Convert ASCII code back to character if it satisfies certain conditions.
So I came across these functions:
string-to-codepoints(string)
and
codepoints-to-string((int,int,...))
provided in XSLT 2.0 (Or Rather XPATH 2.0) But unfortunately I need to use XSLT 1.0 for this task.
So My question is
Is there any equivalent of these functions in XSLT 1.0? If not Can we design it?
Can experts here help me in that?
Thanks in advance
It is possible to replace all characters with codepoints above 255 by "?" using pure XSLT 1.0 without extensions.
Define a variable
<xsl:variable name="upto255">
!"#$%.../01234...ABC...abc...úûüýþÿ</xsl:variable>
whose value is a string containing all the characters in the range 0..255 that are legal in XML.
Then use the double-translate trick:
<xsl:variable name="above255" select="translate($input, $upto255, '')"/>
This variable is a string containing all the non-Latin-1 characters present in the input string. Then use the recursive template
<xsl:template name="pad">
<xsl:param name="char"/>
<xsl:param name="count"/>
<xsl:choose>
<xsl:when test="$count=0"/>
<xsl:otherwise>
<xsl:value-of select="$char"/>
<xsl:call-template name="pad">
<xsl:with-param name="char" select="$char"/>
<xsl:with-param name="count" select="$count - 1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
to create a string of the right number of question marks:
<xsl:variable name="qqq">
<xsl:call-template name="pad">
<xsl:with-param name="char" select="'?'"/>
<xsl:with-param name="count" select="string-length($above255)"/>
</xsl:call-template>
</xsl:variable>
and then do the substitution:
<xsl:value-of select="translate($input, $above255, $qqq)"/>
But of course since you are in Java there is no excuse for writing all this XSLT 1.0 code which could be replaced by a single line of code if you switched to an XSLT 2.0 processor such as Saxon.
Based on your comments you want to perform a string replacement based on a regular expression. If you are using Java and Xalan then I think you can use e.g. java:replaceAll($inputString, $regExpPattern, $replacementString) to call the Java String method replaceAll, here is a simple example
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://xml.apache.org/xalan/java"
version="1.0"
exclude-result-prefixes="java">
<xsl:template match="/">
<xsl:value-of select="java:replaceAll('abc-123-def','\w+', '?')"/>
</xsl:template>
</xsl:stylesheet>
which outputs ?-?-? for me with Xalan.
On the other hand if you are using Java then you should consider moving to Saxon 9 and XSLT 2.0 as that way you can use the XPath 2.0 replace function (replace('abc-123-def', '\w+', '?')) without any need for extensions.
I am not sure what that has to do with your original question about string-to-codepoints and the ASCII code of characters.

How to select and separate comma values in XSLT

My XML:
<geoCode>36.113,-114.925</geoCode>
I need a XSLT which converts the above XML to below XML format:
<geoCode>
<lati>36.113</lati>
<longi>-114.925</longi>
</geoCode>
You can use the following code in your template:
<xsl:template match="...">
<xsl:variable name="geo-code-split" select="tokenize(geoCode, ',')" />
<geoCode>
<lati><xsl:value-of select="$geo-code-split[1]" /></lati>
<longi><xsl:value-of select="$geo-code-split[2]" /></longi>
</geoCode>
</xsl:template>
P.S.: This solution uses XSLT 2.0. For XSLT 1.0, you can use the string-before() and string-after() functions.
<geoCode>
<lati>
<xsl:value-of select="substring-before(geoCode,',')"/>
</lati>
<longi>
<xsl:value-of select="substring-after(geoCode,',')"/>
</longi>
</geoCode>
This is with substring-before and substring-after.

schematron localfunctions gives error

I have schematron file which contains xsl function.
I get this error : "the function functionName was not found in namespace localFunctions"
Here is my schematron codes:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fct="localFunctions"
queryBinding="xslt2" >
<ns prefix="gl-plt" uri="http://www.xbrl.org/int/gl/plt/2010-04-16" />
<ns prefix="gl-cor" uri="http://www.xbrl.org/int/gl/cor/2006-10-25" />
<ns prefix="gl-bus" uri="http://www.xbrl.org/int/gl/bus/2006-10-25" />
<ns prefix="xbrli" uri="http://www.xbrl.org/2003/instance" />
<ns prefix="edefter" uri="http://www.edefter.gov.tr" />
<ns prefix="fct" uri="localFunctions" />
<title></title>
<!-- <gl-cor:accountingEntries> elemanı bir <gl-cor:entityInformation> elemanı içermelidir. -->
<pattern id="accountingentries">
<rule context="/edefter:defter/xbrli:xbrl/gl-cor:accountingEntries">
<let name="accoundMainIdList" value="gl-cor:entryHeader/gl-cor:entryDetail[1]/gl-cor:account/normalize-space(gl-cor:accountMainID)"/>
<assert test="fct:isSorted($accoundMainIdList)">Büyük defterde hesaplar, ana hesap numarası bazında sıralı olmalıdır.</assert>
</rule>
</pattern>
<xsl:function name="fct:isSorted" as="xs:boolean">
<xsl:param name="accoundMainIdList" as="xs:string*"/>
<xsl:variable name="sortedAccountMainIdList" as="xs:string*">
<xsl:for-each select="$accoundMainIdList">
<xsl:sort/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="s1">
<xsl:value-of select="string-join($accoundMainIdList,'|')"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:value-of select="string-join($sortedAccountMainIdList,'|')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$s1 = $s2">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</schema>
Why isSorted xsl function not found in namespace ?
I'm assuming that you are aware that the conventional method of running Schematron schemas is to process them using XSLT to generate an XSLT stylesheet which can be executed against your XML instance.
Looking on github, the XRouters Schematron projects is using a very old version of the standard XSLT stylesheets from http://www.schematron.com/. These are XSLT 1.0 stylesheets and are not capable of generating XSLT 2.0 stylseheets.
The xsl:function element you are trying to use is part of XSLT 2.0. Given that your tool is generating XSLT 1.0 it seems very unlikely that your XSLT 2.0 function will operate.
If you want to try an approach that may be more successful, may I suggest that you obtain a copy of Saxon HE (the .net version) from http://saxon.sf.net/. You can then build a simple set of XSLT transforms that will give you more of a chance of getting what you want.
I think #Nic's answer is in the right direction, but missed the mark.
Although the standard way of running schematron schemas against XML documents is to convert them to XSLT, that approach has a number of drawbacks (speed and having validation report you can process programmatically are two primary ones).
The XRouter SchemaTron is a native .NET implementation of ISO schematron. It doesn't convert the schematron schemas to XSLT stylesheets -- it parses them in memory and then processes each pattern/rule/assert to detect violations.
The problem is certainly rooted in a lack of XSLT2 support, but is not related at all to XSLT schematron stylesheets (they arent used, and are included in the project only as reference). Schematron specification doesn't require XSLT2 (or XPATH2) -- it leaves the query language to the schematron rules file. The branch you were using was probably the one delivering XPATH2 support via "Lightweight XPath2 for .NET", which doesn't support XSLT2.
I recommend using the branch of the project integrated with XmlPrime, with supports XSLT2. We're using that version with great success.

Consequence of xsl:value-of as child of xsl:variable

What is the differences between these three blocks in terms of side-effects when $world is a list of elements? I am seeing a different behaviour between the first and the third and cannot get my head around it.
<xsl:variable name="hello" select="$world" />
<xsl:variable name="hello">
<xsl:value-of select="$world" />
</xsl:variable>
<xsl:variable name="hello">
<xsl:choose>
<xsl:when test="$something=true()">
<xsl:value-of select="$world" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$world" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Edit 1: I want to process $hello in a <xsl:for-each select="$hello">. With the third block above the <xsl:for-each> has only one item to process that contains the joined contents of $world. Why is that?
The first xsl:variable will have the same value and type as $world. The second is a result tree fragment with a single text node of the string value of $world. The third is also a result tree fragment with a single text node.
I guess you want either
<xsl:variable name="hello" select="if (condition) then $world else $foo"/>
in XSLT 2.0 and then your for-each select="$hello" would work as you want or in XSLT 1.0 plus EXSLT common you want
<xsl:variable name="hello">
<xsl:choose>
<xsl:when test="condition">
<xsl:copy-of select="$world"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$foo"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:for-each select="exsl:node-set($hello)/*">...</xsl:for-each>
While all three examples are valid in both XSLT 1.0 and XSLT 2.0, the way the semantics are described is very different in the two specs; also when $value contains multiple nodes, the effect of <xsl:value-of select="$value"/> depends on whether the stylesheet specifies version="1.0" or version="2.0".
The main things to remember, that apply to both versions, are (a) xsl:value-of creates a text node by converting whatever it selects into a string, and (b) xsl:variable with contained instructions (and no "as" attribute) creates a new tree rooted at a document node.
<xsl:variable name="hello">
<xsl:choose>
<xsl:when test="$something=true()">
<xsl:value-of select="$world" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$world" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
I want to process $hello in a
<xsl:for-each select="$hello">. With
the block above the <xsl:for-each> has
only one item to process that contains
the joined contents of $world. Why is
that?
The variable named $hello contains the string value of $world. This is by definition how <xsl:value-of> behaves in XSLT 1.0.
You haven't shown us how $world is defined, but if it contains a single element or a whole document tree, then (again) by definition, its string value is the concatenation (in document order) of all of its descendents - text nodes.
This is exactly what you are seeing.
The situation will be different if insead of:
<xsl:value-of select="$world" />
you use:
<xsl:copy-of select="$world" />
This copies the whole subtree whose root is the element (or root node / in the case when $world contains a complete document) contained in $world.
However, in XSLT 1.0 this creates the so called RTF (Result Tree Fragment) and by definition one cannot use an RTF as a location step in XPath (1.0) expression.
One must first convert this to a regular tree (document node) using a vendor-supplied extension function that most often has the local-name node-set but is in a vendor-specific namespace.
A typical example is:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vWorld" select="/*"/>
<xsl:template match="/">
<xsl:variable name="vrtfHello">
<xsl:copy-of select="$vWorld"/>
</xsl:variable>
<xsl:variable name="vHello" select=
"ext:node-set($vrtfHello)/*"/>
<xsl:copy-of select="$vHello/*[3]"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
the result is (as expected):
<num>03</num>
Here we use the ext:node-set() extension function in the namespace "http://exslt.org/common" as specified by the EXSLT vendor-independent library. Most XSLT 1.0 processors support EXSLT and using its node-set() extension function doesn't decrease the degree of portability of an XSLT application accross all such XSLT processors.

Replacement for saxon:if and saxon:before functions in xslt 2.0

Is there any replacement for saxon:if
and saxon:before functions in XSLT 2.0 / XPath 2.0?
I have code like this:
<xsl:variable name="stop"
select="(following-sibling::h:h1|following-sibling::h:h2)[1]" />
<xsl:variable name="between"
select="saxon:if($stop,
saxon:before(following-sibling::*, $stop),
following-sibling::*)" />
Idea is that between variable should contain all elements between current node and next h1 or h2 element (stored in stop variable), or all remaining elements, if there is no next h1 or h2.
I'd like to use this code in new XSLT 2.0 template, and I am looking for replacement for saxon:if and saxon:before.
saxon.if(A, B, C) is now equivalent to if (A) then B else C in XPath 2.0
Here is my solution:
<xsl:variable
name="stop"
select="(following-sibling::h:h1|following-sibling::h:h2)[1]" />
<xsl:variable name="between">
<xsl:choose>
<xsl:when test="$stop">
<xsl:sequence select="following-sibling::*[. << $stop]" />
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="following-sibling::*" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
It uses <xsl:sequence> and << operator (encoded as <<), from XSLT 2.0 / XPath 2.0.
It's not as short as original version, but it doesn't use saxon extensions anymore.
You also could use just one expression in XSLT/XPath 2.0:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="text()"/>
<xsl:template match="p[position()=(1,3,4)]">
<xsl:copy-of select="following-sibling::*
[not(self::h2|self::h1)]
[not(. >>
current()
/following-sibling::*
[self::h2|self::h1][1])]"/>
</xsl:template>
</xsl:stylesheet>
With this input:
<html>
<p>1</p>
<p>2</p>
<h2>Header</h2>
<p>3</p>
<h1>Header</h1>
<p>4</p>
<p>5</p>
</html>
Output:
<p>2</p><p>5</p>