 |
| XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

July 4th, 2013, 06:59 PM
|
|
Authorized User
|
|
Join Date: Jun 2013
Posts: 21
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
XSLT-displaying the number followed by alphabets
<PassengerList>
<SeatNumber>1A</SeatNumber>
<SeatNumber>1B</SeatNumber>
<SeatNumber>1D</SeatNumber>
<SeatNumber>1E</SeatNumber>
<SeatNumber>1F</SeatNumber>
<SeatNumber>1G</SeatNumber>
<SeatNumber>2B</SeatNumber>
<SeatNumber>2D</SeatNumber>
<SeatNumber>3A</SeatNumber>
<SeatNumber>3B</SeatNumber>
<SeatNumber>3D</SeatNumber>
<SeatNumber>3E</SeatNumber>
<SeatNumber>4A</SeatNumber>
<SeatNumber>4B</SeatNumber>
<SeatNumber>4E</SeatNumber>
<SeatNumber>4F</SeatNumber>
<SeatNumber>4G</SeatNumber>
<SeatNumber>4J</SeatNumber>
</PassengerList>
I need the output to be:
1ABDEFG2BD3ABDE4ABEFGJ
I tried to implement using array ,but i can able display element only, not in the specified format.
<xsl:variable name="array" as="element()*"/>
<xsl:variable name="arrayCount">
<xsl:value-of select="count(//FlightLeg/FlightSummary/CabinSummary[1]/VacantSeatNumberList/SeatNumber)" />
</xsl:variable>
<xsl:value-of select="$parray"/>
<!--
<xsl:if test="$arrayCount > 0">
<xsl:value-of select="$parray[position()]" />
<xsl:call-template name="for-loop">
<xsl:with-param name="arrCount" select="$arrCount - 1"/>
</xsl:call-template>
</xsl:if> -->
Note: Outputtype = "text"
I am strugglling for the last 2 days for this required output. Can you please help me in displaying like above with numbers followed by alphabets.
Last edited by sen1953; July 5th, 2013 at 02:09 AM..
|
|

July 5th, 2013, 11:46 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
|
|
I can think of at least 3 different ways. Recursion (parse the first item, pass the initial character into another call etc), use the preceding-sibling::*[1] to get the previous element and test that, or in XSLT 2.0 use the xsl:for-each-group instruction with the group-adjacent attribute to group by the starting letter.
Can you show us what you have tried and we can probably help you.
|
|

July 5th, 2013, 12:55 PM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Your posted code sample suggest you can use XSLT 2.0 so assuming an XSLT 2.0 processor you can easily group:
Code:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="text"/>
<xsl:template match="PassengerList">
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
That transforms
Code:
<PassengerList>
<SeatNumber>1A</SeatNumber>
<SeatNumber>1B</SeatNumber>
<SeatNumber>1D</SeatNumber>
<SeatNumber>1E</SeatNumber>
<SeatNumber>1F</SeatNumber>
<SeatNumber>1G</SeatNumber>
<SeatNumber>2B</SeatNumber>
<SeatNumber>2D</SeatNumber>
<SeatNumber>3A</SeatNumber>
<SeatNumber>3B</SeatNumber>
<SeatNumber>3D</SeatNumber>
<SeatNumber>3E</SeatNumber>
<SeatNumber>4A</SeatNumber>
<SeatNumber>4B</SeatNumber>
<SeatNumber>4E</SeatNumber>
<SeatNumber>4F</SeatNumber>
<SeatNumber>4G</SeatNumber>
<SeatNumber>4J</SeatNumber>
</PassengerList>
into
Code:
1ABDEFG2BD3ABDE4ABEFGJ
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|

July 7th, 2013, 03:55 AM
|
|
Authorized User
|
|
Join Date: Jun 2013
Posts: 21
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL
<?xml version="1.0" encoding="UTF-8"?>
<seatgroups>
<abcd>firstelement</abcd>
<abc>secondelement</abc>
<PassengerList>
<SeatNumber>1A</SeatNumber>
<SeatNumber>1B</SeatNumber>
<SeatNumber>1D</SeatNumber>
<SeatNumber>1E</SeatNumber>
<SeatNumber>1F</SeatNumber>
<SeatNumber>1G</SeatNumber>
<SeatNumber>2B</SeatNumber>
<SeatNumber>2D</SeatNumber>
<SeatNumber>3A</SeatNumber>
<SeatNumber>3B</SeatNumber>
<SeatNumber>3D</SeatNumber>
<SeatNumber>3E</SeatNumber>
<SeatNumber>4A</SeatNumber>
<SeatNumber>4B</SeatNumber>
<SeatNumber>4E</SeatNumber>
<SeatNumber>4F</SeatNumber>
<SeatNumber>4G</SeatNumber>
<SeatNumber>4J</SeatNumber>
</PassengerList>
<next>Antony</next>
<next>Britto</next>
</seatgroups>
Actual output now:firstelementsecondelement1ABDEFG2BD3ABDE4ABEFG JAntonyBritto
The problem is I need seat number alone. but its printing all the elements
in the xml.But the expected output is 1ABDEFG2BD3ABDE4ABEFGJ. I tried many xpath for the actual result. But I need seat number from the xml.
Why its printing all the elements from the xml even though given correct xml...Please clarify it please.
Thanks in advance
XSL file:
/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="PassengerList">
<!--<xsl:apply-templates select="PassengerList/SeatNumber"/>-->
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Last edited by sen1953; July 7th, 2013 at 04:22 AM..
Reason: correct format
|
|

July 7th, 2013, 04:20 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
The rest of the code you need is completely bog-standard XSLT. If you don't know how to write it, there are some good Wrox books to learn from.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
|
|

July 7th, 2013, 06:54 AM
|
|
Authorized User
|
|
Join Date: Jun 2013
Posts: 21
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
Thanks mckay and Martin
Its perfectly working for me now. But am not going to use as template ,instead of that i written code like this its works fine. it wont bring the all nodes as well.. But i dont know the reason why its brings all nodes when it apply through template match.
Thanks KAY and Martin...
This is the xsl code
<xsl:template match="/">
<xsl:for-each-group select="//seatgroups/PassengerList/SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
</xsl:template>
output is : 1A1B1D1E1F1G2B2D3A3B3D3E4A4B4E4F4G4J
Thanks I solved it Martin...
|
|

July 7th, 2013, 07:06 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
It is good that you managed to adapt the code to your needs. If you want to go with a template based solution then you simply need to be aware that there a built-in templates (see http://www.w3.org/TR/xslt#built-in-rule) that by default output values. Thus if all you write is a template
Code:
<xsl:template match="PassengerList">
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
</xsl:template>
then the default templates kick in for the nodes (and ensure the above template is used at all) but you need to ensure that unwanted output is suppressed.
There are basically two ways to ensure that, either explicitly ensure that certain elements don't output anything with e.g.
Code:
<xsl:template match="next | abc | abcd"/>
or ensure that only the elements are processed you want to be processed with
Code:
<xsl:template match="/">
<xsl:apply-templates select="//PassengerList"/>
</xsl:template>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|

July 12th, 2013, 07:47 AM
|
|
Authorized User
|
|
Join Date: Jun 2013
Posts: 21
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
getting value from for-each group
Code:
<xsl:template match="PassengerList">
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
</xsl:template>
This is the output
1ABDEFG2BD3ABDE4ABEFG
Required format
1ABDEFG 2BD 3ABDE 4ABEFG
Need to separate with single space between new seats as well..
I tried this code by below
Code:
<xsl:template match="PassengerList">
<xsl:variable name="seatgroup">
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
</xsl:variable>
<xsl:value-of select="$seatgroup"/>
</xsl:template>
But am not able to get this variable value. How to get this value from the for-each group? So that I can do string functions or replace for my requirement.
Additionaly I want to know that , any chance to get the required output by modifying the code as well. why my variable is not populating with output?
Please clarify me. thanks in advance
|
|

July 12th, 2013, 07:53 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Use
Code:
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<xsl:if test="position() gt 1"><xsl:text> </xsl:text></xsl:if>
<xsl:value-of select="current-grouping-key(), current-group()/replace(., '[0-9]+', '')" separator=""/>
</xsl:for-each-group>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|
The Following User Says Thank You to Martin Honnen For This Useful Post:
|
|
|

July 12th, 2013, 09:25 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
XSLT and XPath 2.0 operate on sequences of nodes or atomic values like strings or numbers or dates. In the case of your sample the variable named "seatgroup" is a document node with a single text child node containing the string "1ABDEFG2BD3ABDE4ABEFG" so you can't access any particular items, unless you use string processing (substring($seatgroup, 2, 4)). If you want to create structured data use XML e.g.
Code:
<xsl:template match="PassengerList">
<xsl:variable name="seatgroup">
<xsl:for-each-group select="SeatNumber" group-by="replace(., '[^0-9]+', '')">
<group seat="{current-grouping-key()}">
<xsl:for-each select="current-group()/replace(., '[0-9]+', '')">
<item><xsl:value-of select="."/></item>
<xsl:for-each>
</group>
</xsl:for-each-group>
</xsl:variable>
<xsl:value-of select="$seatgroup/group/@seat"/> <!-- outputs '1 2 3 4' -->
<xsl:value-of select="$seatgroup/group[2]/item"/> <!-- outputs 'B D' -->
</xsl:template>
I hope that helps. Consider to start a new question with all details (input you want, output you want to create) if you need more help. And there are introductory books like Beginning XSLT that should help: http://www.wrox.com/WileyCDA/WroxTit...470477253.html
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|
 |