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.
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:
- (X)HTML markup validity
- DTD's mobile-friendliness
- Structure of the page (e.g. weight in KBs)
- Scripting (which should be degradable)
- Inclusions (frames, pop-ups, applets, and objects are discouraged)
- CSS stylesheets (absolute units, floats and absolute positioning are discouraged)
- Character encodings (UTF-8 is recommended)
- HTTP headers (caching is encouraged)
- Links
This blog seems to be 78% mobileOK already :)
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.
Ordering: Ascending Descending
