XSLT CallTemplate ForEach XML - templates

I need a little XSLT help. Couldn't figure out why the actual output is different from my expected output. Any help much appreciated!
XML
<?xml version="1.0"?>
<a>
<b c="d"/>
<b c="d"/>
<b c="d"/>
</a>
XSL
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="foo">
<xsl:param name="content"></xsl:param>
<xsl:value-of select="$content"></xsl:value-of>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="foo">
<xsl:with-param name="content">
<xsl:for-each select="a/b">
<e>
<xsl:value-of select="#c" />
</e>
</xsl:for-each>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
Actual Output
<?xml version="1.0"?>
ddd
Desired Output
<?xml version="1.0"?>
<e>d</e>
<e>d</e>
<e>d</e>
Note: Calling the template is mandatory. In my situation the template does more with extension functions.

Contrary to what ABach says, your xsl:param is fine. The only thing you need to change is your xsl:value-of. It should be a xsl:copy-of:
<xsl:template name="foo">
<xsl:param name="content"/>
<xsl:copy-of select="$content"/>
</xsl:template>

You're very close; you've just mixed up relative positioning and correct parameter usage within templates. Here's a slightly revised answer.
When this XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template name="foo">
<xsl:param name="pContent" />
<xsl:for-each select="$pContent">
<e>
<xsl:value-of select="#c" />
</e>
</xsl:for-each>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="foo">
<xsl:with-param name="pContent" select="*" />
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
...is applied to the original XML:
<?xml version="1.0"?>
<a>
<b c="d" />
<b c="d" />
<b c="d" />
</a>
...the desired result is produced:
<?xml version="1.0"?>
<e>d</e>
<e>d</e>
<e>d</e>
In particular, notice the correct usage of <xsl:param> to include nodes based on their relative position. In your case, you are telling the XSLT parser to output the text values of the parameter that you're passing, rather than altering the nodes' contents in the way you want.

Related

XSLT 2.0 XPATH expression with variable

I'm working on a Java based xsl-transformation (XSLT 2.0, could also be XSLT 3.0 if there is a free processor for java) with different input xml files. one input file could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<CHILD>A</CHILD>
<CHILDBEZ>ABEZ</CHILDBEZ>
<NotInteresting></NotInteresting>
</MyElement>
<MyElement>
<CHILD>B</CHILD>
<CHILDBEZ>BBEZ</CHILDBEZ>
<NotInteresting2></NotInteresting2>
</MyElement>
</TEST>
I want to copy all elements but "NotInteresting" and rename the two nodes CHILD and CHILDBEZ based on two parameters that I get from a mapping file:
the xpath expression that tells me where the text of interest is placed (in this case: TEST/MyFirstElement/CHILD and TEST/MyFirstElement/CHILDBEZ)
and the names of the elements what they should have in the output file (in this case: childName and childBez)
the mapping file:
<?xml version="1.0" encoding="UTF-8"?>
<element root="TEST">
<childName>TEST/MyElement/CHILD</childName>
<childBez>TEST/MyElement/CHILDBEZ</childBez>
</element>
desired output:
<TEST>
<MyElement>
<childName>A</childName>
<childBez>ABEZ</childBez>
</MyElement>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>
what I have so far:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.0 "
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.apoverlag.at"
xmlns:apo="http://www.apoverlag.at">
<xsl:variable name="vars" select="document('mapping.xml')"/>
<xsl:param name="src" />
<xsl:variable name="path" xpath-default-namespace="" select="$src/path"/> <!-- = TEST/*-->
<xsl:template match="/">
<xsl:for-each select="$path">
<xsl:call-template name="buildNode">
<xsl:with-param name="currentNode" select="current()"></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="buildNode">
<xsl:param name="currentNode" />
<xsl:element name="test">
<xsl:for-each select="$vars/element/#root">
<xsl:for-each select="$vars/element/*">
<xsl:element name="{name(.)}"> <xsl:value-of select="concat($currentNode,'/',current())" />
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:transform>
My problem is that:
<xsl:value-of select="concat($currentNode,'/',current())" />
gives me "/TEST/MyFirstElement/CHILD" when I try it hardcoded with:
<xsl:value-of select="$currentNode/CHILD" />
I receive my desired output. Can anyone give me a hint how to solve this problem?
I would suggest a radically different approach. To simplify, I have used a mapping document with full paths (starting with the / root node):
mapping xml
<element root="TEST">
<childName>/TEST/MyElement/CHILD</childName>
<childBez>/TEST/MyElement/CHILDBEZ</childBez>
</element>
XSLT 2.0
<xsl:stylesheet version="2.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="*"/>
<xsl:param name="mapping" select="document('mapping.xml')"/>
<xsl:key name="map" match="*" use="." />
<xsl:template match="/">
<xsl:variable name="first-pass">
<xsl:apply-templates mode="first-pass"/>
</xsl:variable>
<xsl:apply-templates select="$first-pass/*"/>
</xsl:template>
<xsl:template match="*" mode="first-pass">
<xsl:param name="parent-path"/>
<xsl:variable name="path" select="concat($parent-path, '/', name())" />
<xsl:variable name="replacement" select="key('map', $path, $mapping)" />
<xsl:element name="{if ($replacement) then name($replacement) else name()}">
<xsl:attribute name="original" select="not($replacement)"/>
<xsl:apply-templates mode="first-pass">
<xsl:with-param name="parent-path" select="$path"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[#original='true' and not(descendant::*/#original='false')]"/>
</xsl:stylesheet>
Result, when applied to the provided input:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<childName>A</childName>
<childBez>ABEZ</childBez>
</MyElement>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>

Transformation of text file into an xml using datapower

I want to transfer a non-xml text file delimited by '|' characters into an xml using Datapower.
Following is file (sample1)
10|20003|24/23/25|23890
Now i have to break this into the following XML
<ResponseType>
<ResCode>10</ResCode>
<Id>20003</Id>
<SoftCode>24/23/25</SoftCode>
<StatusCode>23890</StatusCode>
</ResponseType>
What I did was following--
1>Create a Transform action in the service that will be receiving non-XML requests.
2>Select "Use XSLT specified in this action on a non-XML message" to specify that this is a Binary Transform.
3>Upload the following stylesheet as the Processing Control File.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
version="1.0">
<dp:input-mapping href="sample1.ffd" type="ffd"/>
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:copy-of select="ResponseType"/>
<xsl:call-template name="str:tokenize">
<xsl:with-param name="string" select="string" />
</xsl:call-template>
</xsl:template>
<xsl:template name="str:tokenize">
<xsl:with-param name="string" select="">
str:tokenize('string', '|')
</xsl:with param>
</xsl:template>
</xsl:stylesheet>
and here is my sample1.ffd(which I have uploaded in my local:// directory in Datapower
<File name="ResponseType">
<!-- capture all data into this tag -->
<Field name="ResCode/Id/SoftCode/StatusCode" />
</File>
But I am not getting desired output , I think my xslt is quite wrong
What can I do do to get desired output?
In DataPower using FFD the following should work:
1) Add the FFD file (below one of my old education samples):
<File name="CSVFILE">
<Group name="CSVLine" minOccurs="0" maxOccurs="unbounded" delim="\n">
<Field name="id"/>
<Field name="fname" delim=","/>
<Field name="lname" delim=","/>
<Field name="title" delim=","/>
<Field name="dept" delim=","/>
<Field name="org"/>
</Group>
</File>
2) Add the XSLT (this one simply copies the FFD transformed XML to output):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
version="1.0">
<dp:input-mapping href="CSVFILE.FFD" type="ffd"/>
<!-- This stylesheet copies the input to the output -->
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
3) Send a message:
1,Anders,Wasen,B2B Architect,DataPower Dev,Enfo Zystems
2,Jean-Luc,Piccard,Captain,USS Enterprise,Star Fleet
4) This will result in the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<CSVFILE>
<CSVLine>
<id>1</id>
<fname>Anders</fname>
<lname>Wasen</lname>
<title>B2B Architect</title>
<dept>DataPower Dev,Enfo Zystems</dept>
<org/>
</CSVLine>
<CSVLine>
<id>2</id>
<fname>Jean-Luc</fname>
<lname>Piccard</lname>
<title>Captain</title>
<dept>USS Enterprise,Star Fleet</dept>
<org/>
</CSVLine>
</CSVFILE>
Make sure that you change the XSLT Transform action into "Transform Binary" and set Request Type to "non-xml", else it will not work!
Hope this will help you! :)
I'm not sure how IBM Datapower might solve this problem, but for XSLT, you would at least wrap your input in a XML element:
<Whatever>
10|20003|24/23/25|23890
</Whatever>
And then you could go on with a transformation like follows. The hard part is splitting your text input. In XSLT 1.0, there is no function available for that, so you need a recursive template.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxml="urn:schemas-microsoft-com:xslt" version="1.0" exclude-result-prefixes="msxml">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<xsl:variable name="tokenized">
<items>
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="//text()" />
</xsl:call-template>
</items>
</xsl:variable>
<ResponseType>
<ResCode>
<xsl:copy-of select="msxml:node-set($tokenized)/items/item[1]/text()" />
</ResCode>
<Id>
<xsl:copy-of select="msxml:node-set($tokenized)/items/item[2]/text()" />
</Id>
<SoftCode>
<xsl:copy-of select="msxml:node-set($tokenized)/items/item[3]/text()" />
</SoftCode>
<StatusCode>
<xsl:copy-of select="msxml:node-set($tokenized)/items/item[4]/text()" />
</StatusCode>
</ResponseType>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="string" />
<xsl:variable name="item" select="normalize-space( substring-before( concat( $string, '|'), '|'))" />
<xsl:if test="$item">
<item>
<xsl:value-of select="$item" />
</item>
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="substring-after($string,'|')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Using XPATHs from file and adding relevant attribute

May be my XSL approach is wrong? please correct me the way to handle this situation
I want to grab XPATHs and Attrs from a mapping file, then use XPATH to match, and apply attributes to XML.
Here is my 3 inputs files:
mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<map xpath="//title" class="title" others="moreToCome" />
<map xpath="//subtitle" class="subtitle" others="moreToCome" />
<map xpath="//p" class="p" others="moreToCome" />
</mappings>
Source.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>title text</title>
<subtitle>subtitle text</subtitle>
<p>subtitle text</p>
</root>
StyleMapping.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="fMappings" select="document('mappings.xml')" />
<xsl:variable name="xpath"><xsl:text>justToMakeItGlobal</xsl:text></xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
<!-- loop thru map in mappings.xml -->
<xsl:for-each select="$fMappings//mappings/map">
<xsl:call-template name="dyn">
<xsl:with-param name="xpath" select="#xpath" />
<xsl:with-param name="class" select="#class" />
<xsl:with-param name="others" select="#others" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template match="$xpath" mode="dyn">
<xsl:param name="xpath"/>
<xsl:param name="class"/>
<xsl:param name="others"/>
<xsl:attribute name="class"><xsl:value-of select="$class" /></xsl:attribute>
<xsl:attribute name="others"><xsl:value-of select="$others" /></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
This is what is planning to do, but i'm not getting the correct way of doing it in XSLT:
1. Read mappings.xml file
2. Loop thru each map tag
3. grab xpath and attr's
4. apply template match/select with above xpath
5. add attr's to above selected nodes
output.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title class="title" others="moreToCome">title text</title>
<subtitle class="subtitle" others="moreToCome">subtitle text</subtitle>
<p class="p" others="moreToCome">subtitle text</p>
</root>
I don't think you can have a template with a calculated match pattern. Let me suggest a different approach:
mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<map elem="title" class="Title" others="moreToCome1" />
<map elem="subtitle" class="Subtitle" others="moreToCome2" />
<map elem="p" class="P" others="moreToCome3" />
</mappings>
stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<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:variable name="mappings" select="document('mappings.xml')/mappings" />
<xsl:template match="*">
<xsl:variable name="elem" select="name()" />
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:if test="$elem = $mappings/map/#elem">
<xsl:attribute name="class">
<xsl:value-of select="$mappings/map[#elem=$elem]/#class"/>
</xsl:attribute>
<xsl:attribute name="others">
<xsl:value-of select="$mappings/map[#elem=$elem]/#others"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Testing with the following source XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title original="yes">title text</title>
<subtitle>subtitle text</subtitle>
<p>para text</p>
<nomatch attr="test">another text</nomatch>
</root>
results in:
<?xml version="1.0" encoding="utf-8"?>
<root>
<title original="yes" class="Title" others="moreToCome1">title text</title>
<subtitle class="Subtitle" others="moreToCome2">subtitle text</subtitle>
<p class="P" others="moreToCome3">para text</p>
<nomatch attr="test">another text</nomatch>
</root>

XSLT multiple stylesheets

I have the following xml
<TopLevel>
<data m="R263">
<s ut="263firstrecord" lt="2013-02-16T09:21:40.393" />
<s ut="263secondrecord" lt="2013-02-16T09:21:40.393" />
</data>
<data m="R262">
<s ut="262firstrecord" lt="2013-02-16T09:21:40.393" />
<s ut="262secondrecord" lt="2013-02-16T09:21:40.393" />
</data>
</TopLevel>
I have some XSLT that does the call template but it's not itterating correctly.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="data">
<xsl:value-of select="#m" />
<xsl:variable name="vYourName" select="#m"/>
<xsl:choose>
<xsl:when test="#m='R262'">
<xsl:call-template name="R262"/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="#m='R263'">
<xsl:call-template name="R263"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="R262">
<xsl:for-each select="/TopLevel/data/s">
Column1=<xsl:value-of select="#ut" />
Column2=<xsl:value-of select="#lt" />
</xsl:for-each>
</xsl:template>
<xsl:template name="R263">
<xsl:for-each select="/TopLevel/data/s">
Column1=<xsl:value-of select="#ut" />
Column2=<xsl:value-of select="#lt" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This gives me 8 records insead of the 4 (<s> level) records. I know it has to do with my iteration ... but I am not sure how to address this.
I am also aware of the apply stylesheets but I couldn't unravel that mystery either ... If someone can help me with XSLT that will only process everything from <TopLevel> to <\TopLevel> checking the value of m at the <data> level and applying the stylesheet at the <s> level for each <s> record I will be greateful beyond belief.
I don't know what output you want to produce, but I suspect you want to replace
<xsl:for-each select="/TopLevel/data/s">
by
<xsl:for-each select="s">
that is, you only want to process the "s" elements within the "data" you are currently processing, rather than selecting all the "s" elements in the whole document.
Why not do this using apply-templates?
<xsl:template match="data">
...
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="s[../#m='R262']">
...
</xsl:template>
<xsl:template match="s[../#m='R263']">
...
</xsl:template>
If you want to use match template and apply-templates you could do the following which gives you also a text output just like your stylesheet does. So this XSLT applied to your original source XML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="data">
<xsl:value-of select="#m"/>
<xsl:apply-templates select="s"/>
</xsl:template>
<xsl:template match="s">
Column1=<xsl:value-of select="#ut"/>
Column2=<xsl:value-of select="#lt"/>
</xsl:template>
</xsl:stylesheet>
gives you this output:
<?xml version="1.0" encoding="UTF-8"?>
R263
Column1=263firstrecord
Column2=2013-02-16T09:21:40.393
Column1=263secondrecord
Column2=2013-02-16T09:21:40.393
R262
Column1=262firstrecord
Column2=2013-02-16T09:21:40.393
Column1=262secondrecord
Column2=2013-02-16T09:21:40.393
You basically only match on the s and give out the attributes "ut" and "lt". You can also output XML which would look better.
Using this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="data">
<list>
<xsl:apply-templates select="s"/>
</list>
</xsl:template>
<xsl:template match="s">
<xsl:element name="record">
<xsl:attribute name="m">
<xsl:value-of select="parent::data/#m"/>
</xsl:attribute>
<item>Column1=<xsl:value-of select="#ut"/></item>
<item>Column2=<xsl:value-of select="#lt"/></item>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
will give you this nice XML output:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<list>
<record m="R263">
<item>Column1=263firstrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
<record m="R263">
<item>Column1=263secondrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
</list>
<list>
<record m="R262">
<item>Column1=262firstrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
<record m="R262">
<item>Column1=262secondrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
</list>
You have to adapt the original XSLT a little bit to get a nice XML structure. Also when matching s you "climb" up to element data to get the R-numbers for your attribute values.
The template matching root you need for a proper XML root element. <list> you could also get rid off then you have <record> as child of <root>.

XSLT: How to reverse output without sorting by content

I have a list of items:
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
and I want as output
z
c
x
a
I have no order information in the file and I just want to reverse the lines. The last line in the source file should be first line in the output. How can I solve this problem with XSLT without sorting by the content of the items, which would give the wrong result?
I will present two XSLT solutions:
I. XSLT 1.0 with recursion Note that this solution works for any node-set, not only in the case when the nodes are siblings:
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:call-template name="reverse">
<xsl:with-param name="pList" select="*"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="reverse">
<xsl:param name="pList"/>
<xsl:if test="$pList">
<xsl:value-of
select="concat($pList[last()], '
')"/>
<xsl:call-template name="reverse">
<xsl:with-param name="pList"
select="$pList[not(position() = last())]"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</t>
produces the wanted result:
z
c
x
a
II. XSLT 2.0 solution :
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:value-of select="reverse(*)/string(.)"
separator="
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the same XML document, the same correct result is produced.
XML CODE:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<device>
<element>a</element>
<element>x</element>
<element>c</element>
<element>z</element>
</device>
XSLT CODE:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//device">
<xsl:for-each select="element">
<xsl:sort select="position()" data-type="number" order="descending"/>
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
note: if you're using data-type="number", and any of the values aren't numbers, those non-numeric values will sort before the numeric values. That means if you're using order="ascending", the non-numeric values appear first; if you use order="descending", the non-numeric values appear last.
Notice that the non-numeric values were not sorted; they simply appear in the output document in the order in which they were encountered.
also, you may find usefull to read this:
http://docstore.mik.ua/orelly/xml/xslt/ch06_01.htm
Not sure what the full XML looks like, so I wrapped in a <doc> element to make it well formed:
<doc>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</doc>
Running that example XML against this stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:call-template name="reverse">
<xsl:with-param name="item" select="doc/item[position()=last()]" />
</xsl:call-template>
</xsl:template>
<xsl:template name="reverse">
<xsl:param name="item" />
<xsl:value-of select="$item" />
<!--Adds a line feed-->
<xsl:text>
</xsl:text>
<!--Move on to the next item, if we aren't at the first-->
<xsl:if test="$item/preceding-sibling::item">
<xsl:call-template name="reverse">
<xsl:with-param name="item" select="$item/preceding-sibling::item[1]" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Produces the requested output:
z
c
x
a
You may need to adjust the xpath to match your actual XML.
Consider this XML input:
<?xml version="1.0" encoding="utf-8" ?>
<items>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</items>
The XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/items[1]">
<xsl:variable name="items-list" select="." />
<xsl:variable name="items-count" select="count($items-list/*)" />
<xsl:for-each select="item">
<xsl:variable name="index" select="$items-count+1 - position()"/>
<xsl:value-of select="$items-list/item[$index]"/>
<xsl:value-of select="'
'"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And the result:
z
c
x
a