XSL in servlet-based WML
I work in the Java Platform group at Sun and we recently created a mailing list that may be of interest to some readers of this list.
The focus of the firstname.lastname@example.org mailing list is the generation of structured content (most concretely WML) in response to HTTP requests using the Servlet and JSP technologies. The relationshpi to XSL-LIST is that in many (most?) cases the generation pipeline involves an XSLT transformation step, often just before returning content to a WAP gateway. The generation pipeline is also applicable to other content but the list is initially targetted to WML/WAP.
I am including the text of the announcement message that Danny Coward sent to some other lists.
I have set up a mailing list specially for people who are using JSPs and Servlets to create WAP content, are interested in using JSP and Servlets to write WAP applications, and hearing about & discussing other people's experiences and knowledge.
WAP is in the news a lot right now, and I know some of you out there are interested in finding out more in this specific area.
The mailing list address is
This list will be pretty informal till we see just how much interest there is.
For now, if you wish to subscribe, just send me an email (to
HDML from XML
With XT, you can use the HDML output method posted on 4xt:
dollar sign in wml output
>WML syntax uses the $ (dollar sign) for de-referencing a variable. To >display the character, $$ must be specified, otherwise most WML browsers >return an error. If an xml file containing a $ in a node is transformed via >XSL (using the xsl:value-of statement) to produce WML, the $ is output as a >$. Other characters such as &, <, " are output in the encoded form. Does a >special encoding scheme exist to force the output of a $ in encoded format? >Does some other mechanism exist to allow character transformations to be >customized within an xsl:value-of operation? Pre-processing the xml file is >an issue as the vast majority of xml inputs do not contain a $. Post >processing the transformed output is also an issue as the output does >contain WML variable references using the $.
One simple way, using the XPath string operators, is to call a template that finds the first '$' in a string, replaces it with '$$', and recurses on itself with the remainder of the string:
First, for each string that might contain '$', call the "dollar" template within your XSL to fix it:
<block> <xsl:call-template name="dollar"> <xsl:with-param name="text" select="ELEMENT_TO_FIX" /> </xsl:call-template> </block>
Substitute whatever you want checked for the select above. This call to dollar must appear wherever you want the text to be searched.
Next, add a "dollar" template (as called above) into the XSL file, which does a recursive search for '$', replacing it with '$$':
<xsl:template match="text()" name="dollar"> <xsl:param name="text" select="."/> <xsl:choose> <xsl:when test="contains($text,'$')"> <xsl:value-of select="substring-before($text,'$')"/> <xsl:text>$$</xsl:text> <xsl:call-template name="dollar"> <xsl:with-param name="text" select="substring-after($text,'$')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template>
Splitting an XML file based on size
> I'm processing an NITF file into HTML. > I need some way to keep track of the number of characters I've > processed and > stop when I reach a specific size, stoping at the end of the > paragraph. I > understand that counting characters is not very precise but I am only > interested in getting the transfer size to be less than 2K or so. >
I used to work on the development of a mobile applications platform that had to deal with byte size pagination (that's what we called this problem) in a flexible, automagic way for n applications and n devices, all of which had different digest sizes (some mandatory, others suggested, like for the Pocket PC, Palm, RIM, etc.), numbers of rows, numbers of accesskeys, etc.. The short answer is that it's not easy in general, and especially not in XSLT. Before I get flamed, let me try to explain why :) and invite people to produce a pure XSLT solution, because I know it's possible, but I also know that it's a royal pain in the behind (at least, the way I was trying to do it).
Solution 1 would be the pure XSLT solution. Like I said, I think it's possible, your code snippet down below is a start. But I think it's going to be extremely hard to make a solution like that extensible (you may end up writing the same code for <p>, <table> and any other tags, just slightly different). Also, I'll go out on a limb here and make a blanket statement: XSLT (this version, anyway) is not supposed to be the end point of a delivery architecture. XSLT is designed for document transformation, so going from unpaginated NITF to unpaginated HTML is almost trivial, as you know. But it has no clue what device it's talking to, which delivery architectures have to know and take into account. You could make your stylesheet aware of the device and its capabilities, although the colossal pain of keeping variables for byte size, number of rows, number of accesskeys (for phones), and linking to the data you didn't have room for will keep you up nights.
You could probably use extension functions or calls out to Java classes to give you more power and a cleaner stylesheet, but it's still a pain (and I have no idea what the performance implications are). I don't know much about that stuff; it's possible that a few extension functions would be able to keep track of where you are and short circuit the transformation when you overflow, but I don't remember whether they can be stateful? if not, Java calls would work, I ended up writing a Java class to catch and paginate tags as I wrote them, with varying levels of success.
Solution 2 would be to use XSLT and build a pagination engine that takes in the output and chops it down to size. This makes a lot more sense to me, all you have to do is make sure you're spitting out XHTML, parse it, and go through and count bytes. You still have to decide what to do with the data you chop off, and you have to make sure you never chop off a valid end tag, things like that, but it's doable. I worked on a prototype of a system like this, but for n devices; instead of spitting out XHTML, we used our own XML to preserve structure, and then embedded markup inside it (WML, HDML, HTML, whatever). So, based on universal rules for how to paginate our XML (in your case, NITF), we could chop markup for any device down to size using one component. It was spiffy.
If you can pull off solution 2, it has a bunch of advantages: 1) you can reuse your pagination engine for multiple apps, and not have to write it all into each stylesheet (I know you can simplify this by inheriting XSLT templates, but I dare anyone to do it :), 2) the stylesheet author (if it's not you) doesn't have to know how to paginate anything, they can just write XSLT and not worry about it, and 3) your stylesheets are cleaner, and don't take as long to execute (probably, there are performance implications for splitting the job like this too, as we have to reparse the XHTML, etc.). I did all this in C++, a coworker did the same thing in Java, don't know how easy it would be to do in a scripting environment.
Good luck, I hope this is useful, and more than that, I would love to hear about experiences other people have had with paginating in XSLT. I know that at least for mobile apps, this was concern #1, and everybody had a story on how to do it. Not being an XSLT guru, I didn't know the answer, but I figure somebody on this list might...
Measuring the size of the output file, in bytes
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="/"> <xsl:variable name="vResult"> <xsl:apply-templates/> </xsl:variable> Length of output is: <xsl:text/> <xsl:value-of select="concat(string-length($vResult), '
')"/> <xsl:if test="string-length($vResult) <= 1800"> <xsl:copy-of select="$vResult"/> </xsl:if> </xsl:template> </xsl:stylesheet>
when applied on this source.xml:
<nums> <num>01</num> <num>02</num> <num>03</num> <num>04</num> <num>05</num> <num>06</num> <num>07</num> <num>08</num> <num>09</num> <num>10</num> </nums>
produces the wanted result:
Length of output is: 51 <nums> <num>01</num> <num>02</num> <num>03</num> <num>04</num> <num>05</num> <num>06</num> <num>07</num> <num>08</num> <num>09</num> <num>10</num> </nums>