I would like to know that is it possible to move xml element up or down in element tree.
The input xml.
<ROOT>
<A1>A</A1>
<B1>B</B1>
<C1>C</C1>
<D1>D</D1>
</ROOT>
The required output xml.
<ROOT>
<A1>A</A1>
<D1>D</D1>
<B1>B</B1>
<C1>C</C1>
</ROOT>
XSD Sequence Rule
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ROOT">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="A1"/>
<xs:element type="xs:string" name="D1"/>
<xs:element type="xs:string" name="B1"/>
<xs:element type="xs:string" name="C1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Can anyone provide me some XSLT example to do this such of thing? Thank you for any help in advance.
Martin Honnen help me to get answer from other post, hence just thought to share answer to help others but still I am wondering if there is any other way to do this - as in this approach if there is change in XSD tag sequence one has to change xsl sequence too.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ROOT">
<ROOT>
<xsl:apply-templates select="A1"/>
<xsl:apply-templates select="D1"/>
<xsl:apply-templates select="C1"/>
<xsl:apply-templates select="B1"/>
</ROOT>
</xsl:template>
<xsl:template match="A1">
<a1>
<xsl:apply-templates />
</a1>
</xsl:template>
<xsl:template match="B1">
<b1>
<xsl:apply-templates />
</b1>
</xsl:template>
<xsl:template match="C1">
<c1>
<xsl:apply-templates />
</c1>
</xsl:template>
<xsl:template match="D1">
<d1>
<xsl:apply-templates />
</d1>
</xsl:template>
</xsl:stylesheet>
Related
I updated the provided xslt to accept a param "multiplexpaths" from my source and assignin enter code here`g this to nodes variable in xslt to below:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="multiplexpaths" as="xs:string" static="yes" />
<!-- xsl:param name="copy" as="xs:string" static="yes" select="'//other[. = 1345], //more[. = 2]'"/-->
<xsl:variable name="nodes" _select="{$multiplexpaths}"/>
<xsl:variable name="ancestors" select="$nodes/ancestor::*"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="$nodes">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template match="$ancestors">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
For the xsl:evaluate example, you would need to use Saxon 10 HE, 9.9 HE doesn't support xsl:evaluate.
As for setting a static parameter with Saxon 9.9 and s9api, a simple example is
String paths = "catalog/cd1,catalog/Test/value/a1";
Processor processor = new Processor(true);
XsltCompiler xsltCompiler = processor.newXsltCompiler();
xsltCompiler.setParameter(new QName("copy"), new XdmAtomicValue(paths));
XsltExecutable xsltExecutable = xsltCompiler.compile(new StreamSource("static-param-example2.xsl"));
Xslt30Transformer xslt30Transformer = xsltExecutable.load30();
xslt30Transformer.transform(new StreamSource("input-sample1.xml"), xslt30Transformer.newSerializer(System.out));
with the input-sample1.xml being
<catalog>
<cd1>
<name>abc</name>
<Stext>1234</Stext>
<Tag>uuuu</Tag>
</cd1>
<cd2>
<name>abc</name>
<Stext>1234</Stext>
<Tag>uuuu</Tag>
</cd2>
<Test>
<value>
<a1>123</a1>
<b1>77474</b1>
</value>
</Test>
</catalog>
and the XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="copy" as="xs:string" static="yes" select="'()'"/>
<xsl:variable name="nodes" _select="{$copy}"/>
<xsl:variable name="ancestors" select="$nodes/ancestor::*"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="$nodes">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template match="$ancestors">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
this outputs
<catalog>
<cd1>
<name>abc</name>
<Stext>1234</Stext>
<Tag>uuuu</Tag>
</cd1>
<Test>
<value>
<a1>123</a1>
</value>
</Test>
</catalog>
So the main point is to set the parameter on the XsltCompiler and not after compilation on the transformer.
I am trying to get the enum value of the corresponding string. I am translating one XML into another.
For example, the source element is
<VehicleBodyType>Van</VehicleBodyType>
I need to transform it to
<VehicleTypeCode>5</VehicleTypeCode>
This is in an XSD:
<xs:simpleType name="VehicleBodyType">
<xs:restriction base="xs:string">
<xs:enumeration value="NotProvided" />
<xs:enumeration value="NotApplicable" />
<xs:enumeration value="PassengerCar" />
<xs:enumeration value="TruckPickupOrPassengerTruck" />
<xs:enumeration value="Van" />
<xs:enumeration value="TruckSingleUnitTruck2Axles" />
<xs:enumeration value="MotorHomeRecreationalVehicle" />
</xs:restriction>
</xs:simpleType>
I tried this:
<VehicleTypeCode>
<xsl:template match="xs:simpleType[#name='VehicleBodyType']/xs:restriction">
<xsl:for-each select="xs:enumeration">
<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>
</VehicleTypeCode>
but would get an error indicating that I can't do a template as a child of 'VehicleTypeCode' element.
I would prefer to use an XSD, but I can put this into the XSLT as well, if that makes it easier. I don't even know if the for-each is valid, but I found it on here and it looks like what I want.
Here is a sample of the source xml:
<?xml version="1.0" encoding="UTF-8"?>
<Crash>
<Vehicles>
<Vehicle>
<VehicleBodyType>Van</VehicleBodyType>
<VehicleColor>Red</VehicleColor>
</Vehicle>
</Vehicles>
</Crash>
Here the stripped down xslt i'm using:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" exclude-result-prefixes="xsl xs fn xsi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Crash" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CrashEntity>
<WorkZoneWorkers>
<xsl:value-of select="WorkersPresentCde"/>
</WorkZoneWorkers>
<xsl:choose>
<xsl:when test="not(Vehicles/Vehicle)">
<CrashUnits/>
</xsl:when>
<xsl:otherwise>
<CrashUnits>
<xsl:apply-templates select="Vehicles/Vehicle" />
</CrashUnits>
</xsl:otherwise>
</xsl:choose>
</CrashEntity>
</xsl:template>
<!-- Vehicles/Vehicle -->
<xsl:template match="Vehicles/Vehicle">
<CrashUnitsEntity>
<VehicleTypeCode>
<xsl:value-of select="VehicleBodyType"/>
</VehicleTypeCode>
<!--Can't use a template within a template-->
<!--<xsl:template match="xs:simpleType[#name='VehicleBodyType']/xs:restriction">
<VehicleTypeCode>
<xsl:value-of select="count(xs:enumeration[#value = 'Van']/preceding-sibling::xs:enumeration) + 1"/>
</VehicleTypeCode>
</xsl:template>-->
<!--Can't use a template within a template (original attempt)-->
<!--<VehicleTypeCode>
<xsl:template match="xs:simpleType[#name=$data]/xs:restriction">
<xsl:for-each select="xs:enumeration">
<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>
</VehicleTypeCode>-->
<!--Try to call a function-->
<VehicleTypeCode function="Enum1">
<xsl:call-template name="getEnum1">
<xsl:with-param name="type" select="VehicleBodyType"/>
<xsl:with-param name="data" select="VehicleBodyType"/>
</xsl:call-template>
</VehicleTypeCode>
<!--Try to call a function-->
<VehicleTypeCode function="Enum2">
<xsl:call-template name="getEnum2">
<xsl:with-param name="type" select="VehicleBodyType"/>
<xsl:with-param name="data" select="VehicleBodyType"/>
</xsl:call-template>
</VehicleTypeCode>
<Vehicle>
<UnitNumber>
<xsl:value-of select="#VehicleNumber"/>
</UnitNumber>
</Vehicle>
</CrashUnitsEntity>
</xsl:template>
<!-- ##################################### functions ##################################### -->
<!-- Can't call a template inside another template-->
<xsl:template name="getEnum1">
<xsl:param name="type"/>
<xsl:param name="data"/>
<xsl:if test="$data">
<!--<xsl:template match="xs:simpleType[#name=$type]/xs:restriction">
<xsl:for-each select="xs:enumeration">
<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>-->
</xsl:if>
</xsl:template>
<!-- Can't call a template inside another template-->
<xsl:template name="getEnum2">
<xsl:param name="type"/>
<xsl:param name="data"/>
<xsl:if test="$data">
<!--<xsl:template match="xs:simpleType[#name=$type]/xs:restriction">
<xsl:value-of select="count(xs:enumeration[#value = $data]/preceding-sibling::xs:enumeration) + 1"/>
</xsl:template>-->
</xsl:if>
</xsl:template>
<xs:simpleType name="VehicleBodyType">
<xs:restriction base="xs:string">
<xs:enumeration value="NotProvided" />
<xs:enumeration value="NotApplicable" />
<xs:enumeration value="PassengerCar" />
<xs:enumeration value="Van" />
<xs:enumeration value="Truck" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="VehicleColor">
<xs:restriction base="xs:string">
<xs:enumeration value="NotProvided" />
<xs:enumeration value="Red" />
<xs:enumeration value="Green" />
<xs:enumeration value="Blue" />
</xs:restriction>
</xs:simpleType>
</xsl:stylesheet>
Expected output xml:
<?xml version="1.0" encoding="UTF-8"?>
<CrashEntity>
<WorkZoneWorkers/>
<CrashUnits>
<CrashUnitsEntity>
<VehicleTypeCode>4</VehicleTypeCode>
<VehicleColor>2</VehicleColor>
</CrashUnitsEntity>
</CrashUnits>
</CrashEntity>
INPUT XML
<root>
<file1>
<commodity>
<units>1</units>
<obj>mango</obj>
</commodity>
<commodity>
<units>5</units>
<obj>guava</obj>
</commodity>
</file1>
<file2>
<category>
<object>guava</object>
<type>CAT1</type>
<colour>green</colour>
</category>
<category>
<object>mango</object>
<type>CAT2</type>
<colour>yellow</colour>
</category>
</file2>
</root>
I need to compare the values of obj in file1 and object in file2 under root, if same I need to take their corresponding units, type and colour and produce the following output using xslt.
OUTPUT XML
<output>
<com>
<name>guava</name>
<num>5</num>
<category>CAT1</category>
<col>green</col>
</com>
<com>
<name>mango</name>
<num>1</num>
<category>CAT2</category>
<col>yellow</col>
</com>
</output>
I tried the below XSLT but the response is not as expected. Its not looping properly. Could you please tell me where I am going wrong.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
indent="yes" />
<xsl:key name="object-search" match="root/file1/commodity" use="obj" />
<xsl:template match="/">
<output>
<xsl:for-each select="key('object-search', //category/object)">
<com>
<name>
<xsl:value-of select="obj" />
</name>
<num>
<xsl:value-of select="units" />
</num>
<category>
<xsl:value-of
select="//root/file2/category/type" />
</category>
<col>
<xsl:value-of
select="//root/file2/category/colour" />
</col>
</com>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
Try it this way:
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:key name="cat" match="category" use="object" />
<xsl:template match="/root">
<output>
<xsl:for-each select="file1/commodity">
<com>
<name>
<xsl:value-of select="obj" />
</name>
<num>
<xsl:value-of select="units" />
</num>
<xsl:variable name="cat" select="key('cat', obj)" />
<category>
<xsl:value-of select="$cat/type" />
</category>
<col>
<xsl:value-of select="$cat/colour" />
</col>
</com>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
Note that the result is slightly different from what you posted:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<com>
<name>mango</name>
<num>1</num>
<category>CAT2</category>
<col>yellow</col>
</com>
<com>
<name>guava</name>
<num>5</num>
<category>CAT1</category>
<col>green</col>
</com>
</output>
Alternatively, you could do:
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:key name="com" match="commodity" use="obj" />
<xsl:template match="/root">
<output>
<xsl:for-each select="file2/category">
<xsl:variable name="com" select="key('com', object)" />
<com>
<name>
<xsl:value-of select="$com/obj" />
</name>
<num>
<xsl:value-of select="$com/units" />
</num>
<category>
<xsl:value-of select="type" />
</category>
<col>
<xsl:value-of select="colour" />
</col>
</com>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
and get:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<com>
<name>guava</name>
<num>5</num>
<category>CAT1</category>
<col>green</col>
</com>
<com>
<name>mango</name>
<num>1</num>
<category>CAT2</category>
<col>yellow</col>
</com>
</output>
Consider the following schema:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.zoo.org/animals" targetNamespace="http://www.zoo.org/animals" elementFormDefault="unqualified" attributeFormDefault="unqualified" version="1.0.0">
<xsd:complexType name="Animals_Type">
<xsd:sequence>
<xsd:element ref="Cat" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Dog" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Mouse" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Lion" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Tiger" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Bear" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Penguin" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="Monkey" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="Animals" type="Animals_Type"/>
<xsd:element name="Cat" type="xsd:string"/>
<xsd:element name="Dog" type="xsd:string"/>
<xsd:element name="Mouse" type="xsd:string"/>
<xsd:element name="Lion" type="xsd:string"/>
<xsd:element name="Tiger" type="xsd:string"/>
<xsd:element name="Bear" type="xsd:string"/>
<xsd:element name="Penguin" type="xsd:string"/>
<xsd:element name="Monkey" type="xsd:string"/>
</xsd:schema>
With the following input xml:
<Animals xmlns="http://www.zoo.org/animals">
<Cat>Pixel</Cat>
<Dog>Ada</Dog>
<Mouse>Minnie</Mouse>
<Lion>Donnie</Lion>
<Tiger>Phil</Tiger>
<Bear>Susie</Bear>
<Penguin>Bob</Penguin>
<Monkey>Lennie</Monkey>
</Animals>
Where the desired output xml is to add a Bear named Billy:
<Animals xmlns="http://www.zoo.org/animals">
<Cat>Pixel</Cat>
<Dog>Ada</Dog>
<Mouse>Minnie</Mouse>
<Lion>Donnie</Lion>
<Tiger>Phil</Tiger>
<Bear>Susie</Bear>
<Bear>Billy</Bear>
<Penguin>Bob</Penguin>
<Monkey>Lennie</Monkey>
</Animals>
The following xslt will add Billy the Bear to the xml, however it will add Billy at the end after all other elements are copied and thus will create a schema invalid xml:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.zoo.org/animals">
<!-- element template that copies over elements -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Animals">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
<xsl:element name="Bear" namespace="{namespace-uri()}">Billy</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Creates schema invalid xml due to sequence out of order:
<?xml version="1.0" encoding="UTF-8"?>
<Animals xmlns="http://www.zoo.org/animals">
<Cat>Pixel</Cat>
<Dog>Ada</Dog>
<Mouse>Minnie</Mouse>
<Lion>Donnie</Lion>
<Tiger>Phil</Tiger>
<Bear>Susie</Bear>
<Penguin>Bob</Penguin>
<Monkey>Lennie</Monkey>
<Bear>Billy</Bear>
</Animals>
A better xslt that will add Billy the Bear in the correct location is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.zoo.org/animals">
<xsl:strip-space elements="*" />
<!-- element template that copies over elements -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Animals">
<xsl:copy>
<xsl:apply-templates select="#*|node()[not(self::Penguin)][not(self::Monkey)]" />
<xsl:element name="Bear" namespace="{namespace-uri()}">Billy</xsl:element>
<xsl:apply-templates select="#*|node()[not(self::Cat)][not(self::Dog)][not(self::Mouse)][not(self::Lion)][not(self::Tiger)][not(self::Bear)]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Creates correct xml:
<?xml version="1.0" encoding="UTF-8"?>
<Animals xmlns="http://www.zoo.org/animals">
<Cat>Pixel</Cat>
<Dog>Ada</Dog>
<Mouse>Minnie</Mouse>
<Lion>Donnie</Lion>
<Tiger>Phil</Tiger>
<Bear>Susie</Bear>
<Bear>Billy</Bear>
<Penguin>Bob</Penguin>
<Monkey>Lennie</Monkey>
</Animals>
The concern I have with this xslt is that it is directly coupled to the current schema. For instance if the schema is later updated with a simple element addition to the sequence, this xslt will break.
What is the most flexible way to add an element to the middle of a sequence? Is there a transform that can be written such that new elements being added to the sequence in the future will not break the transform?
I believe you want something 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:zoo="http://www.zoo.org/animals">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pAddElementName" select="'Bear'"/>
<xsl:param name="pAddValue" select="'Billy'"/>
<xsl:variable name="vSchema" select="document('animals.xsd')"/>
<xsl:variable name="vElementNameSpecified" select=
"$vSchema/*/xs:complexType[#name='Animals_Type']
/xs:sequence/xs:element[#ref=$pAddElementName]"/>
<xsl:variable name="vPreceding" select=
"$vSchema/*/xs:complexType[#name='Animals_Type']
/xs:sequence
/xs:element[following-sibling::xs:element
[#ref=$pAddElementName]]/#ref/string()"/>
<xsl:variable name="vFollowing" select=
"$vSchema/*/xs:complexType[#name='Animals_Type']
/xs:sequence
/xs:element[preceding-sibling::xs:element
[#ref=$pAddElementName]]/#ref/string()"/>
<xsl:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*[$vElementNameSpecified]/zoo:*[name()=$vPreceding][last()]">
<xsl:call-template name="identity"/>
<xsl:element name="{$pAddElementName}" namespace="http://www.zoo.org/animals">
<xsl:sequence select="$pAddValue"/>
</xsl:element>
</xsl:template>
<xsl:template match="/*[$vElementNameSpecified][not(zoo:*[name()=$vPreceding])]
/zoo:*[name()=$vFollowing][1]">
<xsl:element name="{$pAddElementName}" namespace="http://www.zoo.org/animals">
<xsl:sequence select="$pAddValue"/>
</xsl:element>
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="/*[$vElementNameSpecified]
[not(zoo:*[name()=$vPreceding])
and not(zoo:*[name()=$vFollowing])]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:element name="{$pAddElementName}" namespace="http://www.zoo.org/animals">
<xsl:sequence select="$pAddValue"/>
</xsl:element>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Explanation:
The XML Schema is accessed using the document() function.
All different names of elements that can precede the element to be added, are dynamically identified.
All different names of elements that can follow the element to be added, are dynamically identified.
There are three cases: a) preceding elements exist; b) preceding elements don't exist, but following elements exist; c) neither preceding elements nor following elements exist. The transformation contains a template for each of these cases, that adds the wanted new element in its correct place.
I am sick of write all the call-template/with-param stuff.
Is there any shortcut for this in example:
<xsl:call-template name="complexwidget">
<xsl:with-param name="a" select="$bla_213"/>
<xsl:with-param name="b" select="$bla_213"/>
<xsl:with-param name="c" select="$bla_213"/>
<xsl:with-param name="d" select="$bla_213"/>
</xsl:call-template>
A Perfect posibility would be this:
<complex a="{$bla_213}" b="{$bla_213}" c="{$bla_213}" d="{$bla_213}" />
Any idea, maybe a twice-transform-xslt??
If you could switch to xslt 2.0 then user functions would be exactly what you need.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:my="my-namespace">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select="my:complexWidget(1, 2, 3, 4)" />
</xsl:template>
<xsl:function name="my:complexWidget">
<xsl:param name="a" />
<xsl:param name="b" />
<xsl:param name="c" />
<xsl:param name="d" />
<!-- Do something -->
<xsl:value-of select="($a, $b,$c, $d)" separator="-" />
</xsl:function>
</xsl:stylesheet>
In xslt 1.0 I think that preprocessing of xslt stylesheet with another transformation will be the only way (or may be writing some extension functions in language of your processor .
EDIT:
I tried the "preprocess" of xslt and it seems to be working (but probably it is no the most elegant way how to do it).
Input xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mypp="my-preprocess-namespace">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:variable name="varA" select="1"/>
<xsl:variable name="varB" select="2"/>
<xsl:variable name="varC" select="3"/>
<xsl:variable name="varD" select="4"/>
<mypp:complexWidget a="$varA" b="$varB" c="$varC" d="$varD"/>
</xsl:template>
<xsl:template name="complexWidget">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:param name="c"/>
<xsl:param name="d"/>
<!-- do something-->
<xsl:value-of select="$a"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="$b"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="$c"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="$d"/>
</xsl:template>
</xsl:stylesheet>
I defined here a special namespace for element to be replaced (i.e. xmlns:mypp="my-preprocess-namespace"). Element to be replaced is <mypp:complexWidget a="$varA" b="$varB" c="$varC" d="$varD"/>.
This xslt I preprocess with following xslt.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mypp="my-preprocess-namespace">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<xsl:template match="mypp:*">
<xsl:element name="xsl:call-template">
<xsl:attribute name="name">
<xsl:value-of select="local-name()" />
</xsl:attribute>
<xsl:for-each select="#*">
<xsl:element name="xsl:with-param">
<xsl:attribute name="name">
<xsl:value-of select="name()" />
</xsl:attribute>
<xsl:attribute name="select">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
It is based on "Identity transform" - copy everything to the output just elements from special namespace transform into the call-template element. I guess this could be done in more nice way than I did.
The output is
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:mypp="my-preprocess-namespace" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:variable name="varA" select="1"/>
<xsl:variable name="varB" select="2"/>
<xsl:variable name="varC" select="3"/>
<xsl:variable name="varD" select="4"/>
<xsl:call-template name="complexWidget">
<xsl:with-param name="a" select="$varA"/>
<xsl:with-param name="b" select="$varB"/>
<xsl:with-param name="c" select="$varC"/>
<xsl:with-param name="d" select="$varD"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="complexWidget">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:param name="c"/>
<xsl:param name="d"/>
<!-- do something-->
<xsl:value-of select="$a"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="$b"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="$c"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="$d"/>
</xsl:template>
</xsl:stylesheet>
When I run the output as xslt stylesheet it produces expected output.
But I don't have any deeper experience with producing xslt stylesheet by another xslt so I don't know much about possible troubles with this approach.