Advanced API Usage

This document is work in progress. It is intended to discuss the topic of enhancing MorganaXProc's operations by writing your own Java classes and then attach them to MorganaXProc's operations.

This documentation will expand over time. For now the following themes are covered:

How to write a wrapper for non-xml data

XProc is all about working with xml data. But sometimes it is quite useful to work with data that is non-xml. For this purpose, <p:data> allows you to read an arbitrary resource from a URI. To make this resource compatible with xml processing, an xml wrapper element is put around the data.

The basic idea of wrappers in MorganaXProc goes one step further by allowing you to convert non-xml data into valid xml on the fly, while reading the resource in <p:data>. This can be handy for example if you want to process some plain text document with XProc. An on-the-fly converter might read the text document and put some <paragraph> elements around some sequence of characters by looking for double line breaks.

Another use case for a wrapper is data available as CSV, perhaps extracted from some data base or a spread sheet document. It is easy to think the character stream in a csv file as an xml document: Put an element named "table" around the data, put an element named "row" around each line and an element "column" around every piece of data.

MorganaXProc comes with such a wrapper found in "com.xml_project.morganaxproc.datawrapper.CSVWrapper". To use this wrapper, add an attribute "data-wrapper" in MorganaXProc's namespace "https://www.xml-project.com/morgana" in your <p:data> element and give the mentioned Java class name as value for the attribute. As a result of adding this attribute to <p:data> a document will appear which has a document element defined by the usual options set for <p:data> and has one child element named "table" which contains the csv data in the described form.

Using the attribute "{http://www.xml-project.com/morgana}data-wrapper" in a single <p:data> might be handy, but what if you have a lot of <p:data> in your pipeline(s) and want to use a lot of data conversion. In this case you can enable a data wrapper by using a DataWrapper element in your MorganaXProc configuration document.

To implement a data wrapper is very easy because you just have to write a class implementing interface "com.xml_project.morganaxproc.filesystem.DataWrapper". This interface has only one method with the following signature:

public LoadResult wrap(byte[] data, String mimeType, String encoding, String uri)
throws IOException;

The conversion itself is done as a sequence of String operations, which will return a LoadResult instance like this:

return new LoadResult(encoding, convertedData, mimeType, uri);

In order for MorganaXProc to find your implementation of "DataWrapper", supply it as JAR file in folder "Extensions" of MorganaXProc's folder. You can put it anywhere inside the extension folder using subfolders as you like. MorganaXProc will look in every JAR file in folder "Extensions" to find a class with the qualified java class name you supplied as value for "data-wrapper" or "DataWrapper".
Please mind that using this feature will make your XProc pipelines incompatible with other XProc processors.

Connectors for XSLT and XQuery processors

As discussed in other places in this documentation, MorganaXProc has a special feature when it comes to execute <p:xslt> or <p:xquery> in your XProc pipelines. The XQuery or XSLT processors needed to execute this steps are accessed indirectly by MorganaXProc using a mechanism called "Connector". A connector can be understood as an envelope around a specific XSLT or XQuery processor exposing the functionality needed for the corresponding XProc steps. MorganaXProc comes with three different XSLTConnectors and four XQueryConnectors, but you might be interested in supplying a Connector for your favorite XSLT and/or XQuery processor. Let us see how to do this.

The basic functionality needed is in the classes and interfaces of package "com.xml_project.morganaxproc.connectors". Each connector consists of two Java classes.

  • The first class has to extend an abstract class called "XQueryConnector" or "XSLTConnector". Here you have to implement some basic information about the processor you are using (an info string to display its usage while pipeline execution, the version of XQuery or XSLT implemented), a mechanism to return an xml document informing about errors while compiling the query or the stylesheet and basically the method "compile()". This method should invoke the compiler of the XQuery or XSLT processor and return an instance of the "XQueryExpression" or "XSLTTemplate" in case of successful compilation. If compilation fails for some reason, method "compile()" has to return "null" and "getErrorDocument()" should then return an xml document explaining what went wrong.

    Both connector classes contain a method "setURIResolver()" which will be called by MorganaXProc to connect the used XProcFilesystem and also the used XProcSecurityManager to the processor used. You should, if possible, supply an implementation for this method so that all ressources available to the pipeline are also available to the query or the stylesheet. In addition the security shield built into MorganaXProc can be expanded to XQuery and XSLT processing so the query and the stylesheet can only access ressources (via "doc()" or "collection()") allowed by the security system. If you do not implement "setURIResolver" the respective processor has to obtain ressources by itself and there is no security control what ressources are accessed. You should give an information to the pipeline users in this case using either the standard output stream or the standard error stream.

  • The second element of a Connector has to be a class (returned by "compile()") which implements interface "XQueryExpression" or "XSLTTemplate". It has to implement the basic functionality of setting the dynamic context for processing, do the processing itself, access the result(s) of processing and provide information about errors occurred during processing. The interface "XSLTTemplate" provides methods for XSLT as well as for XSLT 2.0 processing. If you are implementing a connector for an XSLT processor, just supply a stub implementation for the XSLT 2.0 specific methods.

In order for MorganaXProc to find your connector, supply it as JAR file in the folder "Extensions" of MorganaXProc’s folder. You can put it anywhere inside the extension folder using subfolders as you like. MorganaXProc will look in every JAR file in folder “Extensions” to find a class with the qualified java class name you supplied as value for "XSLTConnector" or "XQueryConnector" in your configuration document.

Supplying your own XProcFilesystem

MorganaXProc comes with a pluggable mechanism for accessing external ressources from within XProc pipelines. This functionality is provided with the abstract class "XProcFilesystem". MorganaXProc comes with two implementations (extensions) of "XProcFilesystem" supplying access to ressources with the schemes "file", "http" and "https" and an implementation for using the standard http methods in <p:http-request>. If you need access to ressources available using other schemes or need additional methods in <p:http-request>, you can supply your own implementation of "XProcFilesystem" to MorganaXProc by using the configuration document or select it directly with "XProcConfiguration". The methods you have to implement are:

protected StreamResult getInputStream(URI uri)
protected OutputStream getOutputStream(URI uri)
protected String getContentType(URI uri)
protected String getEncoding(URI uri)
protected XProcHttpResponse httpRequest(XProcHttpRequest request)
protected void clearCookieStore() and
protected String[] getDirectoryList(URI uri)

All uris supplied to this methods are already made absolute using the relevant base uri so you do not have to take care about this. Of course you can implement your own XProcFilesystem by extending class "DefaultFilesystem", providing just an implementation for the schemes or methods you would like to support and do a call to "super" for all other schemes/methods. To use your customized version of XProcFilesystem with MorganaXProc you have to create a JAR file and put it somewhere in the folder "Extensions" of MorganaXProc's folder. Additionally you have to give the full class name as value for attribute "value" in the "FileSystem" element of your configuration document.