A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.

Jump to

Quick reference

Showing posts with label xsl. Show all posts
Showing posts with label xsl. Show all posts

XSL array/hash/lookup table

The lookup file:

<?xml version="1.0"?>
<lookup>
<location id="1769" guide="TT00379a" average="TT123456"/>
<location id="1230" guide="TT003999" average="TT000001"/>
</lookup>

The code: NOTE: $id is a local variable:


<!-- look up the country guide ID -->
<xsl:variable name="guide">
<xsl:for-each select="document('lookup.xml')">
<xsl:value-of select="key('map',$id)/@guide"/>
</xsl:for-each>
</xsl:variable>

URI encoding in Java

Deprecated Apache Commons HttpClient 3.x:
 
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;

String uriTest1(String uri) {
    String encodedUri = null;
    try {
        encodedUri = URIUtil.encodePath(uri,"UTF-8");
    } catch (URIException e) {
        System.err.println("Caught URI Exception");
        e.printStackTrace();
    }
    return encodedUri;
}

URIEncoder encodes to application/x-www-form-urlencoded (i.e. spaces turn to +)

import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URLEncoder;

String uriTest2(String uri) {
    String encodedUri = null;
    String encoding = "UTF-8";
    try {
        encodedUri = URLEncoder.encode(uri, encoding);
    } catch (UnsupportedEncodingException e) {
        System.err.println("Unsuported encoding: "+encoding);
        e.printStackTrace();
    }
    return encodedUri;
}

java.net.URI requires the whole URI to be input, but you can extract just the URI encoded query part (turns spaces to %20)

import java.net.URI;

private static String uriTest3(String path) {
    String encodedUri = null;
    URI uri = null;
    try {
        uri = new URI("http","bbc.co.uk","/search/news/",path,null);
    } catch (URISyntaxException e) {
        System.err.println("Caught URI Syntax Exception");
        e.printStackTrace();
    }
    encodedUri = uri.getRawQuery();
    return encodedUri;
}
See also.

oXygen Eclipse plugin

oXygen XML/XSLT: http://www.oxygenxml.com/download_oxygenxml_editor.html#Eclipse
  • it's not all that, but step-through-debugging does work
  • have to manually set the file association defaults to Oxygen types
  • unreadable default colour scheme for Oxygen filetypes. It is difficult to import syntax-highlighting preferences in Eclipse. You're better off setting them yourself.
  • to use step-through debugging, you need to:
    • 'Configure Transformation Scenario' (under XML/XSL menu - it appears when you open an XML or XSL file)
    • open the 'Debug Scenario' perspective in the XML/XSL menu
  • setting the input parameters for debugging is fiddly
  • the XML file being used as input must be "part of the project"

Nginx high-performance webserver

Nginx is a high-performance HTTP server. http://wiki.nginx.org/Main

Seems to be used by quite a lot of sites and a few people have noticed nginx 404 error pages by facebook and youtube indicating they may also be using it? http://wiki.nginx.org/NginxWhyUseIt

Comes also with a memcached module to talk with memcached directly: http://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/

And has embedded perl in it as standard: http://wiki.nginx.org/NginxEmbeddedPerlModule

And call perl directly from SSI
<!- # perl sub="module::function" arg="parameter1" arg="parameter2"... >

For XSLT fans: http://wiki.nginx.org/NginxHttpXsltModule

For-each over static values in XSL

When you want to do this:

<xsl:for-each select="$some_value in ('a','b','c','d')"><!-- invalid? -->

You have to do this:

<xsl:variable name="items">
    <item>a</item>
    <item>b</item>
    <item>c</item>
    <item>d</item>
</xsl:variable>

<xsl:for-each select="$items/item">
    <xsl:choose>
    <xsl:when test="$some_value = .">

Eclipse plugins

Eclipse 3.5
      • Target Management (Remote file browsing, via SSH): http://www.eclipse.org/dsdp/tm/
        • works great (but sshfs is simpler)
        • Instead of that, see also http://wills-tech-notes.blogspot.com/2010/07/remote-file-browsing.html
      • XSLT: http://www.eclipse.org/webtools/
        • can't download through update manager, it's too slow
        • supposed to offer XML/XSL features, but I can't see any
      • Oxygen XML/XSLT: http://www.oxygenxml.com/download_oxygenxml_editor.html#Eclipse
        • Works. To use step-through debugging,you need to open the 'Debug Scenario' in the XML or XSL menu (it appears when you open an XML or XSL file)
      • vim -- why not use vim editor inside Eclipse? No good solution, apparently (none of these were tested):
        • http://www.viplugin.com/viplugin/ (2009 - costs a few pounds)
        • http://eclim.org/vim/ (recent)
        • http://vrapper.sourceforge.net/ (recent)
        • http://sourceforge.net/projects/vimplugin/ (2007, but states it supports syntax files)
      • Full Screen: http://code.google.com/p/eclipse-fullscreen/ (just works) 
      • P4WSAD: Perforce plugin: http://www.perforce.com/perforce/products/p4wsad.html (had to download zip file from FTP site and install manually, as automatic install URL was too slow)
        • Plugin can be slow to use if you browse the repository directly, but is faster if you check out, then do right-click | Import as project, and use the standard Eclipse Navigator or Project tab to work with the files.

          How to use Saxon XSL 2 processor

          java -jar saxon9he.jar -xsl:/path/to/file.xsl -s:/path/to/file.xml -o:/path/to/output.xml parameter1='value1' parameter2='value2'

          XSL tips

          • In XSL templates, when generating new static elements with attributes, instead of <xsl:element name="foo"><xsl:attribute name="bar"><xsl:value-of select="'baz'"> etc, you can just do <foo bar="baz">! The main use for <xsl:element> and <xsl:attribute> is for dynamically named elements and attributes.
          • Print debug statements like this: <xsl:message><xsl:text>min_score = </xsl:text><xsl:value-of select="$min_score"/></xsl:message>

          Stop XML::LibXSLT and XML::LibXML connecting to w3.org

          If you have this line in your XML/XSL:

          <!DOCTYPE xml PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

          Then your parser may connect to w3.org for validation. If w3 blocks you for hammering their server, then you may get this error message: http error : Operation in progress

          http error : Operation in progress

          If you don't want/need validation against the DTD (and you probably don't), you can turn off that feature in XML::LibXML:

          1.70
          $parser = XML::LibXML->new(load_ext_dtd => 0);

          < 1.70
          $parser = XML::LibXML->new();
          $parser->load_ext_dtd(0);

          Min/Max for XSLT

          Obtaining the MIN:
          <!-- Create a variable named $minEventDate containing the MIN date -->
          <xsl:variable name="minEventDate">
          <xsl:for-each select="event">
          <xsl:sort select="@date" data-type="text" order="ascending" />
          <xsl:if test="position() = 1">
          <xsl:value-of select="@date" />
          </xsl:if>
          </xsl:for-each>
          </xsl:variable>

          Obtaining the MAX:
          <!-- Create a variable named $maxEventDate containing the MAX date -->
          <xsl:variable name="maxEventDate">
          <xsl:for-each select="event">
          <xsl:sort select="@date" data-type="text" order="descending" />
          <xsl:if test="position() = 1">
          <xsl:value-of select="@date" />
          </xsl:if>
          </xsl:for-each>
          </xsl:variable>

          XSLT1 processing, using Perl

          Example taken from XML::LibXSLT docs, code commented and replaced because of old versions of libs:
          $ perl -MXML::LibXML -le'print $XML::LibXML::VERSION'

          1.69

          $ perl -MXML::LibXSLT -le'print $XML::LibXSLT::VERSION'

          1.59


          Code:

          #!/usr/bin/perl

          use strict;
          use warnings;
          use XML::LibXSLT;
          use XML::LibXML;

          my $xslt = XML::LibXSLT->new();

          #my $source = XML::LibXML->load_xml(location => 'file.xml');
          my $parser = XML::LibXML-> new();
          my $source = $parser->parse_file('file.xml');

          #my $style_doc = XML::LibXML->load_xml(location=>'file.xsl', no_cdata=>1);
          my $parser2 = XML::LibXML-> new();
          my $style_doc = $parser2->parse_file('file.xsl');

          my $stylesheet = $xslt->parse_stylesheet($style_doc);

          my $results = $stylesheet->transform($source);

          #print $stylesheet->output_as_bytes($results);
          print $results->toString;

          XSL data types

          http://www.zvon.org/xxl/XSL-Ref/Tutorials/Built-in-Types/bt1.html

          <xsl:stylesheet
          xmlns:sch="http://www.w3.org/2001/XMLSchema"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          version="2.0"
          exclude-result-prefixes=" sch">

          <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

          <xsl:variable name="a" as="sch:integer" select="12"/>
          <xsl:variable name="b" as="sch:float" select="12.123456789123456789"/>
          <xsl:variable name="c" as="sch:double" select="12.123456789123456789"/>
          <xsl:variable name="d" as="sch:decimal" select="12.123456789123456789"/>

          </xsl:stylesheet>

          Debugging XSLT

          ...is not fun:

          <!-- DEBUG -->
          <xsl:if test="$debug">
          <xsl:message><xsl:text>--------</xsl:text></xsl:message>
          <xsl:message><xsl:text>FUNCTION display-pagination-links:</xsl:text></xsl:message>
          <xsl:message><xsl:text>--------</xsl:text></xsl:message>
          <xsl:message><xsl:text>direction: </xsl:text><xsl:value-of select="$direction"/></xsl:message>
          <xsl:message><xsl:text>link_type: </xsl:text><xsl:value-of select="$link_type"/></xsl:message>
          </xsl:if>

          XSLT math

          Using math in XSLT: http://www.xml.com/pub/a/2001/05/07/xsltmath.html

          <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          version="1.0">
          <xsl:output method="xml" omit-xml-declaration="yes"/>

          <xsl:template match="numbers">
          A. 4 + 3.2 = <xsl:value-of select="x + y"/>
          B. 3.2 - 4 = <xsl:value-of select="y - x"/>
          C. 4 * 3.2 = <xsl:value-of select="x * y"/>
          D. 11/3.2 = <xsl:value-of select="z div y"/>
          E. 4 + 3.2 * 11 = <xsl:value-of select="x+y*z"/>
          F. (4 + 3.2) * 11 = <xsl:value-of select="(x+y)*z"/>
          G. 11 mod 4 = <xsl:value-of select="z mod x"/>
          H. 4 + 3.2 + 11 = <xsl:value-of select="sum(*)"/>
          I. floor(3.2) = <xsl:value-of select="floor(y)"/>
          J. ceiling(3.2) = <xsl:value-of select="ceiling(y)"/>
          K. round(3.2) = <xsl:value-of select="round(y)"/>
          L. 11 + count(*) = <xsl:value-of select="11+count(*)"/>
          M. 3.2 + string-length("3.2") =
          <xsl:value-of select="y + string-length(y)"/>
          N. 11 + "hello" = <xsl:value-of select="z + 'hello'"/>
          </xsl:template>

          </xsl:stylesheet>


          Warning With some XSLT processors, the use of decimal numbers may introduce a tiny error. For example, the "3.2 - 4" in this example comes out as "-.7999999999999998" on some processors. While being off by .0000000000000002 isn't much, being off at all shows that math is not XSLT's strong point.

          Display output of XSL transformation using PHP

          Use XAMPP or similar to serve (reportedly works on PHP 5):

          <?
          $query = $_GET['q'];
          $filePath = 'http://source-server:8889/page/'.$query;

          $xslDoc = new DOMDocument();
          $xslDoc->load("http://localhost/xslt/page_render.xsl");
          $xmlDoc = new DOMDocument();
          $xmlDoc->load( $filePath );

          $proc = new XSLTProcessor();

          $proc->importStylesheet($xslDoc);
          echo $proc->transformToXML($xmlDoc);
          ?>

          No XSLT2 in PHP

          There is only one known xslt2 processor called SAXON (http://saxon.sourceforge.net/), built by Michael Kay, which was released for the Java and .NET platforms.

          Other XSLT processors, including Sablotron, Xalan and MSXML, have not yet adopted xslt2.

          Kay writes: "implementation [for xslt2 in php] does not exist because no-one has written one". He continues, "The usual workaround I recommend is to implement XSLT 2.0 transformation as a (Java-based or .NET-based) REST web service, and for the php application to submit transformation requests to that web service by means of HTTP requests. An alternative is to use a php-Java bridge"

          Michael Kay manages an email-based discussion group called MulberryTech, a good resource for learning XSLT techniques (both 1 and 2). (http://www.mulberrytech.com/xsl/xsl-list/)


          (If, Then, Else) LOGIC in XSL

          Syntax:
          <xsl:if test="XXX">
          <!-- do something -->
          </xsl:if>

          <xsl:choose>
          <xsl:when test="XXX">
          <!-- do one thing -->
          </xsl:when>
          <xsl:when test="YYY">
          <!-- do another thing -->
          </xsl:when>
          <xsl:otherwise>
          <!-- do default thing -->
          </xsl:otherwise>
          </xsl:choose>


          Logic examples:
          <xsl:when test="matches(sql:feedurl_id, '^(\d+)$')">
          <xsl:if test="$canonical-urls/agg:canonical-url[text()=$canonical-link-href][1]/@module = $module-type">
          <xsl:when test="$module-type = 'knowledge'">
          <xsl:when test="$module-type='iplayer' or $module-type='schedule'">
          <xsl:if test="$debug">
          <xsl:when test="document('')//this:modules/this:module[@type=$module-type]/this:merge-feeds">
          <xsl:if test="position()=1">
          <xsl:if test="position()=3 and count(agg:module)=0">
          <xsl:when test="starts-with($name,'profile') or starts-with($name,'weather')">
          <xsl:when test="starts-with(@type,'profile')">
          <xsl:when test="@type='weather'">
          <xsl:when test="count($modules/agg:modules/agg:module[starts-with(@type,'profile')])>0">

          Cocoon XSLT errors

          java.lang.NullPointerException

          This could mean you've used the wrong attribute name in a tag, e.g.
          <xsl:attribute type="type">
          instead of
          <xsl:attribute name="type">

          There seems to be no syntax checking to warn in cases like this.

          XML::Validator::Schema

          #!/usr/bin/perl

          use XML::SAX::ParserFactory;
          use XML::Validator::Schema;
          # create a new validator object, using foo.xsd
          $validator = XML::Validator::Schema->new(file => 'foo.xsd');
          # create a SAX parser and assign the validator as a Handler
          $parser = XML::SAX::ParserFactory->parser(Handler => $validator);
          # validate foo.xml against foo.xsd
          eval { $parser->parse_uri('foo.xml') };
          die "File failed validation: $@" if $@;

          The problem is:

          Nested comments

          Are your comments disappearing when you wrap them with a <xsl:comment> tag?

          They may already be inside a comment.