Calling function for filtering - xslt

This function "karusell:isCurrentDateTimeBetweenDates" never gets called. Why cant i use it for filtering? If a call i alone and store it in a variable it work. The value of the variable is false.
<xsl:variable name="bannerList" select="verticaldata/contents/content[ karusell:isCurrentDateTimeBetweenDates( 'Thursday', '01' , 'Friday', '03') ][position() <= 5]" />
Edit:
How can the string be returned?
The filtering
The function
<xsl:function name="karusell:isCurrentDateTimeBetweenDates">
<xsl:param name="startDay"/>
<xsl:param name="startHour" />
<xsl:param name="endDay"/>
<xsl:param name="endHour" />
<xsl:variable name="currentDateTime" select="current-dateTime() " />
<xsl:variable name="todayIndex" select="karusell:getDayIndex(format-dateTime($currentDateTime , '[F]'))" />
<xsl:variable name="startDayIndex" select="karusell:getDayIndex($startDay)" />
<xsl:variable name="endDayIndex" select="karusell:getDayIndex($endDay)" />
<xsl:variable name="startDate" select= "$currentDateTime - ( $todayIndex - $startDayIndex )*xs:dayTimeDuration('P1D')"/>
<xsl:variable name="endDate" select= "$currentDateTime + ( $endDayIndex - $todayIndex )*xs:dayTimeDuration('P1D')"/>
<xsl:variable name="startDateTime" select="format-dateTime($startDate, concat('[Y0001]-[M01]-[D01]T', $startHour ,':00:00')) cast as xs:dateTime"/>
<xsl:variable name="endDateTime" select="format-dateTime($endDate, concat('[Y0001]-[M01]-[D01]T', $endHour ,':00:00')) cast as xs:dateTime"/>
<xsl:value-of select="$currentDateTime >= $startDateTime and $currentDateTime < $endDateTime" />
</xsl:function>

Use xsl:sequence, not xsl:value-of to return values of the data type your expression has. So replace
<xsl:value-of select="$currentDateTime >= $startDateTime and $currentDateTime < $endDateTime" />
with
<xsl:sequence select="$currentDateTime >= $startDateTime and $currentDateTime < $endDateTime" />
Additionally you can get better error diagnosis if you define the return type of your function with <xsl:function name="pf:foo" as="xs:boolean">..</xsl:function>.

Related

Date time conversion results in FORG0001 Invalid dateTime value - XSLT 3.0

Resources:
Java 1.8
Saxon-HE-10.3
XSLT3.0
I am merging 2 XML files and want to do date manipulation in the merged output file xml.
I am taking the 2 files as input using java and generate the merged xml - This works fine.
Now, I added the date manipulation in the xsl after the merging operation.
Date Manipulation - convert the given date to epoch/milliseconds
Date format which comes with the input file
<PROP NAME="START_DATE">
<PVAL>16-Aug-2018</PVAL>
</PROP>
The issue is when I try to convert the given date to dateTime or convert to epoch, I get the below error on compilation.
Error at char 10 in expression in xsl:value-of/#select on line 60 column 105 of CASTransform.xsl: FORG0001 Invalid dateTime value "/01--20T00:00:00" (Non-numeric year component) at template reformat-date on line 55 of CASTransform.xsl:
invoked by xsl:call-template at file:/home/Merger/scripts/CASTransform.xsl#50 In template rule with match="element(Q{}RECORDS)/element(Q{}RECORD)/element(Q{}PROP)[(Q{http://www.w3.org/2001/XMLSchema}string(data(attribute::attribute(Q{}NAME)))) eq "START_DATE"]/element(Q{}PVAL)" on line 48 of CASTransform.xsl
invoked by xsl:apply-templates at file:/home/Merger/scripts/CASTransform.xsl#45 In template rule with match="(element()|(text()|(comment()|processing-instruction())))" on line 43 of CASTransform.xsl
invoked by xsl:apply-templates at file:/home/Merger/scripts/CASTransform.xsl#35 at template main on line 14 of CASTransform.xsl: Exception in thread "main" net.sf.saxon.s9api.SaxonApiException: Invalid dateTime value "/01--20T00:00:00" (Non-numeric year component)
at net.sf.saxon.s9api.Xslt30Transformer.callTemplate(Xslt30Transformer.java:488)
XSL Code
<xsl:stylesheet version="3.0"
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:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="#all">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="mapData"/>
<xsl:template match="/" name="main">
<RECORDS>
<xsl:variable name="file1" select="map:get($mapData, '1')" />
<xsl:variable name="input-doc1" as="document-node()" select="doc($file1)"/>
<xsl:variable name="file2" select="map:get($mapData, '2')" />
<xsl:variable name="input-doc2" as="document-node()" select="doc($file2)"/>
<xsl:merge>
<xsl:merge-source name="doc1" select="$input-doc1/RECORDS/RECORD">
<xsl:merge-key select="PROP[#NAME = 'Id']/PVAL"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-source name="doc2" select="$input-doc2/RECORDS/RECORD">
<xsl:merge-key select="PROP[#NAME = 'Id']/PVAL"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-action>
<xsl:if test="current-merge-group('doc1')">
<xsl:copy>
<xsl:apply-templates select="*, current-merge-group('doc2')/(* except PROP[#NAME = 'Id'])"/>
</xsl:copy>
</xsl:if>
</xsl:merge-action>
</xsl:merge>
</RECORDS>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="RECORDS/RECORD/PROP[#NAME = 'START_DATE']/PVAL | RECORDS/RECORD/PROP[#NAME = 'END_DATE']/PVAL">
<xsl:element name="{name()}">
<xsl:call-template name="reformat-date">
<xsl:with-param name="date" select="." />
</xsl:call-template>
</xsl:element>
</xsl:template>
<xsl:template name="reformat-date">
<xsl:param name="date" />
<xsl:variable name="dd" select="substring($date,1,2)" />
<xsl:variable name="mmm" select="upper-case(substring($date,4,3))" />
<xsl:variable name="yyyy" select="substring($date,8,4)" />
<xsl:variable name="mmm">
<xsl:choose>
<xsl:when test="$mmm = 'JAN'">01</xsl:when>
<xsl:when test="$mmm = 'FEB'">02</xsl:when>
<xsl:when test="$mmm = 'MAR'">03</xsl:when>
<xsl:when test="$mmm = 'APR'">04</xsl:when>
<xsl:when test="$mmm = 'MAY'">05</xsl:when>
<xsl:when test="$mmm = 'JUN'">06</xsl:when>
<xsl:when test="$mmm = 'JUL'">07</xsl:when>
<xsl:when test="$mmm = 'AUG'">08</xsl:when>
<xsl:when test="$mmm = 'SEP'">09</xsl:when>
<xsl:when test="$mmm = 'OCT'">10</xsl:when>
<xsl:when test="$mmm = 'NOV'">11</xsl:when>
<xsl:when test="$mmm = 'DEC'">12</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="temp1" as="xs:string" select="string-join(($yyyy,$mmm,$dd),'-')" />
<xsl:value-of select="$temp1" />
</xsl:template>
</xsl:stylesheet>
The above XSL code works perfectly fine and the $temp1 gives proper date like 2018-08-16.
Now, when I try to convert this to dateTime variable I get the mentioned compilation error.
Code which gives error:
<xsl:variable name="temp2" as="xs:dateTime" select="xs:dateTime(concat($temp1,'T00:00:00'))"/>
and tried this as well :
<xsl:value-of select="floor((xs:dateTime(concat($temp1,'T00:00:00')) - xs:dateTime('1970-01-01T00:00:00')) div xs:dayTimeDuration('PT1S')) "/>
Requesting your help as this is my first XSL project.
Full Stacktrace:
Error at char 10 in expression in xsl:value-of/#select on line 60 column 105 of CASTransform.xsl:
FORG0001 Invalid dateTime value "/01--20T00:00:00" (Non-numeric year component)
at template reformat-date on line 55 of CASTransform.xsl:
invoked by xsl:call-template at file:/home/Merger/scripts/CASTransform.xsl#50
In template rule with match="element(Q{}RECORDS)/element(Q{}RECORD)/element(Q{}PROP)[(Q{http://www.w3.org/2001/XMLSchema}string(data(attribute::attribute(Q{}NAME)))) eq "START_DATE"]/element(Q{}PVAL)" on line 48 of CASTransform.xsl
invoked by xsl:apply-templates at file:/home/Merger/scripts/CASTransform.xsl#45
In template rule with match="(element()|(text()|(comment()|processing-instruction())))" on line 43 of CASTransform.xsl
invoked by xsl:apply-templates at file:/home/Merger/scripts/CASTransform.xsl#35
at template main on line 14 of CASTransform.xsl:
Exception in thread "main" net.sf.saxon.s9api.SaxonApiException: Invalid dateTime value "/01--20T00:00:00" (Non-numeric year component)
at net.sf.saxon.s9api.Xslt30Transformer.callTemplate(Xslt30Transformer.java:488)
at com.tracer.Merger.CASExportInput.trans(CASExportInput.java:38)
at com.tracer.Merger.CASExportInput.main(CASExportInput.java:58)
Caused by: ValidationException: Invalid dateTime value "/01--20T00:00:00" (Non-numeric year component)
at net.sf.saxon.type.ValidationFailure.makeException(ValidationFailure.java:406)
at net.sf.saxon.expr.CastExpression.doCast(CastExpression.java:385)
at net.sf.saxon.expr.CastExpression.evaluateItem(CastExpression.java:402)
at net.sf.saxon.expr.CastExpression.evaluateItem(CastExpression.java:30)
at net.sf.saxon.expr.Expression.iterate(Expression.java:872)
at net.sf.saxon.expr.AtomicSequenceConverter.iterate(AtomicSequenceConverter.java:304)
at net.sf.saxon.expr.Expression.process(Expression.java:949)
at net.sf.saxon.expr.instruct.ValueOf.processLeavingTail(ValueOf.java:340)
at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:746)
at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:752)
at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:264)
at net.sf.saxon.expr.instruct.CallTemplate$CallTemplatePackage.processLeavingTail(CallTemplate.java:549)
at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:478)
at net.sf.saxon.expr.instruct.ApplyTemplates.apply(ApplyTemplates.java:351)
at net.sf.saxon.expr.instruct.ApplyTemplates.process(ApplyTemplates.java:285)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:352)
at net.sf.saxon.expr.instruct.Copy.processLeavingTail(Copy.java:429)
at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(TemplateRule.java:384)
at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:568)
at net.sf.saxon.expr.instruct.ApplyTemplates.apply(ApplyTemplates.java:351)
at net.sf.saxon.expr.instruct.ApplyTemplates.process(ApplyTemplates.java:285)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:352)
at net.sf.saxon.expr.instruct.Copy.processLeavingTail(Copy.java:429)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:142)
at net.sf.saxon.expr.parser.ExpressionTool.getIteratorFromProcessMethod(ExpressionTool.java:643)
at net.sf.saxon.expr.instruct.Instruction.iterate(Instruction.java:374)
at net.sf.saxon.expr.instruct.Choose.iterate(Choose.java:1019)
at net.sf.saxon.expr.sort.MergeInstr.lambda$iterate$0(MergeInstr.java:543)
at net.sf.saxon.expr.ContextMappingIterator.next(ContextMappingIterator.java:61)
at net.sf.saxon.om.SequenceIterator.forEachOrFail(SequenceIterator.java:135)
at net.sf.saxon.expr.sort.MergeInstr.processLeavingTail(MergeInstr.java:823)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:142)
at net.sf.saxon.expr.LetExpression.process(LetExpression.java:625)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:352)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:298)
at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:264)
at net.sf.saxon.trans.XsltController.callTemplate(XsltController.java:850)
at net.sf.saxon.s9api.Xslt30Transformer.callTemplate(Xslt30Transformer.java:480)
... 2 more
Java code which serves the Input files :
package com.tracer.Merger.CASMerger;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api. * ;
public class CASExportInput {
public static void trans(String XSLFile, String File1, String File2, String OutputFileName, String OutputFilePath) throws SaxonApiException {
String MergedFile = OutputFilePath.concat(OutputFileName);
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable exp = compiler.compile(new StreamSource(new File(XSLFile)));
Serializer out = processor.newSerializer(new File(MergedFile));
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
Xslt30Transformer trans = exp.load30();
Map < String,
String > mapData = new HashMap < String,
String > ();
mapData.put("1", File1);
mapData.put("2", File2);
HashMap < QName,
XdmValue > parameters = new HashMap < >();
parameters.put(new QName("mapData"), XdmMap.makeMap(mapData));
trans.setStylesheetParameters(parameters);
trans.callTemplate(new QName("main"), out);
System.out.println("Output written to : " + MergedFile);
}
public static void main(String args[]) throws SaxonApiException {
if (args.length < 3) System.out.println("\nPlease check if you have entered arguments properly...");
String XSLFile = args[0].toString().trim();
String File1 = args[1].toString().trim();
String File2 = args[2].toString().trim();
String FileName1 = File1.substring(File1.lastIndexOf("/") + 1, File1.length() - 4);
String FileName2 = File2.substring(File2.lastIndexOf("/") + 1, File2.length() - 4);
String OutputFilePath = File1.substring(0, File1.lastIndexOf("/") + 1);
String OutputFileName = FileName1.concat("-" + FileName2 + ".xml");
trans(XSLFile, File1, File2, OutputFileName, OutputFilePath);
}
}
Not sure what the issue was. But, I uninstalled and re-installed Java 1.8 and the issue got fixed. No changes were done in the xsl or java code.

Convert negative decimal to hexadecimal in xslt

Please, can you help me how to convert negative/positive decimal value to hexadecimal in xslt/xslt 2.0 ?
This is what i tried but does not work with negative numbers/decimals,
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="ConvertDecToHex">
<xsl:param name="index" />
<xsl:if test="$index > 0">
<xsl:call-template name="ConvertDecToHex">
<xsl:with-param name="index" select="floor($index div 16)" />
</xsl:call-template>
<xsl:choose>
<xsl:when test="$index mod 16 < 10">
<xsl:value-of select="$index mod 16" />
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$index mod 16 = 10">A</xsl:when>
<xsl:when test="$index mod 16 = 11">B</xsl:when>
<xsl:when test="$index mod 16 = 12">C</xsl:when>
<xsl:when test="$index mod 16 = 13">D</xsl:when>
<xsl:when test="$index mod 16 = 14">E</xsl:when>
<xsl:when test="$index mod 16 = 15">F</xsl:when>
<xsl:otherwise>A</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
This transformation:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="my:intToHex(53), my:intToHex(-53)" separator="
"/>
</xsl:template>
<xsl:function name="my:intToHex" as="xs:string">
<xsl:param name="pInt" as="xs:integer"/>
<xsl:variable name="vMinusOneHex64" select="18446744073709551615"/>
<xsl:variable name="vCompl" select=
"if($pInt ge 0)
then $pInt
else $vMinusOneHex64 + $pInt +1"/>
<xsl:sequence select=
"if ($vCompl eq 0)
then '0'
else
concat(if ($vCompl gt 16)
then my:intToHex($vCompl idiv 16)
else '',
substring('0123456789ABCDEF',
($vCompl mod 16) +1,
1)
)"/>
</xsl:function>
</xsl:stylesheet>
When applied on any source XML document (ignored), produces the desired result:
35
FFFFFFFFFFFFFFCB

Convert a hexadecimal number to an integer in XSLT

I need to convert a hexadecimal value to an integer value, how can I do that using XSLT?
For example, if the input is hexadecimal FF, my output should be 255.
Converting hexadecimal to decimal in pure XSLT 1.0:
<xsl:template name="hex2num">
<xsl:param name="hex"/>
<xsl:param name="num" select="0"/>
<xsl:param name="MSB" select="translate(substring($hex, 1, 1), 'abcdef', 'ABCDEF')"/>
<xsl:param name="value" select="string-length(substring-before('0123456789ABCDEF', $MSB))"/>
<xsl:param name="result" select="16 * $num + $value"/>
<xsl:choose>
<xsl:when test="string-length($hex) > 1">
<xsl:call-template name="hex2num">
<xsl:with-param name="hex" select="substring($hex, 2)"/>
<xsl:with-param name="num" select="$result"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Edit: Sorry, my bad I just noted the OP asked for hex to decimal and not the other way around.
hexToDecimal template for XSLT-1.0:
<xsl:template name="hexToDecimal">
<xsl:param name="hex"/>
<xsl:variable name="dec"
select="string-length(substring-before('0123456789ABCDEF', substring($hex,1,1)))"/>
<xsl:choose>
<xsl:when test="$hex = ''">0</xsl:when>
<xsl:otherwise>
<xsl:variable name="rest">
<xsl:call-template name="hexToDecimal">
<xsl:with-param name="hex">
<xsl:value-of select="substring($hex,2)"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$dec * math:power(16, string-length($hex) - 1) + $rest"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This needs math:power from exslt http://exslt.org/math/
hexToDecimal function for XSLT-2.0:
<xsl:function name="f:hexToDec">
<xsl:param name="hex"/>
<xsl:variable name="dec"
select="string-length(substring-before('0123456789ABCDEF', substring($hex,1,1)))"/>
<xsl:choose>
<xsl:when test="matches($hex, '([0-9]*|[A-F]*)')">
<xsl:value-of
select="if ($hex = '') then 0
else $dec * f:power(16, string-length($hex) - 1) + f:hexToDec(substring($hex,2))"/>
</xsl:when>
<xsl:otherwise>
<xsl:message>Provided value is not hexadecimal...</xsl:message>
<xsl:value-of select="$hex"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:function name="f:power">
<xsl:param name="base"/>
<xsl:param name="exp"/>
<xsl:sequence
select="if ($exp lt 0) then f:power(1.0 div $base, -$exp)
else if ($exp eq 0)
then 1e0
else $base * f:power($base, $exp - 1)"
/>
</xsl:function>
Leaving this here, also it was not asked for, it might still be useful.
There is no directly implemented function in xslt, so you would have to write it yourself.
Here's a template for XSLT 1.0:
<xsl:template name="decimalToHex">
<xsl:param name="dec"/>
<xsl:if test="$dec > 0">
<xsl:call-template name="decimalToHex">
<xsl:with-param name="dec" select="floor($dec div 16)"/>
</xsl:call-template>
<xsl:value-of select="substring('0123456789ABCDEF', (($dec mod 16) + 1), 1)"/>
</xsl:if>
</xsl:template>
You call it like this:
<xsl:call-template name="decimalToHex">
<xsl:with-param name="dec">4095</xsl:with-param>
</xsl:call-template>
And a function for XSLT 2.0:
<xsl:function name="f:decimalToHex">
<xsl:param name="dec"/>
<xsl:if test="$dec > 0">
<xsl:value-of
select="f:decimalToHex(floor($dec div 16)),substring('0123456789ABCDEF', (($dec mod 16) + 1), 1)"
separator=""
/>
</xsl:if>
</xsl:function>
Which you can call like this:
<xsl:value-of select="f:decimalToHex(4095)"/>
Be aware that you have to declare the namespace for the function in you stylesheet.

Math results in scientific float and cannot calculate with it anymore

I am trying to make an xslt that can convert a position (vector3) via a quaternion to a new position. I have made the following set-up, but I am retrieving NaN's for very small values close to 0. How can I calculate further with the values that come from the quaternion to right-vector calculations?
<xsl:template name="object_markingtape_position">
<xsl:param name="sign"/> <!-- left or right (-1 or 1) -->
<xsl:param name="quaternion"/> <!-- quaternion in x,y,z,w -->
<xsl:variable name="rightvec">
<xsl:call-template name="QuatToRight">
<xsl:with-param name="x" select="$quaternion/ns:x"/>
<xsl:with-param name="y" select="$quaternion/ns:y"/>
<xsl:with-param name="z" select="$quaternion/ns:z"/>
<xsl:with-param name="w" select="$quaternion/ns:w"/>
</xsl:call-template>
</xsl:variable>
Right vector y: <xsl:value-of select="number($rightvec/y)"/> <!-- results in a value with 1.5435434E-04 -->
<xsl:element name="position" namespace="{$ns}">
<xsl:element name="x" namespace="{$ns}">
<xsl:value-of select="$sign * 1.5 * $rightvec/x + ns:position/ns:x"/>
</xsl:element>
<xsl:element name="y" namespace="{$ns}"> <!-- results into NaN -->
<xsl:value-of select="$sign * 1.5 * $rightvec/y + ns:position/ns:y"/>
</xsl:element>
<xsl:element name="z" namespace="{$ns}">
<xsl:value-of select="$sign * 1.5 * $rightvec/z + ns:position/ns:z"/>
</xsl:element>
</xsl:element>
</xsl:template>
<!-- Functionality for calculating the vectors from a quaternion -->
<!-- From http://nic-gamedev.blogspot.nl/2011/11/quaternion-math-getting-local-axis.html -->
<xsl:template name="QuatToRight">
<xsl:param name="x"/>
<xsl:param name="y"/>
<xsl:param name="z"/>
<xsl:param name="w"/>
<xsl:element name="vec3">
<xsl:element name="x">
<xsl:value-of select="1 - 2 * ($x * $y - $w * $z)"/>
</xsl:element>
<xsl:element name="y">
<xsl:value-of select="2 * ($x * $y + $w * $z)"/>
</xsl:element>
<xsl:element name="z">
<xsl:value-of select="2 * ($x * $z - $w * $y)"/>
</xsl:element>
</xsl:element>
</xsl:template>
An example of xml values that can come in are the following:
<Item>
<position>
<x>-106.6172</x>
<y>0.780673563</y>
<z>-13.0446815</z>
</position>
<rotation> <!-- this is where the quaternion param is filled with -->
<x>0.0810996</x>
<y>0.354339659</y>
<z>-0.207844481</z>
<w>-0.908111751</w>
</rotation>
</Item>
If you can't find a better solution you might have to resort to using extension functions.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:quat="urn:myExtension" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="quat msxsl" version="1.0">
<xsl:param name="x"/>
<xsl:param name="y"/>
<xsl:param name="z"/>
<xsl:param name="w"/>
<xsl:template match="*">
<xsl:value-of select="quat:calcQuat($x, $y, $z, $w)"/>
</xsl:template>
<msxsl:script implements-prefix="quat" language="c#">
<![CDATA[
public string calcQuat(double x, double y, double z, double w)
{
double result = 1 - 2 * (x * y - w * z)
return Double.ToString(result)
}
]]>
</msxsl:script>
There are three problems I can see:
the variable rightvec contains an XML fragment, but is then used as a node-set - this requires a conversion to work usually (but it depends on the XSLT processor)
the named template object_markingtape_position references an element ns:position in the current context, so its result depends on where it is called - better to pass the position as a parameter;
the named tamplate QuatToRight generates a vec3 element containing sub-elements with the values, but its result is then used as if there was not vec3 intermediate element.
Using the .NET XSLT processor, this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template name="object_markingtape_position">
<xsl:param name="sign"/> <!-- left or right (-1 or 1) -->
<xsl:param name="quaternion"/> <!-- quaternion in x,y,z,w -->
<xsl:param name="position"/> <!-- position in x,y,z -->
<xsl:variable name="rightvecFragment">
<xsl:call-template name="QuatToRight">
<xsl:with-param name="x" select="$quaternion/x"/>
<xsl:with-param name="y" select="$quaternion/y"/>
<xsl:with-param name="z" select="$quaternion/z"/>
<xsl:with-param name="w" select="$quaternion/w"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="rightvec" select="msxsl:node-set($rightvecFragment)"/>
<xsl:element name="position">
<xsl:element name="x">
<xsl:value-of select="$sign * 1.5 * $rightvec/x + $position/x"/>
</xsl:element>
<xsl:element name="y">
<!-- results into NaN -->
<xsl:value-of select="$sign * 1.5 * $rightvec/y + $position/y"/>
</xsl:element>
<xsl:element name="z">
<xsl:value-of select="$sign * 1.5 * $rightvec/z + $position/z"/>
</xsl:element>
</xsl:element>
</xsl:template>
<!-- Functionality for calculating the vectors from a quaternion -->
<!-- From http://nic-gamedev.blogspot.nl/2011/11/quaternion-math-getting-local-axis.html -->
<xsl:template name="QuatToRight">
<xsl:param name="x"/>
<xsl:param name="y"/>
<xsl:param name="z"/>
<xsl:param name="w"/>
<xsl:element name="x">
<xsl:value-of select="1 - 2 * ($x * $y - $w * $z)"/>
</xsl:element>
<xsl:element name="y">
<xsl:value-of select="2 * ($x * $y + $w * $z)"/>
</xsl:element>
<xsl:element name="z">
<xsl:value-of select="2 * ($x * $z - $w * $y)"/>
</xsl:element>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="object_markingtape_position">
<xsl:with-param name="sign" select="1"/>
<xsl:with-param name="position" select="position"/>
<xsl:with-param name="quaternion" select="rotation"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
applied to the example input produces:
<position>
<x>-104.63717236709732</x>
<y>1.4331220235568977</y>
<z>-12.129909788264223</z>
</position>
I resolved this with some data loss, but it is the cleanest solution so far. I used format-number().
<xsl:template name="QuatToRight">
<xsl:param name="x"/>
<xsl:param name="y"/>
<xsl:param name="z"/>
<xsl:param name="w"/>
<xsl:element name="vec3">
<xsl:element name="x">
<xsl:value-of select="format-number(1 - 2 * ($x * $y - $w * $z),'0.000000')"/>
</xsl:element>
<xsl:element name="y">
<xsl:value-of select="format-number(2 * ($x * $y + $w * $z),'0.000000')"/>
</xsl:element>
<xsl:element name="z">
<xsl:value-of select="format-number(2 * ($x * $z - $w * $y),'0.000000')"/>
</xsl:element>
</xsl:element>
</xsl:template>

Type mismatch error trying to call wmi function from within xslt loop

I have the following xsl template loop (recursive) which calls a VBScript function that takes one parameter which represents the physical hard drive number and retrieves drive information:
<xsl:template name="for.loop.Drives">
<xsl:param name="i" select ="0" />
<xsl:param name="count" />
<!--begin_: Line_by_Line_Output -->
<xsl:if test="$i <= $count">
<xsl:value-of select="nunit2report2:GetDiskDrives($i)"/>
</xsl:if>
<!--begin_: RepeatTheLoopUntilFinished-->
<xsl:if test="$i <= $count">
<xsl:call-template name="for.loop.Drives">
<xsl:with-param name="i">
<xsl:value-of select="$i + 1"/>
</xsl:with-param>
<xsl:with-param name="count">
<xsl:value-of select="$count"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
The VBScript function (which I verified works):
Function GetDiskDrives(drivenumber)
strComputer = "."
objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
colItems = objWMIService.ExecQuery("Select * from Win32_DiskDrive")
'For Each objItem in colItems
DiskDriveInfo = DiskDriveInfo & "Name: " & colItems.ItemIndex(drivenumber).Name & _
" -- Model: " & colItems.ItemIndex(drivenumber).Model & _
" -- Status: " & colItems.ItemIndex(drivenumber).Status & _
" -- Size: " & Int(colItems.ItemIndex(drivenumber).Size /(1073741824)) & " GB" & _
" -- Number of Partitions: " & colItems.ItemIndex(drivenumber).Partitions
'Next
GetDiskDrives = DiskDriveInfo
End Function
The error returned is a type mismatch. It has to do with the $i passed in to the function:
<xsl:if test="$i <= $count">
<xsl:value-of select="nunit2report2:GetDiskDrives($i)"/>
</xsl:if>
When I do this, it works, but I'm explicitly passing in 1.
<xsl:if test="$i <= $count">
<xsl:value-of select="nunit2report2:GetDiskDrives(1)"/>
</xsl:if>
I tried converting the passed in $i to an integer in the VBScript using
drivenum = CInt(drivenumber)
but the cast above returns the following error:
System.InvalidCastException: Conversion from type 'XPathDocumentNavigator' to type 'Integer' is not valid.
Anyone know how I can get this call right? I'm using xslt 1.0
Have you tried:
<xsl:value-of select="nunit2report2:GetDiskDrives(number($i))"/>
In addition to what Dimitre suggested, if you change
<xsl:if test="$i <= $count">
<xsl:call-template name="for.loop.Drives">
<xsl:with-param name="i">
<xsl:value-of select="$i + 1"/>
</xsl:with-param>
<xsl:with-param name="count">
<xsl:value-of select="$count"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
into
<xsl:if test="$i <= $count">
<xsl:call-template name="for.loop.Drives">
<xsl:with-param name="i" select="$i + 1"/>
<xsl:with-param name="count" select="$count"/>
</xsl:call-template>
</xsl:if>
the problem might go away or at least your script function then receives a double number that the script can then easily convert into an integer if needed for the WMI API.
Your current code is not only longer to write but unnecessarily passed around result tree fragments where all you want is passing around number values.