Reputation: 247
I'm producing a simple HTML web page, using a Book Store example, and outputting my web page's content through a combination of XML data and XSLT(1.0), but I've recently come across an issue I'd like to receive some feedback and advice on from the StackOverflow community.
Background:
In my Book Store example, I have a series of main elements called <book></book>
which contain important details about the publications such as the <title></title>
and <author></author>
.
Now, within each of these <book></book>
elements I have a further important element called <promotions></promotions>
, which contain single ID numbers (<promotionNum></promotionNum>
), that act as primary keys to link to corresponding nodes in a further element which deal with the promotions in more detail.
The XML Structure:
<bookstore>
<book>
<title>Harry Potter and the Philosopher's Stone</title>
<author>J K. Rowling</author>
<year>1997</year>
<price>3.99</price>
<publisher>Bloomsbury (UK)</publisher>
<synopsis>
Harry Potter and the Philosopher's Stone is the first novel in the Harry Potter series and J. K. Rowling's debut novel.
The plot follows Harry Potter, a young wizard who discovers his magical heritage as he makes close friends and a few enemies in his first year at the Hogwarts School of Witchcraft and Wizardry.
With the help of his friends, Harry faces an attempted comeback by the dark wizard Lord Voldemort, who killed Harry's parents, but failed to kill Harry when he was just a year old.
</synopsis>
<promotions>
<promotionNum>1</promotionNum>
<promotionNum>2</promotionNum>
<promotionNum>3</promotionNum>
<promotionNum>4</promotionNum>
</promotions>
</book>
<book>
<title>The Girl with the Dragon Tattoo</title>
<author>Stieg Larsson</author>
<year>2005</year>
<price>5.99</price>
<publisher>Norstedts Förlag (SWE)</publisher>
<synopsis>
In Stockholm, Sweden, journalist Mikael Blomkvist, co-owner of Millennium magazine, has lost a libel case brought against him by businessman Hans-Erik Wennerström. Lisbeth Salander, a brilliant but troubled investigator and hacker, compiles an extensive background check on Blomkvist for business magnate Henrik Vanger, who has a special task for him.
In exchange for the promise of damning information about Wennerström, Blomkvist agrees to investigate the disappearance and assumed murder of Henrik's grandniece, Harriet, 40 years ago.
After moving to the Vanger family's compound, Blomkvist uncovers a notebook containing a list of names and numbers that no one has been able to decipher.
</synopsis>
<promotions>
<promotionNum>5</promotionNum>
<promotionNum>6</promotionNum>
<promotionNum>3</promotionNum>
<promotionNum>2</promotionNum>
</promotions>
</book>
<promotion>
<promotionID>1</promotionID>
<percentageOff>10</percentageOff>
<promotionalMerchandise>No</promotionalMerchandise>
<promotionStartDate>2015-10-14T00:00:00</promotionStartDate>
<promotionEndDate>2015-10-19T00:00:00</promotionEndDate>
</promotion>
<promotion>
<promotionID>2</promotionID>
<percentageOff>15</percentageOff>
<promotionalMerchandise>No</promotionalMerchandise>
<promotionStartDate>2015-10-11T00:00:00</promotionStartDate>
<promotionEndDate>2015-10-16T00:00:00</promotionEndDate>
</promotion>
<promotion>
<promotionID>3</promotionID>
<percentageOff>30</percentageOff>
<promotionalMerchandise>Yes</promotionalMerchandise>
<promotionStartDate>2015-09-02T00:00:00</promotionStartDate>
<promotionEndDate>2015-09-07T00:00:00</promotionEndDate>
</promotion>
<promotion>
<promotionID>4</promotionID>
<percentageOff>5</percentageOff>
<promotionalMerchandise>Yes</promotionalMerchandise>
<promotionStartDate>2015-11-22T00:00:00</promotionStartDate>
<promotionEndDate>2015-11-27T00:00:00</promotionEndDate>
</promotion>
<promotion>
<promotionID>5</promotionID>
<percentageOff>50</percentageOff>
<promotionalMerchandise>No</promotionalMerchandise>
<promotionStartDate>2015-08-13T00:00:00</promotionStartDate>
<promotionEndDate>2015-08-18T00:00:00</promotionEndDate>
</promotion>
<promotion>
<promotionID>6</promotionID>
<percentageOff>80</percentageOff>
<promotionalMerchandise>No</promotionalMerchandise>
<promotionStartDate>2015-07-01T00:00:00</promotionStartDate>
<promotionEndDate>2015-07-05T00:00:00</promotionEndDate>
</promotion>
</bookstore>
What Do I Want to Achieve?
For each <book></book>
element, I want to loop through the associated <promotions></promotions>
, using either a <xsl:for-each>
statement or a <template></template>
capturing the <promotionNum>
numerical ID in a variable, e.g. $IDNum
.
Then using my ID variable as validation, I'd like to cross reference this number against the six <promotion>
elements. If we successfully have a match, e.g. <xsl:for-each select="dataroot/Promotion"><xsl:if test="$IDNum">
, I then want to capture the value of the <promotionEndDate>
node in a further variable.
But here's the important part, I want to find the latest date (or largest value). So, for <title>Harry Potter and the Philosopher's Stone</title>
, of the four associated promotion elements (1-4) I'd expect to retrieve <promotionEndDate>2015-11-27T00:00:00</promotionEndDate>
(latest date) from <promotion><promotionID>4</promotionID></promotion>
.
I'm aware that unlike XSLT 2.0, XSLT 1.0 and dates aren't compatible, so when creating the variable to store the <promotionEndDate></promotionEndDate>
,there would need to be a substring treatment after 'T' and then a translate treatment to lose the hyphens, giving you a valid figure to work with, e.g. 2015-11-27T00:00:00
becomes 20151127
(i.e. numerical).
Why? I want to know the final date a promotion will run for on any chosen publication.
Is this possible to achieve using XSLT 1.0? For each <promotionEndDate></promotionEndDate>
node could I run the substring/translate treatment, and then have a template which captures this date figure in a variable and then compares it against the next available date value passed through the template. If this new figure is gt;
than the previous, this then becomes the new highest figure?
Any advice, as always would be warmly received!!
Upvotes: 1
Views: 2621
Reputation: 167706
Use a key for the cross-references and then sort them on that date to find the latest (highest number):
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="prom-by-id" match="bookstore/promotion" use="promotionID"/>
<xsl:template match="bookstore">
<xsl:apply-templates select="book"/>
</xsl:template>
<xsl:template match="book">
<xsl:copy>
<xsl:copy-of select="title"/>
<xsl:for-each select="key('prom-by-id', promotions/promotionNum)">
<xsl:sort select="translate(promotionEndDate, '-T:', '')" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You have said that you want HTML as the output but as you have not shown any of your XSLT code creating the HTML for a book
element I have chosen to simply output the book
itself and its cross-referenced promotion
, of course you can change the template to output HTML, the approach to find the promotion remains the same.
Upvotes: 1