xmlguru.cz

Spreading the XML paradigm around

Power of XSLT

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, … :–)

blog comments powered by Disqus
Copyright © Jiří Kosek, 2006–2014