Extensions :: XML Loader & Transformer

Reference - Loading XML

XmlLoader is a 'source-class' compatible helper class that can load and transform XML/JSON content and provide XPath and DOM oriented access to the document elements when used in combination with a velocity template.

The loader supports remote URLs (e.g. REST-services) and local paths to get the XML (or JSON) content (similar to the standard inclusion engine).

Use this loader when you want to access the parsed content of XML (or JSON) markup using the DOM API with the option to apply optional XSL transformations. This extension is not needed if your aim is to include code snippets that are selected using XPath expressions.

Usage:
%{include|source=template.vm|source-class=org.tinyjee.maven.dim.extensions.XmlLoader|xml=file.xml}
or when using the alias:
%{include|source=template.vm|source-xml=file.xml}
include XML after XSL transformation:
%{include|source-xml=file.xml|xsl=transform-to-html.xsl}

Parameters:

Parameter Name Description
Input Parameters (set with the macro call)
"source-xml" Defines a shortcut for the request properties 'source-class' and 'xml'.

If this parameter is present inside the request parameters list, the system will effectively behave as if 'source-class' and 'xml' where set separately.
"xml" Sets the URL or local path to the XML file to load inside the request parameters.

The specified file is resolved in exactly the same way as when using the parameter "source" (see Macro reference).

Note: When no further source is specified, the xml loader sets the serialized representation of this file as the content that is included by the macro. If a source IS specified, the defined out parameters are set and allow DOM or XPath based access to the document structure.
"xml-class" Sets a fully qualified class name to a class that either provides a Document instance, a Source or is annotated with XmlRootElement.

The specified class is resolved in exactly the same way as when using the parameter "source-class" (see Macro reference).

In addition to fully qualified class names, this parameter supports also factory methods that create the classes:
  • my.package.MyClass
  • my.package.MyClass.getInstance()
  • my.package.MyClassFactory.getMyClass()
  • my.package.MyClassFactory.getInstance().getMyClass()

Source class is implemented as a convenience parameter to "xml=class:", thus using the xml=class:my.pa.. is exactly the same as using xml-class=my.pa... Effectively this means that if this loader is used with the alias syntax, xml classes can be used via source-xml=class:my.package.MyClass.
"json" Experimental: Sets the URL or local path to JSON encoded content that is translated to XML and included.

JSON to XML transcoding is currently experimental and is primarily meant to be used for XSL or XPath matching on a JSON source (e.g. from a REST web service). See PositioningJsonDocumentBuilder for details on how JSON is mapped to XML.
"xsl" Optional parameter, sets the path to an XSL file that is used to transform the given input.

The specified file is resolved in exactly the same way as when using the parameter "source" (see Macro reference).

When a transformation is performed, all given macro call parameters are passed to the XSL processor making them available as xsl params when using global definitions like:
<xsl:param name="my-macro-param" select="'default-value'">
"add-xsl" Optional parameter, sets a relative or absolute URL to an XSL file that is added as standard template to the document being included but it is not executed.

This is useful to place <?xml-stylesheet ... declarations in included content.
"add-declaration" Optional parameter, enables the inclusion of the XML declaration (<?xml...) if set to "true".
"load-schema" Enum parameter that specifies whether XML schemata are loaded in order to include them with the XML content. (Default: false) Possible values for this parameter are: (true|false|local-only)

Note: Enabling this option does not enable schema validation, it enables loading schema content into the output parameter schemaMap.
"indent" Optional parameter, toggles whether the XML is indented before inclusion.
"namespace-aware" Optional parameter, toggles whether the XML parser handles namespaces.

The default value for this option is 'true' when an XML transformation is specified (= xsl is set). Without a xml transformation namespace awareness is turned off by default to simplify xpath based matching.
Output Parameters (set by the extension)
"document" Is set with the parsed document object (Document) and can be accessed from velocity templates.
"originalDocument" Is set with the original parsed document as it existed before applying any transformations. When xsl is not set, originalDocument and document are the same.
"schemaMap" If filled with a map of all loaded XML schemata (in case of schema loading is enabled).

The map contains entries of the format:
[
    "schema-system-id": Document,
    ...
]

Note: Schema loading works with any input type that defines a schema (including schema generation on JAXB classes).

Tipp: Schema content can either be included in the site, parts can be included via XPath matching or finally schema files can also be linked using:
Referenced XML schemata:<ul>
#foreach($entry in $schemaMap.entrySet())
   #if($entry.key.startWith("http"))
       #set($href=$entry.key)
   #else
       #set($href=$globals.attachContent($entry.key, $xpath.serialize($entry.value)))
   #end
   <li><a href="$href">$href</a></li>
#end </ul>
"xpath" Is set with an implementation of "XPathEvaluator" that is configured to match xpath expressions against DOM tree of document.

Usage (from within a velocity template):
Title of $document.documentURI is: $xpath.findText("/html/head/title")

Note: When namespace-aware is set to true, elements are matched using namespace prefixes. This is true also for the default namespace configured via xmlns="http://some/namespace". The xpath evaluator assigns the prefix "default" for the default namespace in order to make it accessible for an xpath evaluation.
E.g. the XHTML example from above changes to $xpath.findText("/default:html/default:head/default:title"). As a consequence, other namespace URIs that use a prefix of "default" will be ignored and are therefore unsupported.
"originalXpath" Is the same as "xpath" but configured to match on the original document.
Note: Output parameters are set when this extension is used and can be accessed from velocity templates using $nameOfOutputParameter
Implementation "org.tinyjee.maven.dim.extensions.XmlLoader": ApiDoc | Source

Usage Examples:

XML Transformation

Example: Extracting a simple summary from the root POM using XML transformation.

pom-html-summary.xsl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:pom="http://maven.apache.org/POM/4.0.0">
    <xsl:template match="pom:project">
        <ul>
            <li>
                Project "<xsl:value-of select="pom:name"/>"
            </li>
            <li>
                Group "<xsl:value-of select="pom:groupId"/>"
            </li>
            <li>
                Version "<xsl:value-of select="pom:version"/>"
            </li>
        </ul>
    </xsl:template>
</xsl:stylesheet>

Macro call:

%{include|source-xml=pom.xml|xsl=pom-html-summary.xsl}

Result:

  • Project "Doxia :: Include Macro"
  • Group "org.tinyjee.dim"
  • Version "1.1"

Verbatim Result (verbatim=true):

1
2
3
4
5
6
7
<ul xmlns:pom="http://maven.apache.org/POM/4.0.0"><li>
                Project "Doxia :: Include Macro"
            </li><li>
                Group "org.tinyjee.dim"
            </li><li>
                Version "1.1"
            </li></ul>

XPath Evaluation

Example: Extracting a simple summary from the root POM using the XPath evaluator and Velocity

pom-html-summary.apt.vm:

1
2
3
4
5
6
7
8
9
10
11
#foreach($node in $xpath.findNodes("project"))
    #set($context = $xpath.newEvaluator($node))
  
    * Project: "$context.findText("name")"
  
    * Group: "$context.findText("groupId")"
  
    * Version: "$context.findText("version")"
  
#end
    []

Macro call:

%{include|source=pom-html-summary.apt.vm|source-xml=pom.xml}

Result:

  • Project: "Doxia :: Include Macro"
  • Group: "org.tinyjee.dim"
  • Version: "1.1"

Verbatim Result (verbatim=true):

1
2
3
4
5
6
7
* Project: "Doxia :: Include Macro"
 
* Group: "org.tinyjee.dim"
 
* Version: "1.1"
 
[]

JAXB Support

In a lot of cases JAXB datatypes that implement interfaces must be documented. XmlLoader can help to 'load' the assigned XML schema and include XML sample content of the implemented types.

Including sample content:

%{include|source-xml=class:samples.SampleXmlType.getSampleInstance()}
1
2
3
<ns2:sample xmlns:ns2="urn:org.tinyjee.dim" doIt="Yes">
    <activity>Include serialized Xml from JAXB root elements.</activity>
</ns2:sample>

Including a snippet of sample content:

%{include|source-xml=class:samples.SampleXmlType.getSampleInstance()|namespace-aware=true|snippet=xp://activity}
2
<activity>Include serialized Xml from JAXB root elements.</activity>

Including sample content as a link:

%{include|source=classpath:/templates/dim/xml-link.xdoc.vm|source-xml=class:samples.SampleXmlType.getSampleInstance()}
sample-xml-type.xml

Including the XML schema (XSDs):

%{include|source=classpath:/templates/dim/xsd-linklist.xdoc.vm|source-xml=class:samples.SampleXmlType|load-schema=local-only}

JAXB Type

The JAXB implementation for this example is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package samples;
  
import javax.xml.bind.annotation.*;
  
/**
 * Provides a sample file for JAXB related operations.
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "sample", namespace = "urn:org.tinyjee.dim")
public class SampleXmlType {
  
    @XmlType
    public enum YesNoOption {
        Yes,
        No
    }
  
    @XmlAttribute(required = true)
    private YesNoOption doIt;
    @XmlElement(required = true)
    private String activity;
  
    public SampleXmlType() {
    }
  
    public SampleXmlType(YesNoOption doIt, String activity) {
        this.doIt = doIt;
        this.activity = activity;
    }
  
    public static SampleXmlType getSampleInstance() {
        return new SampleXmlType(YesNoOption.Yes, "Include serialized Xml from JAXB root elements.");
    }
}

Related Templates

The following bundled templates work well together with this extension:

XML Link Template

The bundled template classpath:/templates/dim/xml-link.xdoc.vm allows to attach and link XML content after loading and processing. (Attached content is stored next to the document to ensure it is static once the documentation was built)

Usage:

%{include|source=classpath:/templates/dim/xml-link.xdoc.vm|source-xml=....}

Example:

  • Attaching the project license definition as separate document:
    %{include|source=classpath:/templates/dim/xml-link.xdoc.vm|source-xml=pom.xml|snippet-xpath=//license|filename=examples/project-license.xml}
    
    project-license.xml

Template Source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0"?>
#*
    Is a velocity template that creates a link to an attached XML document which was loaded with XML loader.
  
    User suppliable parameters:
  
    "filename"         String        Defines the filename to use for the attached XML file. If not present the original filename is used.
    "label"            String        Defines the label to show with the link. If not present the original filename is used.
    "link-original"    (true|false)  Specifies whether the original document is linked instead of the processed document.
    "snippet-xpath"    String        Allows to select a specific node via XPath that is linked as document instead of everything.
*#
#set($node=$document)
#if(${link-original}) #set($node = $originalDocument) #end
#if(${snippet-xpath}) #set($node = $xpath.findNodes(${snippet-xpath}).get(0)) #end
  
#if (!$filename)
    #set($filename = $document.documentURI)
    #if($filename.contains("/"))
        #set($filename = $filename.substring($math.add($filename.lastIndexOf('/'), 1)))
    #end
#end
  
#set($href = $globals.attachContent($filename, $xpath.serialize($node)))
  
#if (!$label)
    #set($label = $href)
    #if($label.contains("/"))
        #set($label = $label.substring($math.add($label.lastIndexOf('/'), 1)))
    #end
#end
  
<document><body><a href="$href">$label</a></body></document>

XSD Link-List Template

The bundled template classpath:/templates/dim/xsd-linklist.xdoc.vm is the xdoc version of the usage example next to "schemaMap". Schema loading allows to download XML schemas and attach them to the document as link. (Attached content is stored next to the document to ensure it is static once the documentation was built)

Usage:

%{include|source=classpath:/templates/dim/xsd-linklist.xdoc.vm|source-xml=....|load-schema=local-only}

or, when external schemas should be downloaded and attached as well:

%{include|source=classpath:/templates/dim/xsd-linklist.xdoc.vm|source-xml=....|load-schema=true|attach-public=true}

Template Source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0"?>
#*
    Is a velocity template that creates an unordered list of links to all schema files that were loaded with XML loader.
  
    User suppliable parameters:
  
    "attach-public"    (true|false)  Toggles whether public schema locations are downloaded and attached or just linked.
*#
<document>
    <body>
        <ul>
#foreach($entry in $schemaMap.entrySet())
    #if($entry.key.startWith("http") && !${attach-public})
        #set($href=$entry.key)
    #else
        #set($href=$globals.attachContent($entry.key, $xpath.serialize($entry.value)))
    #end
            <li><a href="$href">
    #if($href.contains("/")) $href.substring($math.add($href.lastIndexOf('/'), 1)) #else $href #end</a></li>
#end
        </ul>
    </body>
</document>