 |
| 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
|
|
|
|

March 12th, 2009, 11:22 AM
|
|
Authorized User
|
|
Join Date: Feb 2009
Posts: 43
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Getting unique values from substring
Martin,
I'm sorry I am starting another thread with the same title. I can't post a reply to the other thread I started.
As requested My xml is below
Code:
<Properties>
<Data>
- <Result>
- <PRList>
<PressRelease dcr="">
<date>10/02/2008</date>
<title>Title</title>
<content></content>
</PressRelease>
<PRList>
</Result>
</Data>
</Properties>
Please let me know if this is complete enough
Once again my xsl is as follows....
Code:
<xsl:for-each select="$dcr">
<!--xsl:for-each select="$dcr[generate-id() = generate-id(key('by-month', substring(date,1,2))[1])]"-->
<!--xsl:sort select="substring(date,1,2)" order="ascending"/-->
<xsl:variable name="yearn" select="substring(date,7,4)"/>
<xsl:variable name="monthn" select="substring(date,1,2)"/>
<!--xsl:value-of select="$currentYear"/><xsl:value-of select="$yearn"/><br/-->
<xsl:choose>
<xsl:when test="$currentYear = $yearn">
<tr>
<td align="top" valign="middle">
<!--b><xsl:value-of select="substring(date,1,2)"/></b><br/-->
<a href="$PAGE_LINK[/press-releases/detail]dcr={@dcr}"><xsl:value-of select="title"/></a><br/>
</td>
</tr>
</xsl:when>
</xsl:choose>
</xsl:for-each>
I commented out
Code:
<!--xsl:for-each select="$dcr[generate-id() = generate-id(key('by-month', substring(date,1,2))[1])]"-->
for now.
Once again my goal is
Month i.e. Janaury
Press release 1
Press release 2
Date
Month i.e.February
Press release 1
Press release 2
Date
Thanks.
|
|

March 12th, 2009, 12:52 PM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Well you need to use Muenchian grouping in XSLT 1.0 to group on your month component.
As for your code samples, no, that does not help us to tell you where it goes wrong, the input markup sample is not even well-formed XML and if you want help with grouping then there should be enough data to at least populate a few groups. And that stylesheet would need to show how the key is defined, how the variables are set up. So if you want help in explaining why your stylesheet does not work as expected then post minimal but complete samples that we can run without any need for editing them first.
In the meantime, here is some working sample. I produced the following XML input sample:
Code:
<Properties>
<Data>
<Result>
<PRList>
<PressRelease dcr="">
<date>10/02/2008</date>
<title>release 1</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>10/03/2008</date>
<title>release 2</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>01/03/2008</date>
<title>release 3</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>01/12/2008</date>
<title>release 4</title>
<content></content>
</PressRelease>
</PRList>
</Result>
</Data>
</Properties>
then wrote the following stylesheet
Code:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:data="http://example.com/2009/mh"
exclude-result-prefixes="data"
version="1.0">
<xsl:output method="text"/>
<xsl:key name="by-month"
match="PressRelease"
use="substring-before(date, '/')"/>
<data:data>
<month number="01">January</month>
<month number="02">February</month>
<month number="03">March</month>
<month number="04">April</month>
<month number="05">May</month>
<month number="06">June</month>
<month number="07">July</month>
<month number="08">August</month>
<month number="09">September</month>
<month number="10">October</month>
<month number="11">November</month>
<month number="12">December</month>
</data:data>
<xsl:template match="/">
<xsl:for-each select="Properties/Data/Result/PRList/PressRelease[generate-id() = generate-id(key('by-month', substring-before(date, '/'))[1])]">
<xsl:sort select="substring-before(date, '/')"/>
<xsl:value-of select="document('')/xsl:stylesheet/data:data/month[@number = substring-before(current()/date, '/')]"/>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('by-month', substring-before(date, '/'))/title">
<xsl:value-of select="concat(., '
')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
that when run with Saxon 6.5.5 produces the following output:
January
release 3
release 4
October
release 1
release 2
So that is grouped and sorted fine by the month component accessed using substring-before(date, '/').
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|

March 13th, 2009, 01:21 AM
|
|
Authorized User
|
|
Join Date: Feb 2009
Posts: 43
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Thanks Martin. Sorry for being a pain.
The code you sent worked. I just have one problem. The xml I am working with contains data for different years e.g 2009, 2007 etc.
In the light of this, your currently code returns all the press releases per month i.e January regardless of the year, I also need to filter this by year.
I tried this with your code....
Code:
<xsl:for-each select="$dcr[generate-id() = generate-id(key('by-month', substring-before(date, '/'))[1])]">
<xsl:sort select="substring-before(date, '/')"/>
<tr>
<td align="top" valign="middle" class="MarkitBodyText">
<xsl:value-of select="substring-before(current()/date, '/')"/><br/>
<xsl:for-each select="key('by-month', substring-before(date, '/'))/title">
<xsl:if test="$currentYear = substring(date,7,4)"-->
<xsl:value-of select="concat(., '')"/><br/>
</xsl:if-->
</xsl:for-each>
</td>
</tr>
</xsl:for-each>
But the if statement did not return any Press release titles, thus it is no filtering on the year portion of the date.
The variables are defined thus
Code:
<xsl:variable name="currentYear">
<xsl:choose>
<xsl:when test="$year = ''">
<xsl:value-of select="datetime:year()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$year"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="yearn" select="substring(date,7,4)"/>
The ideas is that if no $year parameter is passed to this component, $currentYear is set to the current year, all the press releases for the current year and then pasred for display. That is the bit I can't get to work -
Thanks again
|
|

March 13th, 2009, 11:01 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
If you have data in different years then the key needs to be adapted to include the year as well as the month.
So extending my earlier example we now have the example file as
Code:
<Properties>
<Data>
<Result>
<PRList>
<PressRelease dcr="">
<date>10/02/2008</date>
<title>release 1</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>10/03/2008</date>
<title>release 2</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>01/03/2008</date>
<title>release 3</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>01/12/2008</date>
<title>release 4</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>09/02/2009</date>
<title>release 5</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>09/03/2009</date>
<title>release 6</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>01/03/2009</date>
<title>release 7</title>
<content></content>
</PressRelease>
<PressRelease dcr="">
<date>01/12/2009</date>
<title>release 8</title>
<content></content>
</PressRelease>
</PRList>
</Result>
</Data>
</Properties>
then the stylesheet as follows:
Code:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:data="http://example.com/2009/mh"
xmlns:datetime="http://exslt.org/dates-and-times"
exclude-result-prefixes="data datetime"
version="1.0">
<xsl:output method="text"/>
<xsl:param name="yearParam" select="''"/>
<xsl:variable name="year">
<xsl:choose>
<xsl:when test="$yearParam = ''">
<xsl:value-of select="datetime:year()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$yearParam"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:key name="by-month"
match="PressRelease"
use="concat(substring-after(substring-after(date, '/'), '/'), '-', substring-before(date, '/'))"/>
<data:data>
<month number="01">January</month>
<month number="02">February</month>
<month number="03">March</month>
<month number="04">April</month>
<month number="05">May</month>
<month number="06">June</month>
<month number="07">July</month>
<month number="08">August</month>
<month number="09">September</month>
<month number="10">October</month>
<month number="11">November</month>
<month number="12">December</month>
</data:data>
<xsl:template match="/">
<xsl:value-of select="concat('Press releases in ', $year, ':
')"/>
<xsl:for-each select="Properties/Data/Result/PRList/PressRelease[$year = substring-after(substring-after(date, '/'), '/')][generate-id() = generate-id(key('by-month', concat(substring-after(substring-after(date, '/'), '/'), '-', substring-before(date, '/')))[1])]">
<xsl:sort select="substring-before(date, '/')"/>
<xsl:value-of select="document('')/xsl:stylesheet/data:data/month[@number = substring-before(current()/date, '/')]"/>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('by-month', concat(substring-after(substring-after(date, '/'), '/'), '-', substring-before(date, '/')))/title">
<xsl:value-of select="concat(., '
')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When run against the sample input without setting the yearParam parameter the result with Saxon 6.5.5 is
Press releases in 2009:
January
release 7
release 8
September
release 5
release 6
when run with Saxon 6.5.5 when setting yearParam=2008 the result is as follows:
Press releases in 2008:
January
release 3
release 4
October
release 1
release 2
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|

March 13th, 2009, 12:37 PM
|
|
Authorized User
|
|
Join Date: Feb 2009
Posts: 43
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Martin - thanks very much for the time you have taken to help.
Finally -one last question
I also need to display the date for every press release title
The code below <xsl:value-of select="$dcr/date"/> only returns the first date.
Code:
<xsl:for-each select="key('by-month', concat(substring-after(substring-after(date, '/'), '/'), '-', substring-before(date, '/')))/title">
<xsl:value-of select="concat(., '')"/><br/>
<xsl:value-of select="date"/>
</xsl:for-each><br/>
Thanks again.
|
|

March 13th, 2009, 12:46 PM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
In the for-each you select the title element so I am astonished that you say it outputs the first date. Given your sample the title element is a sibling of the date element so your for-each should not find any date at all.
Try whether
Code:
<xsl:for-each select="key('by-month', concat(substring-after(substring-after(date, '/'), '/'), '-', substring-before(date, '/')))">
<xsl:value-of select="title"/><br/>
<xsl:value-of select="date"/>
</xsl:for-each>
gives you what you are looking for. If not then you will need to post a relevant sample of the XML you have again.
__________________
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:
|
|
|

March 13th, 2009, 03:10 PM
|
|
Authorized User
|
|
Join Date: Feb 2009
Posts: 43
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Thanks Martin - that was exactly what I wanted.
|
|
 |