xsl-list
[Top] [All Lists]

Re: URIResolver howto

2002-10-01 09:55:40
Thanks for the detailed how-to :)
Vedu
--- Robert Koberg <rob(_at_)koberg(_dot_)com> wrote:
Hi, [I sent this with the wrong email address, sorry
if it comes through twice]

I recieved a few requests for a better example of
how to use the URIResolver. I
hope the information below helps.

When you need control over xsl:include/import or the
document(), you need to use
an URIResolver - you cannot do it in your
stylesheet. This is very useful when
you have a 'primary' XSL[1]  and it includes,
imports or uses document() to
bring in other XML/XSL files/streams from two or
more different points of
control.

As a simple example lets say a user logs on to a
server-side application. The
user can choose different navigation styles to get
around a site (dynamic JS or
static HTML). You would need to somehow get or keep
a user preference that tells
the app which nav option they have choosen.

We might have a primary XSLT like:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
<xsl:include href="head.xsl"/>
<xsl:include href="banner.xsl"/>
<xsl:include href="nav.xsl"/>
<xsl:include href="footer.xsl"/>
<xsl:template match="/">
<html>
  <xsl:call-template name="head"/>
  <body>
    <xsl:call-template name="banner"/>
    <div id="leftcol">
      <xsl:call-template name="nav"/>
    </div>
    <div id="centercol">
       call some templates
    </div>
    <div id="rightcol">
      <div class="floater">
        call some templates
      </div>
    </div>
    <br clear="all"/>
    <xsl:call-template name="footer"/>
  </body>
</html>
</xsl:template>
</xsl:stylesheet>

There are two different sets of the head and nav and
to keep things modular. So
you might use static_head.xsl & static_nav.xsl or
dynamic_head.xsl &
dynamic_nav.xsl. You need an URIResolver to handle
which set to include.

You may have a method that starts transformations in
the app:

void xform(ServletContext servlet_context,
HttpServletRequest req,
HttpServletResponse res, long _start_time)
      throws TransformerException, java.io.IOException
{

  System.setProperty(
    "javax.xml.transform.TransformerFactory",
    "com.icl.saxon.TransformerFactoryImpl");
  ServletOutputStream out = res.getOutputStream();
  HttpSession http_session = req.getSession();
  String nav_style =
http_session.getAttribute("nav_style").toString();
  String source =
http_session.getAttribute("source").toString();
  String style =
http_session.getAttribute("style").toString();
  try {
      Templates pss = tryCache(servlet_context,
style, nav_style);
      Transformer transformer =
pss.newTransformer();
      Properties details =
pss.getOutputProperties();
      String mime =

pss.getOutputProperties().getProperty(OutputKeys.MEDIA_TYPE);
      if (mime==null) {
        res.setContentType("text/html");
      } else {
        res.setContentType(mime);
      }
      transformer.setParameter("nav_style",
nav_style);
      transformer.transform(
          new StreamSource(source)),
          new StreamResult(out));
      out.close();
      out.flush();
    } catch (Exception err) {
      System.out.println(err);
    }
}

Your tryCache method might look like:

private synchronized Templates
tryCache(ServletContext serv_context, String
path, String nav_style)
    throws TransformerException, java.io.IOException
{
  String full_path = serv_context.getRealPath(path);
  Templates x = (Templates)this.cache.get(path);
  if (x==null) {
      TransformerFactory factory =
TransformerFactory.newInstance();
      factory.setURIResolver(new
MyResolver(serv_context, nav_style));
      x = factory.newTemplates(new StreamSource(new
File(full_path)));
      this.cache.put(path, x);
  }
  return x;
}

This primary XSLT needs to find files identified in
the xsl:includes/imports and
document(). The following URIResolver simply checks
the href argument
automatically sent in by the transformation process.
The href argument is the
value of the href in the xsl:include/import or the
first (or only) argument from
the document function. The base argument is either
the location of the primary
XSLT or the second argument in the document(). If it
sees head.xsl or nav.xsl it
prepends the filename with the nav style preference
string:

class MyResolver implements URIResolver {
  String base_path;
  String nav_style;
  public MyResolver(ServletContext context, String
style) {
    this.base_path =
context.getRealPath("/WEB-INF/styling/");
    this.nav_style = style;
  }

  public Source resolve(String href,String base) {
    StringBuffer path = new
StringBuffer(this.base_path);
    if (href.equals("head.xsl") |
         href.equals("nav.xsl")) {
      path.append(this.nav_style);
      path.append("_");
    }
    path.append(href);
    File file = new File(path.toString());
    if(file.exists()) return new StreamSource(file);
    return null;
  }
}


best,
Rob Koberg
livestoryboard.com

[1] the XSL used as the argument in the
transformation against the main source
XML



 XSL-List info and archive: 
http://www.mulberrytech.com/xsl/xsl-list



__________________________________________________
Do you Yahoo!?
New DSL Internet Access from SBC & Yahoo!
http://sbc.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



<Prev in Thread] Current Thread [Next in Thread>