4 XSL(T) Transformations without our interface

The XhiveTransformerIf and XhiveFormatterIf interfaces in com.xhive.util.interfaces are really convenient access methods to Xalan and FOP of Apache project respectively. In some cases you may want to use the more advanced options of these packages. This is why we give you our implementation of these interfaces here, to give you a starting point on how to use the interfaces of those packages.

4.1 XhiveFormatterIf.formatAsPDF

  import org.apache.fop.apps.Driver;
  import org.apache.fop.apps.Version;

  public void formatAsPDFToStream(Document foSource, OutputStream os) throws XhiveException {  
    try {                                                                                                   
      Driver driver = new Driver();
      driver.setRenderer("org.apache.fop.render.pdf.PDFRenderer", Version.getVersion());
      driver.addElementMapping("org.apache.fop.fo.StandardElementMapping");
      driver.addElementMapping("org.apache.fop.svg.SVGElementMapping");
      driver.addPropertyList("org.apache.fop.fo.StandardPropertyListMapping");
      driver.addPropertyList("org.apache.fop.svg.SVGPropertyListMapping");
      driver.setOutputStream(os);
      driver.buildFOTree(foSource);
      driver.format();
      driver.render();               
    } 
    catch(Exception e) {
      throw new XhiveException(XhiveException.FORMAT_EXCEPTION, e);
    }
  }

The sample code above is for a quite an old version (0.20) of FOP, shipped with X-Hive/DB. When you want to use a newer version of FOP in combination with X-Hive/DB, you could use a routine like:

  import org.apache.avalon.framework.logger.ConsoleLogger;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.fop.apps.Driver;
  import org.apache.fop.messaging.MessageHandler;

  public static void formatAsPDFToStream(DOMImplementation docCreator, Document xmlSource, Document xslSource, OutputStream os)
      throws XhiveException {
    try {
      // XSLT part
      XhiveTransformerIf transformer = XhiveDriverFactory.getDriver().getTransformer();
      Document foDocument = transformer.transformToDocument(docCreator, xmlSource, xslSource);

      // FOP part
      Driver driver = new Driver();
      Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_ERROR);
      MessageHandler.setScreenLogger(logger);
      driver.setLogger(logger);
      driver.setRenderer(Driver.RENDER_PDF);
      driver.setOutputStream(os);
      driver.render(foDocument);
    } catch (Exception e) {
      //e.printStackTrace();
      throw new XhiveException(XhiveException.FORMAT_EXCEPTION, e);
    }
  }

4.2 XhiveTransformerIf.transform...


  import com.xhive.core.interfaces.XhiveSessionIf;
  import com.xhive.error.XhiveException;
  import com.xhive.dom.*;
  import org.w3c.dom.*;
  import javax.xml.transform.*;
  import java.io.*;
  import java.util.Iterator;

  public Document transformToDocument(DOMImplementation docCreator, Node xmlSource, Document xslSource)
      throws XhiveException {

    Document result = docCreator.createDocument("", "Result", null);
    Node rootElem = result.getDocumentElement();
    result.removeChild(rootElem);

    transform(xmlSource, xslSource, new DOMResult(result));
    return result;
  }

  public void transformToStream(Node xmlSource, Document xslSource, Writer writer)
      throws XhiveException {
    transform(xmlSource, xslSource, new StreamResult(writer));
  }

  public String transformToString(Node xmlSource, Document xslSource)
      throws XhiveException {

    StringWriter result = new StringWriter();
    transformToStream(xmlSource, xslSource, result);
    return result.toString();
  }

  private void transform(Node xmlSource, Document xslSource, Result result) {
    try {
      // Try to initialize URI resolver
      URIResolver myResolver;
      try {
        XhiveSessionIf session = ...; // Left as an exercise to the reader
        if (session != null) {
          myResolver = new XhiveURIResolver(session);
        } else {
          myResolver = null;
        }
      } catch (Exception e) {
        // (No session?) Fine, then we don't use a URIResolver
        myResolver = null;
      }

      TransformerFactory tFactory = TransformerFactory.newInstance();
      if (myResolver != null) {
        // Factory resolver must be set before transformer is created
        tFactory.setURIResolver(myResolver);
      }
      Transformer transformer = tFactory.newTransformer(new DOMSource(xslSource));
      if (myResolver != null) {
        transformer.setURIResolver(myResolver);
      }

      transformer.transform(new DOMSource(xmlSource), result);
    } catch (Exception e) {
      throw new XhiveException(XhiveException.TRANSFORM_EXCEPTION, e);
    }
  }




  /**
   * URI resolver that translates
   *  xhive:path#query
   * into an xquery run on path, e.g.
   *  xhive:/plays#//TITLE
   */
  private class XhiveURIResolver implements URIResolver {
    private static final String XHIVE_PREFIX = "xhive:";
    private static final String SEPARATOR = "#";

    private XhiveSessionIf session;

    public XhiveURIResolver(XhiveSessionIf session) {
      this.session = session;
    }

    public Source resolve(String href, String base) throws TransformerException {
      // Do we need to do anything?
      if (((base == null) || (!base.startsWith(XHIVE_PREFIX))) &&
          (!href.startsWith(XHIVE_PREFIX))) {
        return null;
      } else {
        // Process href
        // Up to us to come up with a result
        if (!href.startsWith(XHIVE_PREFIX)) {
          // Create href with base
          href = base + href;
        }
        // Strip xhive: from href
        href = href.substring(XHIVE_PREFIX.length());
        if (!href.startsWith("/")) {
          href = "/" + href;
        }

        // Separate in path and query
        String path = null;
        String query = null;
        if (href.indexOf(SEPARATOR) != -1) {
          path = href.substring(0, href.indexOf(SEPARATOR));
          query = href.substring(href.indexOf(SEPARATOR) + 1);
        } else {
          path = href;
        }
        // Get query context
        XhiveLibraryChildIf contextNode = session.getDatabase().getRoot().getByPath(path);
        if (contextNode == null) {
          // Nothing found, error or null?
          throw new TransformerException("XhiveXalanTransfomer: Could not resolve " + href);
          //return null;
        } else {
          if (query == null) {
            if (contextNode instanceof XhiveDocumentIf) {
              return new DOMSource(contextNode);
            } else if (contextNode instanceof XhiveBlobNodeIf) {
              return new StreamSource(((XhiveBlobNodeIf) contextNode).getContents());
            } else {
              throw new TransformerException("XhiveXalanTransfomer: " + href + " is not a document");
            }
          } else {
            return getExecuteQuerySource(contextNode, query, href);
          }
        }
      }
    }

    private Source getExecuteQuerySource(XhiveLibraryChildIf contextNode, String query, String href) throws TransformerException {
      if (query.startsWith("xpointer(") && query.endsWith(")")) {
        query = query.substring("xpointer(".length(), query.length() - 1);
      }
      Iterator queryResult = null;
      try {
        queryResult = contextNode.executeXQuery(query);
      } catch (XhiveException e) {
        throw new TransformerException("XhiveXalanTransformer: Problem with query " + href + ": " + e.getMessage(), e);
      }
      // We will only use the first result here (otherwise we would have to include a new top-element)
      if (queryResult.hasNext()) {
        XhiveXQueryValueIf queryValue = (XhiveXQueryValueIf) queryResult.next();
        // Is it a node?
        try {
          return new DOMSource(queryValue.asNode());
        } catch (XhiveException e) {
          // must be XQUERY_ERROR_VALUE, so interpret it as a string
          return new StreamSource(new StringReader(queryValue.asString()));
        }
      } else {
        throw new TransformerException("XhiveXalanTransformer: Query " + href + ": " + " has no results");
      }
    }
  }

For improved Xalan XSLT performance, it may be wise to create Templates objects using the newTemplates call on TransformerFactory. What follows is an example of this, see the Xalan documentation for details.

  TransformerFactory tFactory = TransformerFactory.newInstance();
  tFactory.
  translet    = tFactory.newTemplates(new DOMSource(xslSource));
  // Now keep this translet cached somewhere, and for transforming do:
  Transformer transformer = translet.newTransformer();
  transformer.transform( new DOMSource(xmlSource), new StreamResult(writer)) ) ;
One advantage of a compiled stylesheet is that it no longer has references to any X-Hive/DB persistent data, so you can use the compiled version with any session.