• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Book Promotion and Past Winners in XSLT

 
Sheriff
Posts: 3341
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I felt the these pages could benfit from using XML. The main objective is to ease the burden of maintenance. The overall arcatecture is maintin the bulk of the page in jsp. This allows easy integration with the rest of the site which has the common header and footer as an included jsp page. To incorporate the xml, I am going with the Jakarta jsp taglib xsl. I have created the initial DTD, XML, XSL and JSP pages.
They can be found here: http://www.javaranch.com/carl/xmlindex.html
What should be the next step?
 
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is what I would do. First, I would use one file for each book/promotion item. Second, I would use a lineup file to include only those that I would like to include on those two pages.
The reason is that once the single XML file becomes bigger it will become quite difficult to handle. If you have a separate file for each book, then they become the de facto archives for you anyway. With the lineup, you can pick the ones that need to be included.
Say, the following book (guess which one I chose) will be in a file called "20010313.xml".
<promotion>
<date>03/13/2001</date>
<book url="http://www.amazon.com/exec/obidos/ASIN/0201711036/ref=ase_electricporkchop/107-0402457-1632559">XSLT: Working with XML and HTML</book>
<author url="http://www.javaranch.com/cgi-bin/ubb/ubbmisc.cgi?action=getbio&UserName=Khun+Yee+Fung">Khun Yee Fung</author>
<publisher url="http://www.awl.com/">Addison-Wesley</publisher>
<forum url="http://www.javaranch.com/cgi-bin/ubb/forumdisplay.cgi?action=topics&forum=XML,+XSL,+DOM+and+SAX&number=31&DaysPrune=1000&LastLogin=">XML, XSL, DOM and SAX</forum>
<status>Confirmed</status>
<complete>false</complete>
</promotion>
The lineup XML file might look like:
<lineup>
<promotion date='20010313'/>
<promotion date='20010320'/>
<promotion date='20010327'/>
</lineup>
Now, how to construct the lineup file is really up to you. For instance, if you always have a book to promote for each week, and you want to show the most recent 10 weeks, then all you need is an element to specify the starting date and the number of weeks to cover.
Notice the lineup file I include here contains two dates that have not arrived yet. Well, you can specify whatever the behaviour should be when that happens. Since you will need the document() function to open the XML files, you will know whether a file has been successfully opened.
I would generate the two files offline and then get the JSP to include the HTML files generated. If you only have to worry about these two pages, this is all you need to do. In this way, the XML and XSLT files are safely in your own directories. You move the HTML files to wherever you have to.
A few comments about the XML: I would not specify dates in this way. I would use attributes and separate the day of the month, the month, and the year. Same idea with the book URL: if you have the separate elements that can be used to construct the URL, you might as well specify the data somewhere else. In this way it is not as easy to have an incorrect entry. In fact, I would combine status and completion together as well. Then, I would have an element called "winners" to contain all the winners.
The entry for my book would then become:
<promotion day="13" month="3" year="2001" status='Confirmed' complete='False'>
<book ISBN='0201711036'>XSLT: Working with XML and HTML</book>
<author name='Khun+Yee+Fung'>Khun Yee Fung</author>
<publisher url="http://www.awl.com/">Addison-Wesley</publisher>
<forum forum='XML,+XSL,+DOM+and+SAX">XML, XSL, DOM and SAX</forum>
</promotion>
And the common information is in the common.xml file:
<common>
<amazon prefix='http://www.amazon.com/exec/obidos/ASIN' suffix='ref=ase_electricporkchop/107-0402457-1632559'/>
<author prefix='http://www.javaranch.com/cgi-bin/ubb/ubbmisc.cgi?action=getbio&UserName='/>
<forum prefix='http://www.javaranch.com/cgi-bin/ubb/forumdisplay.cgi?action=topics&forum=' suffix='&number=31&DaysPrune=1000&LastLogin='/>
</common>
You can provide the reference to the common XML in the lineup file, or you can hardcode that in your XSLT, or you can pass the file name of the common file in as a global parameter.
Another example of a promotion:
<promotion day='09' month='01' year='2001' status='Confirmed' complete='True'>
<giftCetificate>Amazon Gift Certificate</giftCetificate>
<winners>
<winner>Travis Gibson</winner>
<winner>Shaochun Xu</winner>
<winner>Justin Moore</winner>
<winner>Nancy Marik</winner>
</winners>
</promotion>
I wonder whether I can combine the status and the complete attributes too. The state transition might look like: empty -> pending -> confirmed -> completed.
My goals are: easy to process by hand and easy to avoid errors. But you might have a different set of criteria when you design your XML files.
Tomorrow, we will look at the XSLT files.

------------------
Khun Yee Fung
Author of XSLT: Working with XML and HTML
 
Carl Trusiak
Sheriff
Posts: 3341
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank You Khun,
I made these changes. The only exception is the book url may not always be amazon so, I didn't add that to the common xml. I took your suggestion and combined complete with status, after all it is the final status of a promotion http://www.javaranch.com/carl/xmlindex2.html
Yes, 20010313.xml looks a lot cleaner
 
Khun Yee Fung
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I am going to use a slighty different format for the promotions. Quite similar, really. This is not a crucial point, anyhow.
An example of a book promotion is:
<book day="13" month="3" year="2001" status='Confirmed'>
<bookTitle url="http://www.amazon.com/exec/obidos/ASIN/0201711036/ref=ase_electricporkchop/107-0402457-1632559">XSLT: Working with XML and HTML</bookTitle>
<author name='Khun+Yee+Fung'>Khun Yee Fung</author>
<publisher url="http://www.awl.com/">Addison-Wesley</publisher>
<forum forum='XML,+XSL,+DOM+and+SAX'>XML, XSL, DOM and SAX</forum>
</book>
For a voucher, an example is:
<voucher day='20' month='02' year='2001' status='Completed'>
<title url="http://suned.sun.com">Sun Certified Java Architect Exam(voucher)</title>
<publisher url="http://suned.sun.com">Sun Educational Services</publisher>
<forum forum="Architect+Certification">Architect Certification</forum>
<winners>
<winner>Bidyut Padhi</winner>
<winner>faisal mahmood</winner>
<winner>shailesh sonavadekar</winner>
<winner>Vishakha Ahuja</winner>
</winners>
</voucher>
The root element for each kind of promotion is different. Again, this is to make it trivial to figure out whether a promotion is about a book, a certificate, or a voucher. In fact, later on, it could be something else. In this way, you can add in different kinds of promotion without rewriting much of the XML documents and XSLT documents.
Since I changed the XML format, I guess I should provide the XSLT documents as well. Actually, I will provide one. The other one is very similar.
Now, let us look at the XSLT document for past winners. It is good it has an xsl:output element. Since the method attribute is set to html, all the BR elements will be output properly. However, I would not set the doctype-public attribute because I believe your output will be only a fragment of the HTML document it is inside. Furthermore, I would set the indent attribute to yes only when debugging the output. Otherwise, I would set it to no. I don't want any browser to mis-interpret any whitespaces, something that the browsers do not handle well.
Now, suppose the lineup file looks like:
<lineup>
<promotion date='20001128'/>
<promotion date='20001219'/>
<promotion date='20010102'/>
<promotion date='20010109'/>
<promotion date='20010116'/>
<promotion date='20010123'/>
<promotion date='20010130'/>
<promotion date='20010206'/>
<promotion date='20010220'/>
<promotion date='20010227'/>
<promotion date='20010306'/>
<promotion date='20010313'/>
<promotion date='20010320'/>
<promotion date='20010327'/>
<promotion date='20010403'/>
</lineup>
I will keep the template that matches the root of the document:
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
I need a template to match the lineup element, so I use what Carl has written for matching 'BookPromotions' as the base. Now, the whole XSLT document looks like:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='html'/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="lineup">
<TABLE BORDER="1" CELLPADDING="5">
<TR BGCOLOR="#dec7a4">
<TD>Starting Date</TD>
<TD>Book</TD>
<TD>Author(s)</TD>
<TD>Publisher</TD>
<TD>JavaRanch Forum</TD>
<TD>Winners</TD>
</TR>
<!-- to handle each promotion -->
</TABLE>
</xsl:template>
</xsl:stylesheet>
No big deal.
Now, we have to write a template to match promotion. Let us do it bit by bit.
<xsl:template match='promotion'>
<!-- the body of the template-->
</xsl:template>
First, we have to read in the XML document corresponding to the date. This is done by using the document() function in XSLT:
document(concat(@date, ".xml"))/*
There are two ways to handle this external file. One is to use apply-templates to handle the nodes inside. The other is to keep the root element of the document in a variable:
<xsl:variable name='dateTree' select='document(concat(@date, ".xml"))/*'/>
From now on, you can use expressions like $dateTree/@status if you need to find out the status attribute of the root element. Notice that I used '*' because I don't want to know the name of the root element yet.
Now, we have winners only if the promotion is completed. To find out this is the case, we use the xsl:test element. If the condition is true, we output a row in the table. We will also output the date of the event as the first column:
<xsl:if test='$dateTree/@status="Completed"'>
<TR BGCOLOR='#eadbc4'>
<TD NOWRAP='NOWRAP'><xsl:value-of select='$dateTree/@day'/>/<xsl:value-of select='$dateTree/@month'/>/<xsl:value-of select='$dateTree/@year'/></TD>
<!-- the other columns -->
</TR>
</xsl:if>
Now, the title of a promotion depends on the kind of promotion it is. The name of the root element of the promotion document tells us what kind of promotion it is. So we simply apply the right templates for the root element of the document:
<xsl:apply-templates select='$dateTree'/>
And we need one template for each of book, giftCertificate, and voucher. And then we can output the other columns of the row.
First, the template for a gift certificate:
<xsl:template match='giftCertificate'>
<TD NOWRAP='NOWRAP'>
<xsl:value-of select='title'/>
</TD><TD> </TD><TD> </TD>
</xsl:template>
Nothing to it.
The template for a voucher looks like:
<xsl:template match='voucher'>
<TD NOWRAP='NOWRAP'>
<A HREF='{title/@url}'><xsl:value-of select='title'/></A>
</TD>
<TD> </TD>
<TD NOWRAP='NOWRAP'>
<A HREF='{publisher/@url}'><xsl:value-of select='publisher'/></A>
</TD>
</xsl:template>
Again, nothing to it, except the funny {publisher/@url} thing as the value of the HREF attribute. Well, this is an example of an attribute value template. In essence, XSLT allows you to specify the value of an (usually non-XSLT) attribute by enclosing an XPath expression in curly brackets (braces). The long hand for the A element above is:
<A><xsl:attribute name='HREF'><xsl:value-of select='title/@url'/></xsl:attribute><xsl:value-of select='title'/></A>
Of course, attribute value templates are much shorter in general. But it does test your understanding of XPath and location paths though.
Ok, finally, the template for a book promotion:
<xsl:template match='book'>
<TD NOWRAP='NOWRAP'>
<A HREF='{bookTitle/@url}'><xsl:value-of select='bookTitle'/></A>
</TD>
<TD NOWRAP='NOWRAP'>
<A HREF='{concat($common/author/@prefix, author[1]/@name, $common/author/@suffix)}'><xsl:value-of select='author'/></A>
<xsl:for-each select='author[position() > 1]'>
<BR/><A HREF='{concat($common/author/@prefix, ., $common/author/@suffix)}'><xsl:value-of select='.'/></A>
</xsl:for-each>
</TD>
<TD NOWRAP='NOWRAP'>
<A HREF='{publisher/@url}'><xsl:value-of select='publisher'/></A>
</TD>
</xsl:template>
Again, the only funny thing is:
{concat($common/author/@prefix, author[1]/@name, $common/author/@suffix)}
Well, I cheated a little bit. I have to get the elements in the common file somehow. What I did was to add an element at the top of the XSLT document in this way:
<xsl:variable name='common' select='document("common.xml")/*'/>
That is why I can use the variable called common.
The whole expression says to concatenate the prefix attribute of the author element of the element stored in the common variable with the author name and the suffix attribute of the author element of the element stored in the common variable. Quite a mouthful, but rather straightforward.
Another thing: I separate the first author name with the other author names because I want to have a BR element only between author names. I don't want a BR element at the end of the list of names.
With the three templates out of the way, the template of the promotion is not mysterious any more. This is the whole template:
<xsl:template match='promotion'>
<xsl:variable name='dateTree' select='document(concat(@date, ".xml"))/*'/>
<xsl:if test='$dateTree/@status="Completed"'>
<TR BGCOLOR='#eadbc4'>
<TD NOWRAP='NOWRAP'><xsl:value-of select='$dateTree/@day'/>/<xsl:value-of select='$dateTree/@month'/>/<xsl:value-of select='$dateTree/@year'/></TD>
<xsl:apply-templates select='$dateTree'/>
<TD NOWRAP='NOWRAP'>
<xsl:choose>
<xsl:when test='not($dateTree/forum)'>
 
</xsl:when>
<xsl:otherwise>
<A HREF='{concat($common/forums/@prefix, $common/forums/forum[@name=$dateTree/forum/@forum]/@number, $common/forums/@suffix)}'>
<xsl:value-of select='$dateTree/forum'/></A>
</xsl:otherwise>
</xsl:choose>
</TD>
<TD NOWRAP='NOWRAP'>
<xsl:value-of select='$dateTree/winners/winner[1]'/>
<xsl:for-each select='$dateTree/winners/winner[position() > 1]'>
<BR/><xsl:value-of select='.'/>
</xsl:for-each>
</TD>
</TR>
</xsl:if>
</xsl:template>
The other XSLT document is quite similar. I will leave that as an exercise.
Oh, below is the whole common.xml file. Obviously, I don't have the full set of forum numbers for JavaRanch. I just inserted enough to handle the promotions.
<common>
<author prefix='http://www.javaranch.com/cgi-bin/ubb/ubbmisc.cgi?action=getbio&UserName='/>
<forums prefix='http://www.javaranch.com/cgi-bin/ubb/forumdisplay.cgi?action=topics&forum=&number=' suffix='&DaysPrune=1000&LastLogin='>
<forum name='Servlets+and+JSP|APO|s' number='7'/>
<forum name='Star+Office,+et+al.' number='14'/>
<forum name='Java+in+General+(beginner)' number='33'/>
<forum name='Java+in+General+(advanced)' number='34'/>
<forum name='Performance' number='15'/>
<forum name='XML,+XSL,+DOM+and+SAX' number='31'/>
<forum name='OO,+Patterns,+UML+and+Refactoring' number='9'/>
<forum name='Other+Java+APIs' number='45'/>
<forum name='Architect+Certification' number='26'/>
<forum name='Process:+UP,+RUP,+DRUP,+XP,+etc.' number='42'/>
</forums>
</common>
Now, we are back to the beginning. Like Carl said, what is the next step? Well, for these two pages, there is really not much else that you want to do, other than setting up a batch file so that whenever you finish generating the HTML pages, you move them over to the place where their JSP pages can pick them up.
These are the files I have: common.xml, the individual promotion files, winners.xsl, and lineup.xml. No idea how to send them over if you want them.

------------------
Khun Yee Fung
Author of XSLT: Working with XML and HTML
 
Don't get me started about those stupid light bulbs.
reply
    Bookmark Topic Watch Topic
  • New Topic