I'm using libxslt on iOS, and I'm getting compilation errors from what should be straightforward xslt, such as:
compilation error: file /Users/yada/Library/Developer/CoreSimulator/Devices/ACE15E20-3230-4966-ACDE-DCADABF48B32/data/Containers/Bundle/Application/A4EC9B34-3A96-42E0-B58F-6EB44C942874/appname.app/upconversion-options.xsl line 19 element function
xsltStylePreCompute: unknown xsl:function
compilation error: file /Users/yada/Library/Developer/CoreSimulator/Devices/ACE15E20-3230-4966-ACDE-DCADABF48B32/data/Containers/Bundle/Application/A4EC9B34-3A96-42E0-B58F-6EB44C942874/appname.app/upconversion-options.xsl line 20 element param
element param only allowed within a template, variable or param
... and many more like that, when I do this:
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
NSString * pMathMLTocMathMLXSLPath = [[NSBundle mainBundle] pathForResource:#"upconversion-options" ofType:#"xsl"];
xsltStylesheetPtr pMathMLTocMathMLXSLStyleSheet = xsltParseStylesheetFile((const xmlChar *)[pMathMLTocMathMLXSLPath cStringUsingEncoding:NSUTF8StringEncoding]);
The xsl file looks like this:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:s="http://www.ph.ed.ac.uk/snuggletex"
xmlns="http://www.w3.org/1998/Math/MathML"
exclude-result-prefixes="xs s"
xpath-default-namespace="http://www.w3.org/1998/Math/MathML">
<xsl:function name="s:get-boolean-option" as="xs:boolean">
<xsl:param name="upconversion-options" as="element(s:upconversion-options)"/>
<xsl:param name="name" as="xs:string"/>
<xsl:sequence select="boolean($upconversion-options/s:option[#name=$name]/#value='true')"/>
</xsl:function>
<xsl:function name="s:get-upconversion-option" as="xs:string?">
<xsl:param name="upconversion-options" as="element(s:upconversion-options)"/>
<xsl:param name="name" as="xs:string"/>
<xsl:sequence select="$upconversion-options/s:option[#name=$name]/#value"/>
</xsl:function>
<xsl:function name="s:get-symbol-assumption" as="element(s:symbol)?">
<xsl:param name="element" as="element()"/>
<xsl:param name="upconversion-options" as="element(s:upconversion-options)"/>
<xsl:sequence select="$upconversion-options/s:symbol[deep-equal(*, $element)]"/>
</xsl:function>
<xsl:function name="s:is-assumed-symbol" as="xs:boolean">
<xsl:param name="element" as="element()"/>
<xsl:param name="upconversion-options" as="element(s:upconversion-options)"/>
<xsl:param name="assume" as="xs:string"/>
<xsl:sequence select="exists($upconversion-options/s:symbol[#assume=$assume and deep-equal($element, *)])"/>
</xsl:function>
<xsl:function name="s:is-assumed-function" as="xs:boolean">
<xsl:param name="element" as="element()"/>
<xsl:param name="upconversion-options" as="element(s:upconversion-options)"/>
<xsl:sequence select="s:is-assumed-symbol($element, $upconversion-options, 'function')"/>
</xsl:function>
</xsl:stylesheet>
Any advice?
libxslt does not support XSLT 2.0. You will either need to use Saxon/C which hasn't left beta yet, or revert back to XSLT 1.0. If you revert back to 1.0 and need extra functionality take a look at EXSLT.
Related
I have a XML that has a date formatted as (2019-Aug-19) (YYYY-MMM-DD).
I want this to be transformed to (2019-08-19) (YYYY-MM-DD)
Hear is a sample what i have done. But no luck
<xsl:value-of select="format-dateTime(xs:dateTime(concat(date, T00:00:00Z')), '[D01]-[M01]-[Y0001]')"/>
Here you go may be another simple method:
XML:
<time>2019-Aug-19T00:00:00Z</time>
XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:output method="text" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:variable name="dt" select="time"/>
<xsl:template match="/">
<xsl:value-of select="format-dateTime(xs:dateTime(replace($dt, substring-before(substring-after($dt,'-'),'-') ,format-number(index-of(('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov', 'dec'),lower-case(substring-before(substring-after(lower-case($dt),'-'), '-'))),'00'))),'[D01]-[M01]-[Y0001]')"/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
Result:
19-08-2019
For YYYY-MM-DD you can do:
<xsl:value-of select="format-dateTime(xs:dateTime(replace($dt, substring-before(substring-after($dt,'-'),'-') ,format-number(index-of(('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov', 'dec'),lower-case(substring-before(substring-after(lower-case($dt),'-'), '-'))),'00'))),'[Y0001]-[M01]-[D01]')"/>
Result:
2019-08-19
See Link: http://xsltransform.net/nbiCsZm
How can I collect all parts of a string matching a regular expression pattern into an array?
<xsl:variable name="matches" select="function('abc_Xza_Y_Sswq', '_[A-Z]')"/>
returning
('_X', '_Y', '_S')
There are no arrays in XSLT/XPath 2.0, you could however write a function that uses analyze-string to return a sequence of strings:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:function name="mf:extract" as="xs:string*">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="pattern" as="xs:string"/>
<xsl:analyze-string select="$input" regex="{$pattern}">
<xsl:matching-substring>
<xsl:sequence select="."/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:template match="/">
<xsl:variable name="matches" select="mf:extract('abc_Xza_Y_Sswq', '_[A-Z]')"/>
<xsl:value-of select="$matches" separator=", "/>
</xsl:template>
</xsl:transform>
Hi I have an XML that upon each delivery has a different unique named Namespace that I cannot pre determine with standard processes.
<ABC xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>111</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>222</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extention>
</Extentions>
</ABC>
The Next XML delivered could be
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extention>
</Extentions>
</ABC>
My current XSL stylesheet works on the first XML predefining the Namespace
But I am looking to find a way to re-define it later on. on the process. I have added a variable to pull the relevant uuid from the Identification element but am not sure how to integrate this. Using the below stylesheet to process any other XML results in false results.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:variable name="SelOpGroup" select="/ABC/Extensions/Identification"/>
<!-- Pass thru --->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/ABC/Extensions/SrcPackage>
<xsl:copy>
<this:ABDList>
<xsl:copy-of select ="this:ABDList/*"/>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin><xsl:value-of select="somethingelse"/> </this:SubBegin>
</xsl:copy>
</xsl:template>
<xsl:template match="/ABC/Extensions/MatPackage>
<xsl:copy>
<this:ABDList>
<xsl:copy-of select ="this:ABDList/*"/>
<TaggedB>999</TaggedB>
</this:ABDList >
<this:SubBegin><xsl:value-of select="somethingelse"/> </this:SubBegin>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Expected Result
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin>a value</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
<TaggedB>999</TaggedA>
</this:ABDList>
<this:SubBegin>a value</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extention>
</Extentions>
</ABC>
Many thanks,
Adrian
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:variable name="SelOpGroup" select="/ABC/Extensions/Identification"/>
<!-- Pass thru -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Extension/SrcPackage">
<xsl:copy>
<xsl:element name="{'this:ABDList'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:copy-of select ="*[name() = 'this:ABDList']/*"/>
<TaggedA>888</TaggedA>
</xsl:element>
<xsl:element name="{'this:SubBegin'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:value-of select="'somethingelse'"/>
</xsl:element>
</xsl:copy>
</xsl:template>
<xsl:template match="Extension/MatPackage">
<xsl:copy>
<xsl:element name="{'this:ABDList'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:copy-of select ="*[name() = 'this:ABDList']/*"/>
<TaggedB>999</TaggedB>
</xsl:element>
<xsl:element name="{'this:SubBegin'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:value-of select="'somethingelse'"/>
</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied on the first provided XML document:
<ABC xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>111</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>222</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extension>
</Extensions>
</ABC>
Produces the wanted, correct result:
<ABC xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>111</TaggedValue>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>222</TaggedValue>
<TaggedB>999</TaggedB>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</MatPackage><!-- Stuff -->
</Extension>
</Extensions>
</ABC>
When the same transformation is applied on the second provided XML document:
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extension>
</Extensions>
</ABC>
Again the wanted, correct result is produced:
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
<TaggedB>999</TaggedB>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</MatPackage><!-- Stuff -->
</Extension>
</Extensions>
</ABC>
This is bizarre input (what were they smoking?). But since the namespace is only used on one element, ABDList, my approach would be to select the ABDList elements using *:ABDList in XSLT 2.0, or *[local-name()='ABDList'] in XSLT 1.0.
I have an XML that upon each delivery has a different unique named
Namespace
Someone ahead of you obviously does not understand the purpose of having a namespace.
Perhaps this could work for your unfortunate situation:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SrcPackage/*/TaggedValue">
<xsl:copy-of select="."/>
<TaggedA>888</TaggedA>
</xsl:template>
<xsl:template match="MatPackage/*/TaggedValue">
<xsl:copy-of select="."/>
<TaggedB>999</TaggedB>
</xsl:template>
</xsl:stylesheet>
I am making controls on a web page (comboboxes) with Saxon-CE and Xslt 2.0. I am having trouble in passing the values of multiple control to a template that uses the values from that control to process the document. Here is what I have:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT"
extension-element-prefixes="ixsl">
<xsl:template match="/">
<xsl:result-document href="#comboBox1">
<select id="myBox1">
<option value="1">One</option>
<option value="2">two</option>
</select>
</xsl:result-document>
<xsl:result-document href="#comboBox2">
<select id="myBox2">
<option value="A">Letter-A</option>
<option value="B">Letter-B</option>
</select>
</xsl:result-document>
</xsl:template>
<xsl:template match="select[#id='myBox1'] mode=ixsl:onchange">
<xsl:variable name="control1" select="."/>
<xsl:variable name="numVal" select="ixsl:get($control1,'value')"/>
<xsl:call-template name="displayStuff">
<xsl:with-param name="field1" select="$numVal"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="select[#id='myBox2'] mode=ixsl:onchange">
<xsl:variable name="control2" select="."/>
<xsl:variable name="letVal" select="ixsl:get($control2,'value')"/>
<xsl:call-template name="displayStuff">
<xsl:with-param name="field2" select="$letVal"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="displayStuff">
<xsl:param name="field1" select="0"/>
<xsl:param name="field2" select="Z">
<xsl:result-document href="#display" method="ixsl:replace-content">
<xsl:text>Number: </xsl:text> <xsl:value-of select="$field1"/><br/>
<xsl:text>Letter: </xsl:text> <xsl:value-of select="$field2"/><br/>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
The problem is that each control returns the correct value to the display template for an then item just changed, but not the other item.
For example if I select 1 in the first dropbox I get Number: 1 Letter: Z
but now if I change the vale of the second dropbox (for lets say to A) I get Number: 0 Letter:A.
How can I make sure what is passed to the display template is the current selected value of all the dropboxes, not the one just changed?
Instead of passing the current values of the controls as parameters to the displayStuff template, why not have that template access them directly from the HTML page by means of XPath expressions?
I suspect you could combine all this into a single template:
<xsl:template match="select[#id=('myBox1', 'myBox2')] mode=ixsl:onchange">
<xsl:variable name="control1" select="."/>
<xsl:variable name="numVal" select="ixsl:get(id('myBox1'),'value')"/>
<xsl:variable name="letVal" select="ixsl:get(id('myBox2'),'value')"/>
<xsl:result-document href="#display" method="ixsl:replace-content">
<xsl:text>Number: </xsl:text> <xsl:value-of select="$numVal"/><br/>
<xsl:text>Letter: </xsl:text> <xsl:value-of select="$letVal"/><br/>
</xsl:result-document>
</xsl:template>
Is it possible to make xsl:analyze-string return one string instead of a sequence of strings?
Background: I'd like to use xsl:analyze-string in a xsl:function that should encapsulate the pattern matching. Ideally, the function should return an xs:string to be used as sort criteria in an xsl:sort element.
At the moment, i have to apply string-join() on every result of the function call since xsl:analyze-string returns a sequence of strings, and xsl:sort doesn't accept such a sequence as sort criteria. See line 24 of the stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="www.my-personal-namespa.ce"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes" method="xml" />
<xsl:function name="my:sortierung" >
<xsl:param name="inputstring" as="xs:string"/>
<xsl:analyze-string select="$inputstring" regex="[0-9]+">
<xsl:matching-substring>
<xsl:value-of select="format-number(number(.), '00000')" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:template match="/input">
<result>
<xsl:apply-templates select="value" >
<xsl:sort select="string-join((my:sortierung(.)), ' ')" />
</xsl:apply-templates>
</result>
</xsl:template>
<xsl:template match="value">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
with this input:
<?xml version="1.0" encoding="UTF-8"?>
<input>
<value>A 1 b 120</value>
<value>A 1 b 1</value>
<value>A 1 b 2</value>
<value>A 1 b 1a</value>
</input>
In my example, is there a way to modify the xsl:function to return a xs:string instead of a sequence?
There are several ways I think, you could put the result of the analyze-string into a variable inside of the function and then use xs:sequence select="string-join($var, ' ')" in the function.
However the following with xsl:value-of should also do:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="www.my-personal-namespa.ce"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="my xs">
<xsl:output indent="yes" method="xml" />
<xsl:function name="my:sortierung" as="xs:string">
<xsl:param name="inputstring" as="xs:string"/>
<xsl:value-of separator=" ">
<xsl:analyze-string select="$inputstring" regex="[0-9]+">
<xsl:matching-substring>
<xsl:value-of select="format-number(number(.), '00000')" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:value-of>
</xsl:function>
<xsl:template match="/input">
<result>
<xsl:apply-templates select="value" >
<xsl:sort select="my:sortierung(.)" />
</xsl:apply-templates>
</result>
</xsl:template>
<xsl:template match="value">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>