Hi, folks. Is anybody interested in these tasks? Or did I do something wrong? Please someone give me some comments? -- )Hiroaki Nakamura) hnakamur@v003.vaio.ne.jp ----- Original Message ----- From: "Hiroaki Nakamura" To: "Ant Developers List" Sent: Thursday, January 30, 2003 12:10 PM Subject: [Proposal] ReadXML, XPathSingle, XPathForEach Task > Kirk, > Sorry for my very late response, but shortly after using VPP I came to like > your idea using XPath. However, I don't need jakarta-digester here personally, > I think just DOM and XPath are enough. For XPath, Xalan's XPathAPI is very handy. > > Kirk, Christopher wrote: > > 1) I have found the real power of Ant+Velocity comes out when Ant is used to > > load an XML file (that forms the velocity context) and then a set of XPath > > mappers that specify when Velocity is to be fired and what file is to be > > generated. > > So I made a sample program for proof of concept. Please see an attached patch. > - First you provide your configuration as a separate xml file, > like config.xml in the patch. > - You read the xml with , and add the DOM node (newly defined > datatype) to a reference in the ant project (see "init_config" target). > - You can reference a node dom value and set to a property by using > with property attribute (see "xpathsingle_example1" target). > - You can add a reference by using with node attribute > (see "xpathsingle_example2" target). > - You can loop on nodes by using with node attribute > (see "xpathforeach_example1" target). > - You can loop on node values by using with property attribute > (see "xpathforeach_example2" target). > - "xpathforeach_example3" target is a real life example. It loops on nodes and > for each loop it calls a task using VPP which references the node value by > using sample.velocity.XPathTool. > > > > > > > > > > > > - Also, please see "wrong_example1" and "wrong_example2". It prints the > same value as the first iteration for each iteration. So you must use > in the loopbody like "xpathforeach_example1". > > Usage: > (1) run ant > (2) run ant test > You must run (2) separately since (1) puts a jar file to ant lib directory. > > So, what do you all people think about these tasks? I think these are good > and welcome your feedbacks. > > -- > )Hiroaki Nakamura) hnakamur@v003.vaio.ne.jp > > > diff -ruN XPathForEachSample.orig/application.xml.vpp XPathForEachSample/application.xml.vpp > --- XPathForEachSample.orig/application.xml.vpp 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/application.xml.vpp 2003-01-30 09:52:20.000000000 +0900 > @@ -0,0 +1,23 @@ > + > +#set($ear = $project.getReference('ear').getNode()) > + > + + "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" > + "http://java.sun.com/dtd/application_1_3.dtd"> > + > + > + $xp.value($ear, '@name') > +#foreach($w in $xp.list($ear, 'war')) > + > + > + $xp.value($w, '@filename') > + $xp.value($w, '@context_root') > + > + > +#end > +#foreach($e in $xp.list($ear, 'ejb')) > + > + $xp.value($e, '@filename') > + > +#end > + > diff -ruN XPathForEachSample.orig/build.xml XPathForEachSample/build.xml > --- XPathForEachSample.orig/build.xml 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/build.xml 2003-01-30 11:30:06.000000000 +0900 > @@ -0,0 +1,134 @@ > + > + > + > + > + > + > + > + + destdir="classes" > + debug="true" > + deprecation="true" > + optimize="true" > > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + + property="earname"/> > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + + context="dom1" path="build_config/ears/ear/@name"> > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + + context="dom1" path="build_config/ears/ear/@name"> > + > + > + > + > + > + + description="Creates destdir even if srcdir doesn't exist."/> > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + + context="dom1" path="build_config/ears/ear/@name"> > + > + > + > + > + > + > + > + > + > + > + > diff -ruN XPathForEachSample.orig/config.xml XPathForEachSample/config.xml > --- XPathForEachSample.orig/config.xml 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/config.xml 2003-01-30 07:18:21.000000000 +0900 > @@ -0,0 +1,20 @@ > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > diff -ruN XPathForEachSample.orig/src/sample/ant/taskdefs/ReadXML.java XPathForEachSample/src/sample/ant/taskdefs/ReadXML.java > --- XPathForEachSample.orig/src/sample/ant/taskdefs/ReadXML.java 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/src/sample/ant/taskdefs/ReadXML.java 2003-01-30 11:07:39.000000000 +0900 > @@ -0,0 +1,59 @@ > +package sample.ant.taskdefs; > + > +import java.io.File; > +import java.io.IOException; > + > +import javax.xml.parsers.DocumentBuilder; > +import javax.xml.parsers.DocumentBuilderFactory; > +import javax.xml.parsers.ParserConfigurationException; > + > +import org.apache.tools.ant.BuildException; > +import org.apache.tools.ant.Project; > +import org.apache.tools.ant.Task; > +import sample.ant.types.DOMNode; > +import org.w3c.dom.Document; > +import org.xml.sax.SAXException; > + > +/** > + * > + */ > +public class ReadXML extends Task { > + protected String domID; > + protected File file; > + > + public void setDomID(String domID) { > + this.domID = domID; > + } > + > + public void setFile(File file) { > + this.file = file; > + } > + > + /** > + * @see org.apache.tools.ant.Task#execute() > + */ > + public void execute() throws BuildException { > + Project prj = getProject(); > + DOMNode dom = (DOMNode)prj.createDataType("domnode"); > + Document doc = parseXML(file); > + dom.setNode(doc); > + prj.addReference(domID, dom); > + } > + > + protected Document parseXML(File file) throws BuildException { > + Document doc = null; > + try { > + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); > + DocumentBuilder db = dbf.newDocumentBuilder(); > + doc = db.parse(file); > + } catch (ParserConfigurationException ex) { > + throw new BuildException(ex); > + } catch (IOException ex) { > + throw new BuildException(ex); > + } catch (SAXException ex) { > + throw new BuildException(ex); > + } > + return doc; > + } > + > +} > diff -ruN XPathForEachSample.orig/src/sample/ant/taskdefs/XPathForEach.java > XPathForEachSample/src/sample/ant/taskdefs/XPathForEach.java > --- XPathForEachSample.orig/src/sample/ant/taskdefs/XPathForEach.java 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/src/sample/ant/taskdefs/XPathForEach.java 2003-01-30 10:49:20.000000000 +0900 > @@ -0,0 +1,145 @@ > +package sample.ant.taskdefs; > + > +import java.util.Enumeration; > +import java.util.Vector; > + > +import org.apache.tools.ant.BuildException; > +import org.apache.tools.ant.Project; > +import org.apache.tools.ant.Task; > +import org.apache.tools.ant.TaskContainer; > +import sample.ant.types.DOMNode; > +import sample.ant.util.XPathUtils; > +import org.w3c.dom.Node; > +import org.w3c.dom.traversal.NodeIterator; > + > +/** > + * > + */ > +public class XPathForEach extends Task implements TaskContainer { > + protected String node; > + protected String property; > + protected String context; > + protected String path; > + > + /** Optional Vector holding the nested tasks */ > + private Vector nestedTasks = new Vector(); > + > + /** > + * Sets the node. > + * @param node The node to set > + */ > + public void setNode(String node) { > + this.node = node; > + } > + > + /** > + * Sets the property. > + * @param property The property to set > + */ > + public void setProperty(String property) { > + this.property = property; > + } > + > + /** > + * Sets the context. > + * @param context The context to set > + */ > + public void setContext(String context) { > + this.context = context; > + } > + > + /** > + * Sets the path. > + * @param path The path to set > + */ > + public void setPath(String path) { > + this.path = path; > + } > + > + /** > + * Override {@link org.apache.tools.ant.Task#maybeConfigure > + * maybeConfigure} in a way that leaves the nested tasks > + * unconfigured until they get executed. > + * > + * @since Ant 1.5 > + */ > + public void maybeConfigure() throws BuildException { > + if (isInvalid()) { > + super.maybeConfigure(); > + } else { > + getRuntimeConfigurableWrapper().maybeConfigure(getProject(), false); > + } > + } > + > + /** > + * Add a nested task to Sequential. > + *

> + * @param nestedTask Nested task to execute Sequential > + *

> + */ > + public void addTask(Task nestedTask) { > + nestedTasks.addElement(nestedTask); > + } > + > + /** > + * Execute all nestedTasks. > + */ > + public void execute() throws BuildException { > + if (context == null) { > + throw new BuildException("context node must be set"); > + } > + if (path == null) { > + throw new BuildException("path must be set"); > + } > + if (property == null && node == null) { > + throw new BuildException("one of property or node must be set"); > + } > + if (property != null && node != null) { > + throw new BuildException("property and node must not be both set"); > + } > + > + Project prj = getProject(); > + Object savedNodeRef = null; > + if (node != null) { > + savedNodeRef = prj.getReference(node); > + } > + try { > + DOMNode contextDOMNode = (DOMNode)prj.getReference(context); > + if (contextDOMNode == null) { > + throw new BuildException("context node [" + context + "] does not exist."); > + } > + Node contextNode = contextDOMNode.getNode(); > + > + NodeIterator it = XPathUtils.selectNodeIterator(contextNode, path); > + Node n = null; > + while ((n = it.nextNode()) != null) { > + if (node != null) { > + addNewDOMNodeReference(prj, node, n); > + } else if (property != null) { > + prj.setProperty(property, n.getNodeValue()); > + } > + > + performNestedTasks(); > + } > + } finally { > + if (savedNodeRef != null) { > + prj.addReference(node, savedNodeRef); > + } > + } > + } > + > + protected DOMNode addNewDOMNodeReference(Project prj, String id, Node n) { > + DOMNode nDomNode = (DOMNode)prj.createDataType("domnode"); > + nDomNode.setNode(n); > + prj.addReference(id, nDomNode); > + return nDomNode; > + } > + > + protected void performNestedTasks() > + throws BuildException { > + for (Enumeration e = nestedTasks.elements(); e.hasMoreElements();) { > + Task nestedTask = (Task) e.nextElement(); > + nestedTask.perform(); > + } > + } > +} > diff -ruN XPathForEachSample.orig/src/sample/ant/taskdefs/XPathSingle.java > XPathForEachSample/src/sample/ant/taskdefs/XPathSingle.java > --- XPathForEachSample.orig/src/sample/ant/taskdefs/XPathSingle.java 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/src/sample/ant/taskdefs/XPathSingle.java 2003-01-30 10:49:20.000000000 +0900 > @@ -0,0 +1,92 @@ > +package sample.ant.taskdefs; > + > +import org.apache.tools.ant.BuildException; > +import org.apache.tools.ant.Project; > +import org.apache.tools.ant.Task; > +import sample.ant.types.DOMNode; > +import sample.ant.util.XPathUtils; > +import org.w3c.dom.Node; > + > +/** > + * > + */ > +public class XPathSingle extends Task { > + protected String node; > + protected String property; > + protected String context; > + protected String path; > + > + /** > + * Sets the node. > + * @param node The node to set > + */ > + public void setNode(String node) { > + this.node = node; > + } > + > + /** > + * Sets the property. > + * @param property The property to set > + */ > + public void setProperty(String property) { > + this.property = property; > + } > + > + /** > + * Sets the context. > + * @param context The context to set > + */ > + public void setContext(String context) { > + this.context = context; > + } > + > + /** > + * Sets the path. > + * @param path The path to set > + */ > + public void setPath(String path) { > + this.path = path; > + } > + > + /** > + * @see org.apache.tools.ant.Task#execute() > + */ > + public void execute() throws BuildException { > + if (context == null) { > + throw new BuildException("context node must be set"); > + } > + if (path == null) { > + throw new BuildException("path must be set"); > + } > + if (property == null && node == null) { > + throw new BuildException("one of property or node must be set"); > + } > + if (property != null && node != null) { > + throw new BuildException("property and node must not be both set"); > + } > + > + Project prj = getProject(); > + DOMNode contextDOMNode = (DOMNode)prj.getReference(context); > + if (contextDOMNode == null) { > + throw new BuildException("context node [" + context + "] does not exist."); > + } > + Node contextNode = contextDOMNode.getNode(); > + Node n = XPathUtils.selectSingleNode(contextNode, path); > + if (n == null) { > + throw new BuildException("exaclty one node must be selected by xpath"); > + } > + > + if (node != null) { > + addNewDOMNodeReference(prj, node, n); > + } else if (property != null) { > + prj.setProperty(property, n.getNodeValue()); > + } > + } > + > + protected DOMNode addNewDOMNodeReference(Project prj, String id, Node n) { > + DOMNode nDomNode = (DOMNode)prj.createDataType("domnode"); > + nDomNode.setNode(n); > + prj.addReference(id, nDomNode); > + return nDomNode; > + } > +} > diff -ruN XPathForEachSample.orig/src/sample/ant/types/DOMNode.java XPathForEachSample/src/sample/ant/types/DOMNode.java > --- XPathForEachSample.orig/src/sample/ant/types/DOMNode.java 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/src/sample/ant/types/DOMNode.java 2003-01-30 10:49:48.000000000 +0900 > @@ -0,0 +1,16 @@ > +package sample.ant.types; > + > +import org.apache.tools.ant.types.DataType; > +import org.w3c.dom.Node; > + > +public class DOMNode extends DataType { > + protected Node node; > + > + public void setNode(Node node) { > + this.node = node; > + } > + > + public Node getNode() { > + return node; > + } > +} > diff -ruN XPathForEachSample.orig/src/sample/ant/util/XPathUtils.java XPathForEachSample/src/sample/ant/util/XPathUtils.java > --- XPathForEachSample.orig/src/sample/ant/util/XPathUtils.java 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/src/sample/ant/util/XPathUtils.java 2003-01-30 10:48:49.000000000 +0900 > @@ -0,0 +1,32 @@ > +package sample.ant.util; > + > +import javax.xml.transform.TransformerException; > + > +import org.apache.tools.ant.BuildException; > +import org.apache.xpath.XPathAPI; > +import org.w3c.dom.Node; > +import org.w3c.dom.traversal.NodeIterator; > + > +/** > + * > + */ > +public class XPathUtils { > + public static Node selectSingleNode(Node contextNode, String path) > + throws BuildException { > + try { > + return XPathAPI.selectSingleNode(contextNode, path); > + } catch (TransformerException ex) { > + throw new BuildException(ex); > + } > + } > + > + public static NodeIterator selectNodeIterator(Node contextNode, String path) > + throws BuildException { > + try { > + return XPathAPI.selectNodeIterator(contextNode, path); > + } catch (TransformerException ex) { > + throw new BuildException(ex); > + } > + } > + > +} > diff -ruN XPathForEachSample.orig/src/sample/velocity/XPathTool.java XPathForEachSample/src/sample/velocity/XPathTool.java > --- XPathForEachSample.orig/src/sample/velocity/XPathTool.java 1970-01-01 09:00:00.000000000 +0900 > +++ XPathForEachSample/src/sample/velocity/XPathTool.java 2003-01-30 10:48:29.000000000 +0900 > @@ -0,0 +1,251 @@ > +package sample.velocity; > + > +import java.util.ArrayList; > +import java.util.Iterator; > +import java.util.List; > + > +import javax.xml.transform.TransformerException; > + > +import org.apache.xml.utils.PrefixResolver; > +import org.apache.xpath.XPathAPI; > +import org.apache.xpath.objects.XObject; > +import org.w3c.dom.Node; > +import org.w3c.dom.NodeList; > +import org.w3c.dom.traversal.NodeIterator; > + > +/** > + * > + */ > +public class XPathTool { > + public XPathTool() { > + } > + > + public String value(Node contextNode, String str) > + throws TransformerException { > + Node n = node(contextNode, str); > + return n == null ? null : n.getNodeValue(); > + } > + > + public String value(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + Node n = node(contextNode, str, namespaceNode); > + return n == null ? null : n.getNodeValue(); > + } > + > + /** > + * Use an XPath string to select a single node. XPath namespace > + * prefixes are resolved from the context node, which may not > + * be what you want (see the next method). > + * > + * @param str A valid XPath string. > + * @return The first node found that matches the XPath, or null. > + * > + * @throws TransformerException > + */ > + public Node node(Node contextNode, String str) > + throws TransformerException { > + return XPathAPI.selectSingleNode(contextNode, str); > + } > + > + /** > + * Use an XPath string to select a single node. XPath namespace > + * prefixes are resolved from the context node, which may not > + * be what you want (see the next method). > + * > + * @param str A valid XPath string. > + * @return The first node found that matches the XPath, or null. > + * > + * @throws TransformerException > + */ > + public Node node(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + return XPathAPI.selectSingleNode(contextNode, str, namespaceNode); > + } > + > + public Iterator iter(Node contextNode, String str) > + throws TransformerException { > + return asIterator(nodeIter(contextNode, str)); > + } > + > + public Iterator iter(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + return asIterator(nodeIter(contextNode, str, namespaceNode)); > + } > + > + /** > + * Use an XPath string to select a nodelist. > + * XPath namespace prefixes are resolved from the contextNode. > + * > + * @param str A valid XPath string. > + * @return A NodeIterator, should never be null. > + * > + * @throws TransformerException > + */ > + public NodeIterator nodeIter(Node contextNode, String str) > + throws TransformerException { > + return XPathAPI.selectNodeIterator(contextNode, str); > + } > + > + /** > + * Use an XPath string to select a nodelist. > + * XPath namespace prefixes are resolved from the contextNode. > + * > + * @param str A valid XPath string. > + * @return A NodeIterator, should never be null. > + * > + * @throws TransformerException > + */ > + public NodeIterator nodeIter(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + return XPathAPI.selectNodeIterator(contextNode, str, namespaceNode); > + } > + > + public List list(Node contextNode, String str) > + throws TransformerException { > + return asList(nodeList(contextNode, str)); > + } > + > + public List list(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + return asList(nodeList(contextNode, str, namespaceNode)); > + } > + > + /** > + * Use an XPath string to select a nodelist. > + * XPath namespace prefixes are resolved from the contextNode. > + * > + * @param str A valid XPath string. > + * @return A NodeIterator, should never be null. > + * > + * @throws TransformerException > + */ > + public NodeList nodeList(Node contextNode, String str) > + throws TransformerException { > + return XPathAPI.selectNodeList(contextNode, str); > + } > + > + /** > + * Use an XPath string to select a nodelist. > + * XPath namespace prefixes are resolved from the contextNode. > + * > + * @param str A valid XPath string. > + * @return A NodeIterator, should never be null. > + * > + * @throws TransformerException > + */ > + public NodeList nodeList(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + return XPathAPI.selectNodeList(contextNode, str, namespaceNode); > + } > + > + /** > + * Evaluate XPath string to an XObject. Using this method, > + * XPath namespace prefixes will be resolved from the namespaceNode. > + * @param str A valid XPath string. > + * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null. > + * @see org.apache.xpath.objects.XObject > + * @see org.apache.xpath.objects.XNull > + * @see org.apache.xpath.objects.XBoolean > + * @see org.apache.xpath.objects.XNumber > + * @see org.apache.xpath.objects.XString > + * @see org.apache.xpath.objects.XRTreeFrag > + * > + * @throws TransformerException > + */ > + public XObject eval(Node contextNode, String str) > + throws TransformerException { > + return XPathAPI.eval(contextNode, str); > + } > + > + /** > + * Evaluate XPath string to an XObject. Using this method, > + * XPath namespace prefixes will be resolved from the namespaceNode. > + * @param str A valid XPath string. > + * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null. > + * @see org.apache.xpath.objects.XObject > + * @see org.apache.xpath.objects.XNull > + * @see org.apache.xpath.objects.XBoolean > + * @see org.apache.xpath.objects.XNumber > + * @see org.apache.xpath.objects.XString > + * @see org.apache.xpath.objects.XRTreeFrag > + * > + * @throws TransformerException > + */ > + public XObject eval(Node contextNode, String str, Node namespaceNode) > + throws TransformerException { > + return XPathAPI.eval(contextNode, str, namespaceNode); > + } > + > + /** > + * Evaluate XPath string to an XObject. > + * XPath namespace prefixes are resolved from the namespaceNode. > + * The implementation of this is a little slow, since it creates > + * a number of objects each time it is called. This could be optimized > + * to keep the same objects around, but then thread-safety issues would arise. > + * > + * @param contextNode The node to start searching from. > + * @param str A valid XPath string. > + * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. > + * @param prefixResolver Will be called if the parser encounters namespace > + * prefixes, to resolve the prefixes to URLs. > + * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null. > + * @see org.apache.xpath.objects.XObject > + * @see org.apache.xpath.objects.XNull > + * @see org.apache.xpath.objects.XBoolean > + * @see org.apache.xpath.objects.XNumber > + * @see org.apache.xpath.objects.XString > + * @see org.apache.xpath.objects.XRTreeFrag > + * > + * @throws TransformerException > + */ > + public XObject eval( > + Node contextNode, > + String str, > + PrefixResolver prefixResolver) > + throws TransformerException { > + return XPathAPI.eval(contextNode, str, prefixResolver); > + } > + > + > + protected Iterator asIterator(NodeIterator nit) { > +// List list = new ArrayList(); > +// Node n = null; > +// while ((n = nit.nextNode()) != null) { > +// list.add(n); > +// } > +// return list.iterator(); > + final NodeIterator fnit = nit; > + return new Iterator() { > + protected Object savedNext; > + > + public boolean hasNext() { > + if (savedNext == null) { > + savedNext = fnit.nextNode(); > + } > + return savedNext != null; > + } > + public Object next() { > + if (savedNext == null) { > + return fnit.nextNode(); > + } else { > + Object n = savedNext; > + savedNext = null; > + return n; > + } > + } > + public void remove() { > + throw new UnsupportedOperationException(); > + } > + }; > + } > + > + protected List asList(NodeList nl) { > + int len = nl.getLength(); > + List list = new ArrayList(len); > + for (int i = 0; i < len; i++) { > + list.add(nl.item(i)); > + } > + return list; > + } > + > +} > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: ant-dev-unsubscribe@jakarta.apache.org > For additional commands, e-mail: ant-dev-help@jakarta.apache.org > > >