Spreading the XML paradigm around
2011-10-13
Když se na stránkách konference WebExpo objevil seznam účastníků, ozvalo se několik výtek k tomu, že kód stránky je divný a že se z toho špatně dají vytáhnout údaje o účastnících. Jistě nějaký ten mikroformát nebo mikrodato by neuškodilo, ale s vhodným nástrojem je to hračka i tak.
Mnoha „webaři“ tolik zatracované XSLT to zvládne hravě. Vše jsem měl hotové za deset minut, více času zabrala publikace na mém blogu.
Pro provoz je potřeba XSLT procesor Saxon a knihovna TagSoup, která umí parsovat HTML a vrátí jej jako XML. Kdybych kód napsal v XQuery byl ještě o polovinu kratší.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" xmlns:h="http://www.w3.org/1999/xhtml" exclude-result-prefixes="h saxon" version="2.0"> <xsl:variable name="doc" select="saxon:parse-html(unparsed-text('http://webexpo.cz/praha2011/ucastnici/', 'utf-8'))"/> <xsl:variable name="ucastnici" as="element()*"> <xsl:for-each select="$doc//h:li[@class eq 'cfx']"> <ucastnik> <jméno><xsl:value-of select=".//h:span[@class eq 'name']"/></jméno> <firma><xsl:value-of select="normalize-space(.//h:span[@class eq 'company'])"/></firma> <stát><xsl:value-of select=".//h:span[@class eq 'country']/h:img/@title"/></stát> <město><xsl:value-of select=".//h:span[@class eq 'country']/h:span"/></město> </ucastnik> </xsl:for-each> </xsl:variable> <xsl:template name="main"> <html> <head> <title>Statistika účastníků WebExpo</title> </head> <body> <h2>Agregace podle firem</h2> <table border="1"> <thead> <tr><th>Firma</th><th>Počet lidí</th></tr> </thead> <tbody> <xsl:for-each-group select="$ucastnici" group-by="firma"> <xsl:sort select="count(current-group())" order="descending"/> <tr> <td><xsl:value-of select="current-grouping-key()"/></td> <td><xsl:value-of select="count(current-group())"/></td> </tr> </xsl:for-each-group> </tbody> </table> <h2>Agregace podle měst</h2> <table border="1"> <thead> <tr><th>Město</th><th>Počet lidí</th></tr> </thead> <tbody> <xsl:for-each-group select="$ucastnici" group-by="město"> <xsl:sort select="count(current-group())" order="descending"/> <tr> <td><xsl:value-of select="current-grouping-key()"/> (<xsl:value-of select="stát"/>)</td> <td><xsl:value-of select="count(current-group())"/></td> </tr> </xsl:for-each-group> </tbody> </table> </body> </html> </xsl:template> </xsl:stylesheet>
Přitom samotné vyzobání informaci ze stránky je velice krátké. Nejprve si načteme celou stránku jako strom XML do proměnné:
<xsl:variable name="doc" select="saxon:parse-html(unparsed-text('http://webexpo.cz/praha2011/ucastnici/', 'utf-8'))"/>
A potom pár jednoduchými XPath výrazy vybereme informace, co nás zajímají, a uložíme si je do přehledné struktury XML pro další snazší zpracování:
<xsl:variable name="ucastnici" as="element()*"> <xsl:for-each select="$doc//h:li[@class eq 'cfx']"> <ucastnik> <jméno><xsl:value-of select=".//h:span[@class eq 'name']"/></jméno> <firma><xsl:value-of select="normalize-space(.//h:span[@class eq 'company'])"/></firma> <stát><xsl:value-of select=".//h:span[@class eq 'country']/h:img/@title"/></stát> <město><xsl:value-of select=".//h:span[@class eq 'country']/h:span"/></město> </ucastnik> </xsl:for-each> </xsl:variable>
Tak a v komentářích se můžete předvést s vašimi Javascripty, Pythony, Ruby, PHP, Darty, … :–)