I wrote following article, about implementing some of the Schema aware stylesheet ideas (as defined in the XSLT 2.0 spec.) using a XSLT 1.0 processor and Java extensions, and a suitable validating XML parser. A requirement from a XSLT user on this blog motivated me to work on this idea.
The article on my web site showcases just how few of the XSLT 2.0 Schema aware facilities like, validating the output tree (or even a result tree fragment) prior to serialization can be done. This covers one of the very important aspects of Schema aware XSLT 2.0 stylesheet design.
I think it's not possible to implement following Schema aware XSLT 2.0 facilities, using XSLT 1.0 and extensions alone:
1) Pass the validated XML instance tree to the XSLT processor, and the stylesheet is able to access Schema annotated XPath 2.0 data model tree. The XSLT 2.0 and XPath 2.0 languages define various Schema related instructions and expressions (for e.g., element(*, typeName) etc.), which cannot be simulated with XSLT 1.0 and extensions.
2) Since we cannot access Schema annotated XPath 2.0 data model tree in a XSLT 1.0 stylesheet, we cannot access XML Schema type names in a stylesheet, which prohibits the enhanced static typing features in XSLT stylesheets.
Using a complete Schema aware XSLT 2.0 system allows very rich static typing in XSLT stylesheets out of the box.
Saturday, August 30, 2008
Friday, August 22, 2008
Nice use case for xsl:analyze-string instruction
I thought that this was interesting to share.
Recently an XSLT user discussed a problem on xsl-list, which was solved by Jeni Tennison using XSLT 1.0 long time ago.
I presented a XSLT 2.0 solution for the same problem. The 2.0 solution is lot shorter as compared to the 1.0 solution, and utilizes the XSLT 2.0 instruction, xsl:analyze-string.
The link to this thread is at, http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200808/msg00383.html.
This problem could be a nice use case for xsl:analyze-string instruction.
Recently an XSLT user discussed a problem on xsl-list, which was solved by Jeni Tennison using XSLT 1.0 long time ago.
I presented a XSLT 2.0 solution for the same problem. The 2.0 solution is lot shorter as compared to the 1.0 solution, and utilizes the XSLT 2.0 instruction, xsl:analyze-string.
The link to this thread is at, http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200808/msg00383.html.
This problem could be a nice use case for xsl:analyze-string instruction.
Thursday, August 14, 2008
Transforming tree structure from one format into another
An interesting question was asked on xsl-list,
The input XML file is something as:
Let's say that XML file has only one root node.
The output XML file would be:
A tree structure is defined in input XML, by the 'name' and 'child' attributes. The output represents a true logical tree. We should be able to cater to unlimited number of tree nodes.
We need to write a XSLT stylesheet for this.
At first thought, I imagined that this could be a tough problem. But a little bit of patience helped me to write the stylesheet for this. The solution is presented below.
At first thought, I felt that XSLT 2.0 constructs will be required to solve this problem. But the problem can be solved completely with a XSLT 1.0 stylesheet.
My belief that XSLT is a wonderful language for processing XML data, became stronger after solving this problem.
The input XML file is something as:
<Objs>
<obj name="a" child="b"/>
<obj name="b" child="c"/>
<obj name="b" child="d"/>
<obj name="c" child="e"/>
</Objs>
Let's say that XML file has only one root node.
The output XML file would be:
<Obj name="a">
<Obj name="b">
<Obj name="c">
<Obj name="e"/>
</Obj>
<Obj name="d"/>
</Obj>
</Obj>
A tree structure is defined in input XML, by the 'name' and 'child' attributes. The output represents a true logical tree. We should be able to cater to unlimited number of tree nodes.
We need to write a XSLT stylesheet for this.
At first thought, I imagined that this could be a tough problem. But a little bit of patience helped me to write the stylesheet for this. The solution is presented below.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="Objs">
<xsl:variable name="start" select="obj[not(@name = ../obj/@child)]" />
<xsl:variable name="startName" select="$start[1]/@name" />
<Obj name="{$startName}">
<xsl:for-each select="obj[(@name = $startName) and not(../obj/@name = @child)]">
<Obj name="{@child}" />
</xsl:for-each>
<xsl:call-template name="makeTree">
<xsl:with-param name="list" select="obj[@name = $start/@child]" />
</xsl:call-template>
</Obj>
</xsl:template>
<xsl:template name="makeTree">
<xsl:param name="list" />
<Obj name="{$list[1]/@name}">
<xsl:for-each select="$list">
<xsl:variable name="child" select="@child" />
<xsl:choose>
<xsl:when test="not(../obj[@name = $child])">
<Obj name="{$child}" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="makeTree">
<xsl:with-param name="list" select="../obj[@name = $child]" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Obj>
</xsl:template>
</xsl:stylesheet>
At first thought, I felt that XSLT 2.0 constructs will be required to solve this problem. But the problem can be solved completely with a XSLT 1.0 stylesheet.
My belief that XSLT is a wonderful language for processing XML data, became stronger after solving this problem.
Sunday, August 3, 2008
Multiple values for XSLT keys
An XSLT user, asked following question, on xsl-list.
How do I use multiple key values?
Declaration:
<xsl:key name="keyname" match="subroot" use="ccc"/>
During the usage, I want to specify multiple values:
<xsl:variable name="keyname" select="key('keyname', '11' or '22')"/> ==> Here I want to use multiple values 11 and 22.
xsl-list members suggested useful options,
1. David Carlisle
<xsl:variable name="keyname" select="key('keyname', '22')|key('keyname', '11')"/>
2. Michael Kay
In XSLT 2.0, you can supply a sequence:
key('keyname', ('111', '222'))
In 1.0, you can supply a node-set with one value per node - but of course it's hard to set that up, you need the xx:node-set() function.
I worked upon Mike's idea for a XSLT 1.0 solution,
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
exclude-result-prefixes="exslt"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="x" match="subroot" use="ccc"/>
<xsl:variable name="x-values">
<v>11</v>
<v>22</v>
</xsl:variable>
<xsl:template match="/root">
<result>
<xsl:for-each select="key('x', exslt:node-set($x-values)/v)">
<value>
<xsl:value-of select="eee" />
</value>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
Mukul: I think, this could be better than David's suggestion, because if we want to have quite large number of different values to search by the key, we just have to change following code fragment,
<xsl:variable name="x-values">
<v>11</v>
<v>22</v>
<!-- more values -->
</xsl:variable>
G. Ken Holman responded to my post, and provided a brilliant idea,
The node-set extension can be avoided to achieve what you want.
<xsl:for-each select="key('x', exslt:node-set($x-values)/v)">
The above can be replaced with standard XSLT 1.0 to read the stylesheet file as a source node tree.
<xsl:for-each
select="key('x',document('')/*/xsl:variable[@name='x-values']/v)">
Ken further wrote,
I grant, though, that if your stylesheet is large then putting this into a small included or imported fragment would keep any overhead of building the tree small.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="x" match="subroot" use="ccc"/>
<xsl:include href="ken2values.xsl"/>
<xsl:template match="/root">
<result>
<xsl:for-each select="key('x',$x-values)">
<value>
<xsl:value-of select="eee" />
</value>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
ken2values.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="x-values-data">
<v>11</v>
<v>22</v>
</xsl:variable>
<xsl:variable name="x-values"
select="document('')/*/xsl:variable[@name='x-values-data']/v"/>
</xsl:stylesheet>
I think, Ken's idea of having an included stylesheet (ken2values.xsl, above) is brilliant, as it is memory efficient, and we are able to avoid the node-set extension (as mentioned earlier).
How do I use multiple key values?
Declaration:
<xsl:key name="keyname" match="subroot" use="ccc"/>
During the usage, I want to specify multiple values:
<xsl:variable name="keyname" select="key('keyname', '11' or '22')"/> ==> Here I want to use multiple values 11 and 22.
xsl-list members suggested useful options,
1. David Carlisle
<xsl:variable name="keyname" select="key('keyname', '22')|key('keyname', '11')"/>
2. Michael Kay
In XSLT 2.0, you can supply a sequence:
key('keyname', ('111', '222'))
In 1.0, you can supply a node-set with one value per node - but of course it's hard to set that up, you need the xx:node-set() function.
I worked upon Mike's idea for a XSLT 1.0 solution,
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
exclude-result-prefixes="exslt"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="x" match="subroot" use="ccc"/>
<xsl:variable name="x-values">
<v>11</v>
<v>22</v>
</xsl:variable>
<xsl:template match="/root">
<result>
<xsl:for-each select="key('x', exslt:node-set($x-values)/v)">
<value>
<xsl:value-of select="eee" />
</value>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
Mukul: I think, this could be better than David's suggestion, because if we want to have quite large number of different values to search by the key, we just have to change following code fragment,
<xsl:variable name="x-values">
<v>11</v>
<v>22</v>
<!-- more values -->
</xsl:variable>
G. Ken Holman responded to my post, and provided a brilliant idea,
The node-set extension can be avoided to achieve what you want.
<xsl:for-each select="key('x', exslt:node-set($x-values)/v)">
The above can be replaced with standard XSLT 1.0 to read the stylesheet file as a source node tree.
<xsl:for-each
select="key('x',document('')/*/xsl:variable[@name='x-values']/v)">
Ken further wrote,
I grant, though, that if your stylesheet is large then putting this into a small included or imported fragment would keep any overhead of building the tree small.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="x" match="subroot" use="ccc"/>
<xsl:include href="ken2values.xsl"/>
<xsl:template match="/root">
<result>
<xsl:for-each select="key('x',$x-values)">
<value>
<xsl:value-of select="eee" />
</value>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
ken2values.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="x-values-data">
<v>11</v>
<v>22</v>
</xsl:variable>
<xsl:variable name="x-values"
select="document('')/*/xsl:variable[@name='x-values-data']/v"/>
</xsl:stylesheet>
I think, Ken's idea of having an included stylesheet (ken2values.xsl, above) is brilliant, as it is memory efficient, and we are able to avoid the node-set extension (as mentioned earlier).
Sunday, July 27, 2008
XML Schema 1.1 assertions implementation in Xerces-J
One of the interesting enhancements, that are happening recently to Xerces code base, is XML Schema 1.1 implementation.
The Xerces-J team motivated me to implement some of the XML Schema 1.1 features into Xerces. I've started with the implementation of XML Schema 1.1 facility, "assertions".
I've completed quite a bit of work regarding this, and am hoping that the assertions support I'm writing would be available in Xerces-J in near future.
2008-11-04: Xerces team approved my work so far for assertions implementation, and have committed my patch to the Xerces code base. In the coming weeks, I would be working on integrating XPath 2.0 processing for assertions.
The Xerces-J team motivated me to implement some of the XML Schema 1.1 features into Xerces. I've started with the implementation of XML Schema 1.1 facility, "assertions".
I've completed quite a bit of work regarding this, and am hoping that the assertions support I'm writing would be available in Xerces-J in near future.
2008-11-04: Xerces team approved my work so far for assertions implementation, and have committed my patch to the Xerces code base. In the coming weeks, I would be working on integrating XPath 2.0 processing for assertions.
Saturday, July 26, 2008
An elegant XSLT solution
We usually see some nice posts, on the xsl-list.
David Carlisle recently posted a very elegant XSLT solution to a question asked on xsl-list. It's archived here, http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200807/msg00574.html.
I really liked the following expression, in David's solution:
<xsl:attribute name="level">
<xsl:value-of select="sum(.|preceding::sect[1]/@depth)"/>
</xsl:attribute>
I might have solved this problem differently, but not as elegantly like this. Nice thought, David!
David Carlisle recently posted a very elegant XSLT solution to a question asked on xsl-list. It's archived here, http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200807/msg00574.html.
I really liked the following expression, in David's solution:
<xsl:attribute name="level">
<xsl:value-of select="sum(.|preceding::sect[1]/@depth)"/>
</xsl:attribute>
I might have solved this problem differently, but not as elegantly like this. Nice thought, David!
Friday, July 18, 2008
XSLT 2.0 shines over 1.0
I was pondering over XSLT 2.0's advantages over XSLT 1.0, and came up with a simple example that illustrates XSLT 2.0's benefits.
Below are a 1.0 and 2.0 stylesheets, for finding the 1st n fibonacci numbers (and, analysis later on):
XSLT 2.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:x="http://localhost"
version="2.0">
<xsl:output method="text" />
<xsl:param name="n" />
<xsl:template match="/">
<xsl:for-each select="1 to $n">
<xsl:value-of select="x:fibonacci(position())" /><xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:function name="x:fibonacci" as="xs:integer">
<xsl:param name="n" as="xs:integer" />
<xsl:sequence select="if (($n = 1) or ($n = 2)) then 1 else x:fibonacci($n - 1) + x:fibonacci($n - 2)" />
</xsl:function>
</xsl:stylesheet>
XSLT 1.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text" />
<xsl:param name="n" />
<xsl:template match="/">
<xsl:call-template name="iterateAndFib">
<xsl:with-param name="x" select="1" />
</xsl:call-template>
</xsl:template>
<xsl:template name="iterateAndFib">
<xsl:param name="x" />
<xsl:if test="$x <= $n">
<xsl:call-template name="fibonacci">
<xsl:with-param name="n" select="$x" />
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:call-template name="iterateAndFib">
<xsl:with-param name="x" select="$x + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="fibonacci">
<xsl:param name="n" />
<xsl:choose>
<xsl:when test="($n = 1) or ($n = 2)">
<xsl:value-of select="1" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="x">
<xsl:call-template name="fibonacci">
<xsl:with-param name="n" select="$n - 1" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="y">
<xsl:call-template name="fibonacci">
<xsl:with-param name="n" select="$n - 2" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$x + $y" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Why therefore I think, XSLT 2.0 is better over 1.0,
1. A 2.0 stylesheet can be written with very few lines of code as compared to 1.0 stylesheet. In this case, the 2.0 stylesheet is of 22 lines, and the 1.0 stylesheet is of 51 lines (considering normal indentation markers in code).
2. In a 2.0 stylesheet, there is no need of recursion to iterate. The for-each loop natively supports iteration in a numerical range.
3. In the 2.0 stylesheet, we can utilize the xsl:function construct to write shorter code, which is better logically understood. The recursive calls in xsl:function in this example are easy to understand.
In a 1.0 stylesheet, we need to write named template to achieve recursive calls, which can get cumbersome if logic is complex.
4. In XSLT 2.0, the data model type system has lot more data types, than 1.0 (All built-in XML Schema types, as well user defined types can be used in XSLT 2.0 stylesheets).
I have no doubt, XSLT 2.0 shines over XSLT 1.0.
I read Norman Walsh expressing following thoughts on his blog post, "Every experience that I have with XSLT 2.0 increases my enthusiasm for it.". I totally agree with Norm.
Below are a 1.0 and 2.0 stylesheets, for finding the 1st n fibonacci numbers (and, analysis later on):
XSLT 2.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:x="http://localhost"
version="2.0">
<xsl:output method="text" />
<xsl:param name="n" />
<xsl:template match="/">
<xsl:for-each select="1 to $n">
<xsl:value-of select="x:fibonacci(position())" /><xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:function name="x:fibonacci" as="xs:integer">
<xsl:param name="n" as="xs:integer" />
<xsl:sequence select="if (($n = 1) or ($n = 2)) then 1 else x:fibonacci($n - 1) + x:fibonacci($n - 2)" />
</xsl:function>
</xsl:stylesheet>
XSLT 1.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text" />
<xsl:param name="n" />
<xsl:template match="/">
<xsl:call-template name="iterateAndFib">
<xsl:with-param name="x" select="1" />
</xsl:call-template>
</xsl:template>
<xsl:template name="iterateAndFib">
<xsl:param name="x" />
<xsl:if test="$x <= $n">
<xsl:call-template name="fibonacci">
<xsl:with-param name="n" select="$x" />
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:call-template name="iterateAndFib">
<xsl:with-param name="x" select="$x + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="fibonacci">
<xsl:param name="n" />
<xsl:choose>
<xsl:when test="($n = 1) or ($n = 2)">
<xsl:value-of select="1" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="x">
<xsl:call-template name="fibonacci">
<xsl:with-param name="n" select="$n - 1" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="y">
<xsl:call-template name="fibonacci">
<xsl:with-param name="n" select="$n - 2" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$x + $y" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Why therefore I think, XSLT 2.0 is better over 1.0,
1. A 2.0 stylesheet can be written with very few lines of code as compared to 1.0 stylesheet. In this case, the 2.0 stylesheet is of 22 lines, and the 1.0 stylesheet is of 51 lines (considering normal indentation markers in code).
2. In a 2.0 stylesheet, there is no need of recursion to iterate. The for-each loop natively supports iteration in a numerical range.
3. In the 2.0 stylesheet, we can utilize the xsl:function construct to write shorter code, which is better logically understood. The recursive calls in xsl:function in this example are easy to understand.
In a 1.0 stylesheet, we need to write named template to achieve recursive calls, which can get cumbersome if logic is complex.
4. In XSLT 2.0, the data model type system has lot more data types, than 1.0 (All built-in XML Schema types, as well user defined types can be used in XSLT 2.0 stylesheets).
I have no doubt, XSLT 2.0 shines over XSLT 1.0.
I read Norman Walsh expressing following thoughts on his blog post, "Every experience that I have with XSLT 2.0 increases my enthusiasm for it.". I totally agree with Norm.
Subscribe to:
Posts (Atom)