This example shows the usage of Xpath and Velocity. It permits the usage of XPath in foreach directives.
This sample has a dependency to Saxon. Libraries used:
Run the test.Sample class.
File: test.v
package ${packageName}; public class My${xpath.run("xs:string(//package/class/@name)",$mydoc)} { public My${xpath.run("xs:string(//package/class/@name)",$mydoc)}() { #foreach($field in $xpath.iterator("//package/class/field",$mydoc)) this.${xpath.run("xs:string(//field/@name)",$field)} = "1"; #end } } |
File: test.Sample
package test; import java.io.StringWriter; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; public class Sample { public String generate(String templateFile,String rawDoc) throws Exception { VelocityEngine engine = new VelocityEngine(); Template t = engine.getTemplate(templateFile); VelocityContext context = new VelocityContext(); context.put("mydoc", rawDoc); context.put("xpath", new XPathHandler()); context.put("packageName", "org.test"); StringWriter wr = new StringWriter(); t.merge(context, wr); return wr.getBuffer().toString(); } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { String templateFile = "test.v"; String rawDoc = "<package><class name=\"Director\"><field name=\"test1\"/></class></package>"; System.out.println(new Sample().generate(templateFile, rawDoc)); } } |
File: test.XPathHandler
package test; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Properties; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import net.sf.saxon.Configuration; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.query.DynamicQueryContext; import net.sf.saxon.query.StaticQueryContext; import net.sf.saxon.query.XQueryExpression; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; public class XPathHandler { /** * Run a Xpath query using Saxon * @param xpath * @param doc either an instance of {@link Element} or a raw xml {@link String}. * @return */ public String run(String xpath, Object doc) { try { Configuration config = new Configuration(); StaticQueryContext staticContext = new StaticQueryContext(config); StringReader reader = new StringReader(xpath); XQueryExpression exp = staticContext.compileQuery(reader); DynamicQueryContext dynamicContext = new DynamicQueryContext(config); if( doc instanceof String ) { DocumentInfo d = staticContext.buildDocument(new StreamSource(new StringReader((String)doc))).getDocumentRoot(); dynamicContext.setContextNode(d); } else if( doc instanceof Element) { DOMSource domSource = new DOMSource((Element)doc); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "xml"); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.setOutputProperties(props); transformer.transform(domSource, result); DocumentInfo d = staticContext.buildDocument(new StreamSource(new StringReader(writer.toString()))).getDocumentRoot(); dynamicContext.setContextNode(d); } else { return null; } Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "text"); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); props.setProperty(OutputKeys.STANDALONE, "yes"); StringWriter wr = new StringWriter(); exp.run(dynamicContext,new StreamResult(wr), props); return wr.getBuffer().toString(); } catch (Exception e) { throw new RuntimeException(e); } } /** * Run a xpath and return a collection of elements * @param xpath * @param rawdoc * @return Collection of {@link Element} elements */ public Collection iterator(String xpath, String rawdoc) { try { Configuration config = new Configuration(); StaticQueryContext staticContext = new StaticQueryContext(config); StringReader reader = new StringReader(xpath); XQueryExpression exp = staticContext.compileQuery(reader); DynamicQueryContext dynamicContext = new DynamicQueryContext(config); DocumentInfo doc = staticContext.buildDocument(new StreamSource(new StringReader(rawdoc))).getDocumentRoot(); Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "xml"); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); dynamicContext.setContextNode(doc); StringWriter wr = new StringWriter(); exp.run(dynamicContext,new StreamResult(wr), props); String xml ="<root>"+wr.getBuffer().toString()+"</root>"; //wraps in a root element, for getting a list of elements later DocumentBuilderFactory dom = javax.xml.parsers.DocumentBuilderFactory.newInstance(); Document document = dom.newDocumentBuilder().parse(new InputSource(new StringReader(xml))); return new NodeListWrapper(document.getDocumentElement().getChildNodes()); } catch (Throwable e) { throw new RuntimeException(e); } } /** * Wraps a NodeList within an ArrayList. only accepts {@link Element} as elements */ public static class NodeListWrapper extends ArrayList { public NodeListWrapper(NodeList si) { try { for(int i=0; i<si.getLength(); i++) { if( si.item(i) instanceof Element) { add(si.item(i)); } } } catch (Exception e) { //ignore } } } } |