You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by Christoph Reck <Ch...@dlr.de> on 2000/11/22 10:41:33 UTC
Re: velocity version of XSL
This sounds very interesting, I agree that XSL is not a pretty
templating language; up to now there was no real alternative and
it is a *real* standard - which does not mean it could be
replaced by something better.
Can I do something joining in?
I already wrote a context tool to load and handle XML/XSL, maybe some
of its methods can be re-used (see below). I had done the transformation
before with a template and XPath, but it looked really ugly :I (yes,
programming within a VL template should be avoided, this should
be placed in VM/VSL and control templates):
#set $xmlSpec = "AttributeValueDescriptor[AttributeId='$gipAttributeId']"
#set $xmlNodes = $xpath.selectNodeList($gipValids, $xmlSpec)
#if ( $xmlNodes )
<select name="$_gipAttributeId" size="1">
<option value="">Any
#set $loopCount = 0
#### would need a 'for'-loop here
#foreach ( $dummy in $Context.newArray($xmlNodes.Length) )
#set $xmlNode = $_mlNodes.item($_loopCount)
#set $value = $xpath.eval($xmlNode, "AttributeValue").toString()
#set $name = $xpath.eval($_xmlNode, "ShortName").toString()
<option value="$value"#if ($selected == $value) selected="1"#end>$name
#set $_loopCount = $Math.sum($_loopCount, 1)
#end
</select>
#end
So I went to XSL and desigend a way in XmlTool.xslt to automagically
populate the <xsl:param> within a XSL template with the corresponding
context variables - see XmlTool code below (velocimacros are clearly
a better solution). This is currently xalan_1.1, with xalan_1.2 it
is even cleaner to do.
I did like the feature that one can directly call static methods
(and instantiate java classes as extensions).
See how I used the ORO regexp and the Tokenizer.tokenize:
-------------------------- cut here -----------------------------
<!-- reformat abstract into text (multiline, fixed-space font) -->
<xsl:preserve-space elements="Abstract" />
<xsl:template match="Abstract">
<xsl:variable name="regexp"
select="java:org.apache.oro.text.perl.Perl5Util.new()"/>
<!-- add space to empty lines to render it after the EOL tokenizer -->
<xsl:variable name="text" select="java:substitute($regexp,
's/

/
 
/gs', string(text()))" />
<tt>
<xsl:for-each select=
"java:org.apache.xalan.xslt.extensions.Tokenizer.tokenize($text, '
')" >
<xsl:if test="position() > 1"><br /></xsl:if>
<!-- skip emitting empty lines -->
<xsl:if test="string(.) != ' '">
<!-- emit string after replacing spaces with nbsp's -->
<xsl:value-of
select="java:substitute($regexp, 's/ /  /g', string(.))" />
</xsl:if>
</xsl:for-each>
</tt>
</xsl:template>
-------------------------- cut here -----------------------------
For this reason I have placed a ClassTool into the context to
instantiate any class. This may be a security issue. In
turbine/velocity the controller would place the required
instances into the context... WM has a bug it cannot call a method
of a Class.forName() instance of a static class, so it requires
creating a real class instance (which is not possible if the
constructor is private...).
Here is a simple VL example how I used the XML/XSL tool:
-------------------------- cut here -----------------------------
## ------------------------------------------------------------------------
## File: templates/control/explain.vm
##
## Description: Controller to show details on an attribute.
##
## Input: QueryData: attributeId and attributeValue
## Loads the 'gipValids' using a #parse (possibly from cache)
##
## Output: Attribute help screen.
##
## Date: 2000-11-08
## Author: Christoph.Reck@dlr.de
## Copyright: (c) 2000 Deutsches Zentrum fuer Luft und Raumfahrt
## ------------------------------------------------------------------------
##
#set $page.Title = "GIP Attribute Descriptor"
##
## -------- import attribute valids (cached) --------
#parse ("control/include/gipValids.vm")
##
#set $attributeId = $data.Parameters.getString("AttributeId")
#set $attributeValue = $data.Parameters.getString("AttributeValue", "")
##
#set $_xslName = "/templates/xslt/explain.xsl" ### make dependant of ENV
#set $_xslFile = $data.ServletContext.getRealPath($_xslName)
#set $_xslDoc = $Xml.loadXSL($_xslFile);
##
## get it by processing the stylesheet
$Xml.format( $Xml.xslt($gipValids, $_xslDoc), 2, $indent)
-------------------------- cut here -----------------------------
This shows a simple way to cache things in the session:
-------------------------- cut here -----------------------------
## ------------------------------------------------------------------------
## File: templates/control/include/gipValids.vm
##
## Description: Loads the gipValids (caches it in the session).
##
## Input: file /export/GDS/GUA___.xml
##
## Output: $xpath (XPathAPI)
## $gipValids (DOM Tree) cached in session
##
## Date: 2000-11-08
## Author: Christoph.Reck@dlr.de
## Copyright: (c) 2000 Deutsches Zentrum fuer Luft und Raumfahrt
## ------------------------------------------------------------------------
##
#set $xpath = $Class.newInstance("org.apache.xpath.XPathAPI")
##
## ------------ import attribute valids -------------
## try getting the gipValids as cached within the session
#set $gipValids = $data.session.getAttribute("gipValids")
#if ( !$gipValids )
#set $xmlName = "/export/GDS/GUA___.xml" ### make dependant of ENV
#set $xmlFile = $data.ServletContext.getRealPath($xmlName)
## get DOM root
#set $gipValids = $Xml.loadXML($xmlFile).getDocumentElement()
## save in session
#set $dummy = $data.session.setAttribute("gipValids", $gipValids)
## cleanup
context (with Velocimacros this can be made obsolete!)
#set $dummy = $Context.remove( ["xmlName", "xmlFile"] )
#end
-------------------------- cut here -----------------------------
This is the XmlTool, specially loadXML(), xstl(), and format()
methods are interesting...
-------------------------- cut here -----------------------------
package de.dlr.dfd.naomi.turbine.util;
import java.io.*;
import java.util.Vector;
import org.apache.velocity.Context;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.apache.xpath.XPathAPI;
import org.apache.xerces.parsers.DOMParser;
import org.apache.xerces.dom.*;
import org.apache.xml.serialize.*;
import org.apache.xalan.xslt.*;
public class XmlTool
{
/** The context to extract XSLT parameters **/
protected Context context = null;
/** The indention used for formatting the output **/
protected int indent = 2;
/**
* Constructor needs a backpointer to the context.
*
* @param context A Context.
*/
public XmlTool(Context context)
{
this.context = context;
}
/**
* Set the default indentation for the formatting.
*
* @param indent The default indentation amount to use.
*/
public void setIndent(int indent)
{
this.indent = indent;
}
/**
* Get the default indentation for the formatting.
*
* @return The default indentation amount.
*/
public int getIndent()
{
return this.indent;
}
/**
* Format XML indented nicely. Uses the default
* indentation, and no indent offset.
*
* @param xml The XML node to pretty print.
* @return A string with the XML prettely formatted.
* @see #setIndent(int)
*/
public String format(Node xml)
{
return format(xml, indent, "");
}
/**
* Format XML indented nicely.
*
* @param xml The XML node to pretty print.
* @return A string with the XML prettely formatted.
*/
public String format(Node xml, int indent, String indentOffset)
{
OutputFormat fmt = new OutputFormat();
fmt.setIndent(indent);
fmt.setLineSeparator("\n" + indentOffset);
fmt.setOmitXMLDeclaration(true);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
HTMLSerializer serializer = new HTMLSerializer(buf, fmt);
try {
if (xml instanceof Element)
serializer.serialize( (Element) xml );
else if (xml instanceof Document)
serializer.serialize( ((Document) xml).getDocumentElement() );
else
serializer.serialize( xml.getOwnerDocument() );
} catch (Exception ex) {
// ignore
}
return buf.toString();
}
/**
* Load an XML document into a DOM tree.
*
* @param fileName The name of the file to load.
* @returns an XML document.
*/
public static Document loadXML(String fileName)
throws FileNotFoundException, IOException, SAXException
{
DOMParser parser = new DOMParser();
FileInputStream fileIn = new FileInputStream(fileName);
InputSource xmlIn = new InputSource(fileIn);
parser.parse(xmlIn);
return parser.getDocument();
}
/**
* Load an XML stylesheet.
*
* @param fileName The name of the file to load.
* @returns an XSLT Stylesheet.
*/
public static Stylesheet loadXSL(String fileName)
throws FileNotFoundException, SAXException
{
XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
FileInputStream fileIn = new FileInputStream(fileName);
XSLTInputSource xslIn = new XSLTInputSource(fileIn);
return processor.processStylesheet(xslIn);
}
/**
* Transform an XML document using XSLT.
*
* @param xml The XML node to transform.
* @param xsl The XSLT Stylesheet used for the transform.
* @returns The transformed XML document.
*/
public Document xslt(Node xml, Stylesheet xsl)
throws SAXException
{
// create the input
XSLTInputSource xmlIn = new XSLTInputSource(xml);
XSLTInputSource xslIn = new XSLTInputSource(xsl);
// create the output
Document outDoc = new DocumentImpl();
XSLTResultTarget xmlOut = new XSLTResultTarget(outDoc);
// get the processor
XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
Vector params = xsl.getTopLevelVariables();
for(int i = 0; i < params.size(); i++)
{
ElemVariable param = (ElemVariable)params.elementAt(i);
// extract value from context
String name = param.m_qname.m_localpart; //### change for xalan 2.0
Object value = context.get(name);
if (value != null)
processor.setStylesheetParam(name, "'" + value.toString() + "'");
//## processor.setStylesheetParam(name, processor.createXString(value));
}
// do the actual transformation
processor.process(xmlIn, xslIn, xmlOut);
return outDoc;
}
/**
* Transform an XML files using XSLT.
* @param xmlFileName The name of the XML file to transform
* @param xslFileName The name of the XSLT file used for the transformation.
* @param indentOffset The initial indentation.
*/
public String xslt(String xmlFileName,
String xslFileName,
String indentOffset)
throws FileNotFoundException, IOException, SAXException
{
Document xml = loadXML(xmlFileName);
Stylesheet xsl = loadXSL(xslFileName);
return format( xslt(xml, xsl), indent, indentOffset );
}
} // end of XmlTool.java
-------------------------- cut here -----------------------------
:)
Christoph