Blog

2008 12 posts (3)

Ordering: Ascending Descending

1. Grouping in XSLT

2008-12-16 15:34:15 by Martynas Jusevičius

Together with joining, grouping is one of the most used techniques in XSLT, at least in my practice. Unfortunately, there is no native support in XSLT 1.0 (there is <xsl:for-each-group> construct in XSLT 2.0).
However, grouping can be implemented in XSLT 1.0 as well using the Muenchian method. For that you will need a key to compute values by which elements will be grouped, and (as I do it) one template to handle the whole group of elements, and one template to handle each element, single entry in the group.

Suppose we have a list of keywords used in a book, containing the text itself and the number of the page it appears on:

<keywords>
	<keyword>
		<text>XML</text>
		<page>25</page>
	</keyword>
	<keyword>
		<text>PHP</text>
		<page>10</page>
	</keyword>
	<keyword>
		<text>XSLT</text>
		<page>30</page>
	</keyword>
	<keyword>
		<text>W3C</text>
		<page>2</page>
	</keyword>
</keywords>

Now, as it is common in publishing, we want to use them to build an aplhabetically-grouped index of keywords to be added to the appendix of the book.
First we define a key, which assigns each keyword a value equal to the first letter of its text (and can be used to select keywords starting with the same letter):

<xsl:key name="keywords-by-letter" match="keyword" use="substring(text, 1, 1)"/>

Then, a group template which displays the current letter and a list of keywords starting with it:

<xsl:template match="keyword" mode="group">
	<xsl:variable name="letter" select="substring(text, 1, 1)"/>
	<h1>
		<xsl:value-of select="$letter"/>
	</h1>
	<ul>
		<xsl:apply-templates select="key('keywords-by-letter', $letter)" mode="entry"/>
	</ul>
</xsl:template>

And a template to show a single keyword as a list item (notice how mode is different from the group template):

<xsl:template match="keyword" mode="entry">
	<li>
		<xsl:value-of select="text"/>, page <xsl:value-of select="page"/>
	</li>
</xsl:template>

Finally, we can put this all to use with a master template which applies templates for each keyword group, or in other words, for each unique starting letter found in the keyword list:

<xsl:template match="keywords">
	<html>
		<head>...</head>
		<body>
			<xsl:apply-templates select="keyword[generate-id(.) = generate-id(key('keywords-by-letter', substring(text, 1, 1))[1])]" mode="group">
				<xsl:sort select="text"/>
			</xsl:apply-templates>
		</body>
	</html>
</xsl:template>

XML and XSLT will be both grouped under X.

Add a comment Comments (101)

2. W3C released mobileOK validator

2008-12-09 12:14:22 by Martynas Jusevičius

W3C released mobileOK checker, which is intended to help developers created clean websites suited for mobile devices and help them reach mobile community, supporting strategy that the Web should be accessible on a variety of heterogeneous clients.

Among other things, mobileOK validator seems to analyze:

This blog seems to be 78% mobileOK already :)

Add a comment Comments (3)

3. Method overloading in PHP 5

2008-12-02 13:21:47 by Martynas Jusevičius

Method overloading (a feature of object-oriented programing which allows having several class methods with the same name but different signatures) is not implemented in PHP, which is a drawback compared to Java.
However, PHP 5 provides a way to imitate overloading by catching calls to inaccessible methods with magic method __call.

Here is an example with constructor overloading (idea taken from DZone Snippets):

class YearResource extends TimeIntervalResource
{
	public function __construct() // dispatches calls to specific constructors
	{
		$num = func_num_args();
		$args = func_get_args();
		if ($num == 0) $this->__call('__construct0', null);
		if ($num == 1) $this->__call('__construct1', $args);
	}

	private function __call($name, $arg) // calls a user function given with an array of parameters
	{
		return call_user_func_array(array($this, $name), $arg);
	}

	public function __construct0() // no parameter constructor
	{
		parent::__construct();
		$this->setType(FrontEndResourcePeer::CLASSKEY_YEARRESOURCE);
	}

	public function __construct1(Year $year) // single parameter constructor
	{
		parent::__construct(YearListResource::getInstance());
		$this->setType(FrontEndResourcePeer::CLASSKEY_YEARRESOURCE);
		$this->setRelativeURI(rawurlencode($year->getStartDateTime(null)->format("Y")));
		$year->setFrontEndResource($this);
	}
}

Now the YearResource can be constructed with one parameter or none at all:

$resource = new YearResource($year);
$resource = new YearResource();

Note that in parent classes you might have to use self::__call instead of $this->__call to get the desired effect.

Add a comment Comments (1223)

Ordering: Ascending Descending