Saturday, 17 December 2011
XSLT Title Case Converter
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:griffmonster="http://www.griffmonster.com/functions" exclude-result-prefixes="griffmonster">
<!-- title case converter module
takes a string input and converts to title case as output
uses an exceptions file for word exceptions
created griffmonster -->
<xsl:param name="strExceptionsFilename">titleCaseExceptions.xml</xsl:param>
<xsl:param name="nstExceptions" select="document($strExceptionsFilename)"/>
<xsl:function name="griffmonster:fnTitleCase">
<xsl:param name="string"/>
<xsl:variable name="intLength" select="string-length($string)"/>
<xsl:variable name="tokenizedSample" select="tokenize($string,'\s')"/>
<xsl:for-each select="$tokenizedSample">
<xsl:variable name="strToken" select="."/>
<xsl:choose>
<xsl:when test="$nstExceptions//Exception[lower-case(self::*) = lower-case($strToken)]">
<xsl:value-of select="$nstExceptions//Exception[lower-case(self::*) = lower-case($strToken)]"/>
</xsl:when>
<!--Filter for name begining with O' -->
<xsl:when test='starts-with(lower-case($strToken),"o'")'>
<xsl:value-of select="upper-case(substring($strToken, 1, 3))"/>
<xsl:value-of select="lower-case(substring($strToken, 4, $intLength))"/>
</xsl:when>
<!-- filter for names begining with 'Mc' -->
<xsl:when test="starts-with(lower-case($strToken),'mc')">
<xsl:value-of select="upper-case(substring($strToken, 1, 1))"/>
<xsl:value-of select="lower-case(substring($strToken, 2, 1))"/>
<xsl:value-of select="upper-case(substring($strToken, 3, 1))"/>
<xsl:value-of select="lower-case(substring($strToken, 4, $intLength))"/>
</xsl:when>
<!--filter for hyphenated names-->
<xsl:when test="contains(lower-case($strToken),'-')">
<xsl:variable name="tokenizedHyphen" select="tokenize($strToken,'-')"/>
<xsl:for-each select="$tokenizedHyphen">
<xsl:value-of select="upper-case(substring(., 1, 1))"/>
<xsl:value-of select="lower-case(substring(., 2))"/>
<xsl:if test="position() != last()">
<xsl:text>-</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<!--filter for postcodes-->
<xsl:when test="matches($strToken,'[A-Z][A-Z]?[0-9][0-9]?') or matches($strToken,'[0-9][A-Z]{2}')">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="upper-case(substring($strToken, 1, 1))"/>
<xsl:value-of select="lower-case(substring($strToken, 2, $intLength))"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="position() != last() and matches($strToken,'[A-Z][A-Z]?[0-9][0-9]?')">
<xsl:text> </xsl:text>
</xsl:when>
<xsl:when test="position() != last()">
<xsl:text> </xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:function>
</xsl:stylesheet>
<!-- Exceptions file can be added thus
<Exceptions>
<Exception description="Example Company Ltd">ECL</Exception>
<Exception>GriffMonster</Exception>
<Exception description="acronym for Limited Liability Partnership">LLP</Exception>
<Exception>UK</Exception>
<Exception>in</Exception>
<Exception>aka</Exception>
</Exceptions>
Thursday, 23 August 2007
XSLT Maths operators
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="numbers">
A. 4 + 3.2 = <xsl:value-of select="x + y"/>
B. 3.2 - 4 = <xsl:value-of select="y - x"/>
C. 4 * 3.2 = <xsl:value-of select="x * y"/>
D. 11/3.2 = <xsl:value-of select="z div y"/>
E. 4 + 3.2 * 11 = <xsl:value-of select="x+y*z"/>
F. (4 + 3.2) * 11 = <xsl:value-of select="(x+y)*z"/>
G. 11 mod 4 = <xsl:value-of select="z mod x"/>
H. 4 + 3.2 + 11 = <xsl:value-of select="sum(*)"/>
I. floor(3.2) = <xsl:value-of select="floor(y)"/>
J. ceiling(3.2) = <xsl:value-of select="ceiling(y)"/>
K. round(3.2) = <xsl:value-of select="round(y)"/>
L. 11 + count(*) = <xsl:value-of select="11+count(*)"/>
M. 3.2 + string-length("3.2") =
<xsl:value-of select="y + string-length(y)"/>
N. 11 + "hello" = <xsl:value-of select="z + 'hello'"/>
</xsl:template>
</xsl:stylesheet>
this results in:
A. 4 + 3.2 = 7.2
B. 3.2 - 4 = -0.8
C. 4 * 3.2 = 12.8
D. 11/3.2 = 3.4375
E. 4 + 3.2 * 11 = 39.2
F. (4 + 3.2) * 11 = 79.2
G. 11 mod 4 = 3
H. 4 + 3.2 + 11 = 18.2
I. floor(3.2) = 3
J. ceiling(3.2) = 4
K. round(3.2) = 3
L. 11 + count(*) = 14
M. 3.2 + string-length("3.2") =
6.2
N. 11 + "hello" = NaN
Wednesday, 8 August 2007
convert to camel case using XPath 2
xmlns:str="http://www.metaphoricalweb.org/xmlns/string-utilities"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:function name="str:title-case" as="xs:string">
<xsl:param name="expr"/>
<xsl:variable name="tokens" select="tokenize($expr,' ')"/>
<xsl:variable name="titledTokens" select="for $token in $tokens return
concat(upper-case(substring($token,1,1)),
lower-case(substring($token,2)))"/>
<xsl:value-of select="string-join($titledTokens,'')"/>
</xsl:function>
<xsl:template match="/">
<data><xsl:value-of select="str:title-case('This is a test')"/></data>
</xsl:template>
</xsl:stylesheet>
Friday, 6 July 2007
Setting up the Saxon Servlet
1. Install Tomcat - I have Tomcat v6 already installed. It was the basic installation.
2. in webapps add a directory called xslt
copy the files to the following locations:
xslt
|
WEB-INF
web.xml
|
classes
SaxonServlet.class
|
lib
Saxon8.jar + other saxon jars
web.xml consists of the following lines:
<web-app>
<display-name>Saxon Servlet Example</display-name>
<description>
Saxon Servlet Example
</description>
<servlet>
<servlet-name>SaxonServlet</servlet-name>
<servlet-class>SaxonServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SaxonServlet</servlet-name>
<url-pattern>/SaxonServlet</url-pattern>
</servlet-mapping>
</web-app>
then use the following url to calls the transformation:
http://localhost:8080/xslt/SaxonServlet?source=books.xml&style=books.xsl
and to clear the stylesheet cache:
http://localhost:8080/xslt/SaxonServlet?clear-stylesheet-cache=yes
Thursday, 5 July 2007
XSLT Generating lists in InDesign Interchange
<xsl:template match="ul">
<xsl:variable name="list">
<xsl:apply-templates mode="inline"/>
</xsl:variable>
<xsl:apply-templates select="$list" mode="out"/>
</xsl:template>
Without this method the result contains elements for each list item.
Wednesday, 4 July 2007
InDesign Interchange Format
InDesign CS2 provides an export format called Interchange (INX) This produces an xml document which can be used for rolling InDesign documents back to previous versions. Although Adobe documentation denotes that this format should only be used for backward compatibility because it may change the INX schema in future releases, a tinkering guy like myself cant help but notice that if we generate an INX document from an XSL transformation on raw data we have a means of generating unique InDesign documents instead of using XML feeds.
To introduce a proof-of-concept I constructed an InDesign document based upon a PIL from a brand of well known hay-fever tablets. I then exported this format out as INX format using the exported INX as a guide attempted to produce and XSLT to take data from KMS and run out a formatted InDesign document. This works!
A few things are worth noticing:
ACE processing instructions: these insert characters disallowed in a well formed XML document - see http://partners.adobe.com/public/developer/indesign/sdk/explodedSDK/cs.01/docs/references/api/TextChar_8h-source.html
for a full listing
aid procssing instructions: these a markers and usually can be ignored when producing an INX using XSLT
Text nodes - each text node is preceded with c_ - this indicates that the element content is a string.
Lists - an IX list is contained within a <pcnt> element and each item is separated by a paragraph break
Hidden InDesign Characters
This can cause issues when using an XSL transformation to generate data for use within InDesign. Without these hidden characters all paragraph and line breaks cease to exist in the document.
The initial trick I used to to get around this was to include a named template thus:
<xsl:template name="break">
<xsl:text>
</xsl:text>
</xsl:template>
This was called each time a paragraph break was needed.
More recently I have found that using the character entities 
 (for a paragraph break) and 
 (for a line break) does the same trick.