My Portal with XSLT

Tommi Komulainen <[email protected]>
Newsgroups gmane.comp.web.galeon.devel
Message-ID <[email protected]>
Hi all,

I've been playing around with XSLT attempting to generate the My Portal
page with it, instead of doing silly things like hardcoding the portal
structure in code.  IMHO, XSLT is just the right tool for the job.  If
you look at what XSLT does, you should be convinced too ;)

Please find attached a stylesheet I've got almost finished.  The page
the stylesheet generates should be identical (within reason) to the new
My Portal in 1.3.2.  See the attached XHTML file for yourself, it's
generated from the default-bookmarks.xbel (you should have galeon
installed in /usr/local or the CSS and icons can't be found and the page
will look rather dull)

You can still customize basically every aspect of My Portal by modifying
the XSLT stylesheet, but I bet it'll be much easier than editing the
code.  XSLT will also enable you to generate the My Portal page without
running galeon.

You can use the following command to try the stylesheet on your own
bookmarks and see if anything breaks:

	xsltproc myportal.xsl bookmarks.xbel >myportal.html

(add '--stringparam prefix /opt/gnome' if you've installed galeon in
/opt/gnome instead of the default /usr/local)


Now, what's really going to rock your socks off is that if you add

	<?xml-stylesheet href="myportal.xsl" type="text/xsl"?>

in the beginning of the bookmarks.xbel file, you can simply open the
bookmarks file itself in the browser and see My Portal.  Well, almost,
smart bookmarks text entries seem to disappear somewhere, but anyway...


What do you think?  Could this be used as new My Portal?


-- 
Tommi Komulainen                                 [email protected]
GPG 1024D/68388EE6    6FD6 DD79 EB38 BF6F 3533  09C0 04A8 9871 6838 8EE6
myportal.xsl (text/plain, 5 KB)
<?xml version="1.0"?>
<!-- myportal.xsl - XSL stylesheet for converting (Galeon) XBEL bookmarks file 
   - into Galeon My Portal.
   -
   - Copyright (C) 2003 Tommi Komulainen <[email protected]>
   - Available under the terms of the GNU General Public License version 2.
   -->
<xsl:stylesheet version="1.0"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:str="http://exslt.org/strings"
  exclude-result-prefixes="str"
  extension-element-prefixes="str">

<xsl:output method="xml" indent="yes" encoding="utf-8"
  media-type="text/html"
  omit-xml-declaration="no"
  doctype-public="-//W3C//DTD XHTML Transitional 1.0//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
  />

<!-- default installation prefix, can be overridden with for example
   - xsltproc -\-stringparam prefix /opt/gnome -->
<xsl:param name="prefix" select="'/usr/local'" />

<!-- other helpful variables, don't touch -->
<xsl:variable name="datadir" select="concat('file:',$prefix,'/share/galeon')"/>
<xsl:variable name="galeon">http://galeon.sourceforge.net/</xsl:variable>

<!-- My Portal -->
<xsl:template match="/">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="{concat($datadir,'/myportal.css')}"/>
<title>My Portal</title>
</head>

<body>
<!-- header -->
<div class="top_bar">
  <table cellpadding="2" cellspacing="0" width="100%" border="0">
  <tbody>
  <tr>
    <td><img alt="" src="{concat($datadir,'/galeon.png')}" />myportal:</td>
  </tr>
  </tbody>
  </table>
</div>

<div class="top2">
  <a href="http://galeon.sourceforge.net/">
    <img class="logo" alt="Galeon logo" src="{concat($datadir,'/logo.png')}" />
  </a>
</div>
<p><br /></p>

<!-- add all bookmarks here -->
<xsl:apply-templates select="xbel"/>
<!-- or we could also use this to show only particular folder -->
<!-- <xsl:apply-templates select="//folder[title = $path]"/> -->

<!-- footer -->
<div class="bottom_bar"><center><b>Galeon</b> : <i>the web, only the web</i></center></div>
</body></html>
</xsl:template>
<!-- /My Portal -->

<!-- xbel -->
<xsl:template match="xbel">
  <blockquote>
    <a class="heading"><strong>Bookmarks</strong></a>
    <xsl:apply-templates select="folder|bookmark|separator|alias"/>
  </blockquote>
</xsl:template>
<!-- /xbel -->

<!-- folder -->
<xsl:template match="folder">
  <blockquote>
    <a class="heading">
      <strong>
	<xsl:value-of select="title"/>
      </strong>
    </a>
    <br />
    <xsl:apply-templates select="folder|bookmark|separator|alias"/>
  </blockquote>
</xsl:template>
<!-- /folder -->

<!-- separator -->
<xsl:template match="separator">
  <br />
</xsl:template>
<!-- /separator -->

<!-- alias -->
<xsl:template match="alias">
  <xsl:variable name="ref"><xsl:value-of select="@ref"/></xsl:variable>
  <!-- get the bookmark or folder the alias is referring to
     -
     - TODO currently this is limited to just bookmarks, because I just 
     - can't figure out how to avoid infinite recursion that happens
     - with folders... -->
  <!-- <xsl:apply-templates select="//*[@id = $ref]"/> -->
  <i>
    <xsl:apply-templates select="//bookmark[@id = $ref]"/>
  </i>
</xsl:template>
<!-- /alias -->

<!-- bookmark -->
<xsl:template match="bookmark">
  <a href="{@href}">
    <xsl:value-of select="title"/>
  </a>
</xsl:template>
<!-- /bookmark -->

<!-- smart bookmark -->
<xsl:template match="bookmark[info/metadata[@owner = $galeon]/smarturl]">

  <xsl:variable name="smarturl" 
    select="info/metadata[@owner = $galeon]/smarturl" />
  <xsl:variable name="pixmap" 
    select="info/metadata[@owner = $galeon]/pixmap" />

  <!-- submit url is the part before the query string
     - XXX why are we using GET? -->
  <form method="get" action="{substring-before($smarturl, '?')}">

    <xsl:variable name="query" select="substring-after($smarturl, '?')" />

    <!-- parameters are separated by ampersands '&' -->
    <xsl:for-each select="str:tokenize($query, '&amp;')">

      <!-- param := name [ '=' value ] -->
      <xsl:variable name="name" select="substring-before(., '=')"/>
      <xsl:variable name="value" select="substring-after(., '=')"/>

      <xsl:choose>
        <!-- parameter with variable value -->
	<xsl:when test="$value = '%s'">
	  <input type="text" name="{$name}" value="" size="30" />
	</xsl:when>

	<!-- parameter without a value (I think) -->
	<xsl:when test="$name = $value">
	  <input type="hidden" name="{$name}" />>
	</xsl:when>

	<!-- parameter with fixed value -->
	<xsl:otherwise>
	  <input type="hidden" name="{$name}" value="{$value}" />
	</xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>

    <!-- use image for submit if we have one, ordinary button otherwise -->
    <xsl:choose>
      <xsl:when test="$pixmap">
	<input type="image" value="{title}" src="{$pixmap}" />
      </xsl:when>

      <xsl:otherwise>
	<input type="submit" value="{title}" />
      </xsl:otherwise>
    </xsl:choose>
  </form>
</xsl:template>
<!-- /smart bookmark -->

</xsl:stylesheet>
<!-- vim: set sts=2 sw=2: -->
myportal.html (text/html, 13.4 KB)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Transitional 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" type="text/css" href="file:/usr/local/share/galeon/myportal.css" />
    <title>My Portal</title>
  </head>
  <body>
    <div class="top_bar">
      <table cellpadding="2" cellspacing="0" width="100%" border="0">
        <tbody>
          <tr>
            <td><img alt="" src="file:/usr/local/share/galeon/galeon.png" />myportal:</td>
          </tr>
        </tbody>
      </table>
    </div>
    <div class="top2">
      <a href="http://galeon.sourceforge.net/">
        <img class="logo" alt="Galeon logo" src="file:/usr/local/share/galeon/logo.png" />
      </a>
    </div>
    <p>
      <br />
    </p>
    <blockquote>
      <a class="heading">
        <strong>Bookmarks</strong>
      </a>
      <blockquote>
        <a class="heading">
          <strong>New bookmarks</strong>
        </a>
        <br />
      </blockquote>
      <blockquote>
        <a class="heading">
          <strong>GNU / Linux</strong>
        </a>
        <br />
        <a href="http://www.fsf.org">Free Software Foundation (FSF)</a>
        <blockquote>
          <a class="heading">
            <strong>Gnome</strong>
          </a>
          <br />
          <a href="http://www.gnome.org/">Gnome.org</a>
          <a href="http://www.gnomedesktop.org">Footnotes - Gnome News Portal</a>
          <a href="http://es.gnome.org/">GNOME Hispano</a>
          <a href="http://www.gnomesupport.org/forums">Gnome User's Support Forum</a>
          <a href="http://www.gnomesupport.org">Gnome Support.org</a>
          <i>
            <a href="http://galeon.sourceforge.net/">Galeon: the web, only the web</a>
          </i>
          <blockquote>
            <a class="heading">
              <strong>Development</strong>
            </a>
            <br />
            <a href="http://developer.gnome.org/">The GNOME Developer Site</a>
            <a href="http://mail.gnome.org">Gnome Mailing Lists</a>
            <a href="http://bugzilla.gnome.org">Gnome Bugzilla</a>
            <a href="http://lidn.sourceforge.net">Api Documentation</a>
          </blockquote>
        </blockquote>
        <blockquote>
          <a class="heading">
            <strong>News</strong>
          </a>
          <br />
          <a href="http://www.desktoplinux.com">Desktop Linux</a>
          <a href="http://www.osnews.com">OSNews</a>
          <a href="http://www.pclinuxonline.com">Pclinuxonline</a>
          <a href="http://www.slashdot.org">Slashdot</a>
        </blockquote>
      </blockquote>
      <blockquote>
        <a class="heading">
          <strong>Internet</strong>
        </a>
        <br />
        <a href="http://www.w3.org/">The World Wide Web Consortium</a>
        <a href="http://galeon.sourceforge.net/">Galeon: the web, only the web</a>
      </blockquote>
      <br />
      <blockquote>
        <a class="heading">
          <strong>Toolbar</strong>
        </a>
        <br />
        <i></i>
        <form method="get" action="http://www.google.com/search">
          <input type="text" name="q" value="" size="30" />
          <input type="image" value="Google" src="/usr/local/share/galeon/google.png" />
        </form>
        <form method="get" action="http://groups.google.com/groups">
          <input type="text" name="q" value="" size="30" />
          <input type="hidden" name="meta" value="site%3Dgroups" />
          <input type="image" value="Usenet" src="/usr/local/share/galeon/google_groups.png" />
        </form>
        <form method="get" action="http://images.google.com/images">
          <input type="text" name="q" value="" size="30" />
          <input type="image" value="Images" src="/usr/local/share/galeon/google_images.png" />
        </form>
        <form method="get" action="http://www.wikipedia.org/w/wiki.phtml">
          <input type="text" name="search" value="" size="30" />
          <input type="submit" value="Dictionary" />
        </form>
        <blockquote>
          <a class="heading">
            <strong>Bookmarklets</strong>
          </a>
          <br />
          <a href="http://www.bookmarklets.com/">More Bookmarklets</a>
          <br />
          <a href="javascript:location.href=%22http://web.archive.org/web/*/%22+location.href">Old versions of this page</a>
          <a href="javascript:if(frames.length%3E0){F=' (Open frame in new window first.)'}else{F=''}Q=document.getSelection();if(!Q){void(Q=prompt('No text selected on page.'+F+'\n\nKeywords...?',''))};if(Q)location.href='http://bookmarklets.com/moreinfo.phtml?q='+escape(Q)">More Info About...</a>
          <br />
          <a href="javascript:if(document.images.length%3C1){alert('No image!')}else{D0iB=document.images[0];sZ2T=prompt('Resize by..','1.5');if(sZ2T){with(document){write('%3Cimg src='+D0iB.src+' width='+sZ2T*D0iB.width+' height='+sZ2T*D0iB.height+'%3E');close()}}}void(null)">Zoom on First Image...</a>
          <a href="javascript:if(frames.length%3C1){var c0l=prompt('Change to which background color?','');if (c0l != null) void(document.bgColor=c0l)}else{alert('Page has frames. Use the version of this bookmarklet for frames. (bookmarklets.com)')}">Page Color...</a>
          <br />
          <a href="javascript:var wN2sc8Rl;Sa5gNA9k=new Function('clearTimeout(wN2sc8Rl)');document.onkeydown=Sa5gNA9k;Sa5gNA9k();void(wN2sc8Rl=setInterval('if(pageYOffset%3Cdocument.height-innerHeight){window.scrollBy(0,1)}else{Sa5gNA9k()}',150))">Scroll Page (very slow)</a>
          <a href="javascript:var wN2scRl;Sa5gNA9k=new Function('clearTimeout(wN2scRl)');document.onkeydown=Sa5gNA9k;Sa5gNA9k();void(wN2scRl=setInterval('if(pageYOffset%3Cdocument.height-innerHeight){window.scrollBy(0,1)}else{Sa5gNA9k()}',50))">Scroll Page (slow)</a>
          <a href="javascript:var wN2scRl;Sa5gNA9k=new Function('clearTimeout(wN2scRl)');document.onkeydown=Sa5gNA9k;Sa5gNA9k();void(wN2scRl=setInterval('if(pageYOffset%3Cdocument.height-innerHeight){window.scrollBy(0,2)}else{Sa5gNA9k()}',50))">Scroll Page (fast)</a>
          <a href="javascript:var wN2scRl;Sa5gNA9k=new Function('clearTimeout(wN2scRl)');document.onkeydown=Sa5gNA9k;Sa5gNA9k();void(wN2scRl=setInterval('if(pageYOffset%3Cdocument.height-innerHeight){window.scrollBy(0,10)}else{Sa5gNA9k()}',50))">Scroll Page (very fast)</a>
          <a href="javascript:var wN2scRl;S3g=new Function('clearTimeout(wN2scRl)');document.onkeydown=S3g;a7T=prompt('Rate...','');if(a7T!=null){S3g();void(wN2scRl=setInterval('if(pageYOffset%3Cdocument.height-innerHeight){scrollBy(0,a7T)}else{S3g()}',50))}else{void(null)}">Scroll Page... (variable)</a>
          <br />
          <a href="javascript:if(frames.length%3C1){alert('The server indicates that the page was last modified: ' + window.document.lastModified)}else{alert('Page is framed. Use version of bookmarklet for frames. (bookmarklets.com)')}">Page Freshness?</a>
          <a href="javascript:if(frames.length%3E0){alert('Frames!')}else{ulBV3pQy=document.getSelection();if(ulBV3pQy!=''){location.href=ulBV3pQy.replace(/\042/g,'').replace(/\047/g,'').replace(/\s/g,'')}else{alert('Select text on page like:\n   http://www.domain.com...')}}">Go To Selected URL</a>
          <a href="javascript:dT30FfN3b=new Date();void(window.open(location.href,'w'+dT30FfN3b.getTime()))">Duplicate Page</a>
          <a href="javascript:void(InPageBookmark=pageYOffset)">Set In-Page Bookmark</a>
          <a href="javascript:if (typeof InPageBookmark=='undefined'){alert('No in-page bookmark. Use Set In-Page Bookmark tool. (bookmarklets.com)')}else{scrollBy(0,InPageBookmark-pageYOffset)}">Go To In-Page Bookmark</a>
          <br />
          <a href="javascript:if(document.cookie.length%3C1){alert('No cookie for this site.')}else{alert('Cookie for this site: '+document.cookie)}">Read Cookie for Site</a>
          <a href="javascript:function ROIoiW(){var i=0,j,A='anonymous',D,E,F=document.forms;while(i%3CF.length){E=F[i].elements;for(j=0;j%3CE.length;j++){D=E[j];if(D.type=='text'){D.value=(D.name.toUpperCase().indexOf('MAIL')!=-1)?A+'@example.com':A}}i++}}ROIoiW();void(null)">AutoFill Anonymous</a>
          <a href="javascript:void(location.href='http://translate.google.com/translate?hl=en%26u='+location.href)">Translate to English</a>
        </blockquote>
      </blockquote>
      <blockquote>
        <a class="heading">
          <strong>Sample Smart Bookmarks</strong>
        </a>
        <br />
        <form method="get" action="http://www.google.com/search">
          <input type="text" name="q" value="" size="30" />
          <input type="image" value="Google" src="/usr/local/share/galeon/google.png" />
        </form>
        <form method="get" action="http://groups.google.com/groups">
          <input type="text" name="q" value="" size="30" />
          <input type="hidden" name="meta" value="site%3Dgroups" />
          <input type="image" value="Usenet" src="/usr/local/share/galeon/google_groups.png" />
        </form>
        <form method="get" action="http://images.google.com/images">
          <input type="text" name="q" value="" size="30" />
          <input type="image" value="Images" src="/usr/local/share/galeon/google_images.png" />
        </form>
        <form method="get" action="http://www.m-w.com/cgi-bin/dictionary">
          <input type="text" name="va" value="" size="30" />
          <input type="submit" value="Dictionary" />
        </form>
        <form method="get" action="http://search.yahoo.com/bin/search">
          <input type="text" name="p" value="" size="30" />
          <input type="submit" value="Yahoo!" />
        </form>
        <form method="get" action="http://search.dogpile.com/texis/search">
          <input type="text" name="q" value="" size="30" />
          <input type="hidden" name="geo" value="no" />
          <input type="hidden" name="fs" value="web" />
          <input type="hidden" name="av" value="custom" />
          <input type="hidden" name="engines" value="goto" />
          <input type="hidden" name="engines" value="looksmart" />
          <input type="hidden" name="engines" value="thunderstone" />
          <input type="hidden" name="engines" value="findwhat" />
          <input type="hidden" name="engines" value="sprinks" />
          <input type="hidden" name="engines" value="directhit" />
          <input type="hidden" name="engines" value="google" />
          <input type="hidden" name="engines" value="infoseek" />
          <input type="hidden" name="engines" value="lycos" />
          <input type="hidden" name="engines" value="kanoodle" />
          <input type="hidden" name="engines" value="opendir" />
          <input type="hidden" name="engines" value="realnames" />
          <input type="hidden" name="engines" value="altavista" />
          <input type="hidden" name="engines" value="yahoo" />
          <input type="submit" value="Dogpile" />
        </form>
        <form method="get" action="http://www.linuxpackages.net/search_view.php">
          <input type="hidden" name="by" value="name" />
          <input type="hidden" name="what_cat" value="" />
          <input type="hidden" name="subcat" value="" />
          <input type="hidden" name="ver" value="8" />
          <input type="text" name="name" value="" size="30" />
          <input type="image" value="LinuxPackages" src="/usr/local/share/galeon/slack.png" />
        </form>
        <form method="get" action="http://finance.yahoo.com/q">
          <input type="text" name="s" value="" size="30" />
          <input type="hidden" name="d" value="c" />
          <input type="hidden" name="k" value="c4" />
          <input type="hidden" name="t" value="1d" />
          <input type="image" value="Stocks" src="/usr/local/share/galeon/stocks.png" />
        </form>
        <form method="get" action="http://bugzilla.gnome.org/show_bug.cgi">
          <input type="text" name="id" value="" size="30" />
          <input type="image" value="Bug #" src="/usr/local/share/galeon/bug.png" />
        </form>
        <form method="get" action="http://freshmeat.net/search">
          <input type="text" name="q" value="" size="30" />
          <input type="image" value="Freshmeat" src="/usr/local/share/galeon/freshmeat.png" />
        </form>
        <form method="get" action="http://www.gnu.org/search/fsd-search.py">
          <input type="text" name="q" value="" size="30" />
          <input type="image" value="GNU Free Software Directory" src="/usr/local/share/galeon/gnu.png" />
        </form>
        <form method="get" action="http://rpmfind.net/fux/rpm2html/search.php">
          <input type="text" name="query" value="" size="30" />
          <input type="image" value="RPMFind" src="/usr/local/share/galeon/rpm.png" />
        </form>
        <form method="get" action="http://packages.debian.org/cgi-bin/search_packages.pl">
          <input type="text" name="keywords" value="" size="30" />
          <input type="hidden" name="searchon" value="names" />
          <input type="hidden" name="subword" value="1" />
          <input type="hidden" name="version" value="all" />
          <input type="hidden" name="release" value="all" />
          <input type="image" value="Debian" src="/usr/local/share/galeon/debian.png" />
        </form>
      </blockquote>
    </blockquote>
    <div class="bottom_bar">
      <center><b>Galeon</b> : <i>the web, only the web</i></center>
    </div>
  </body>
</html>
signature.asc (application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQA+YLtiBKiYcWg4juYRAsgoAJwNoxvVpI8ZdvvLL2Fk8NpdmmFjTACeOo/B
1l0cjJSZvzg+sIbR2dDhvH8=
=akJv
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.