ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Hiroaki Nakamura" <hnaka...@v003.vaio.ne.jp>
Subject [Proposal] ReadXML, XPathSingle, XPathForEach Task
Date Thu, 30 Jan 2003 03:10:50 GMT
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 <readxml>, and add the DOM node (newly defined
  <domnode> 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
  <xpathsingle> with property attribute (see "xpathsingle_example1" target).
- You can add a reference by using <xpathsingle> with node attribute
   (see "xpathsingle_example2" target).
- You can loop on nodes by using <xpathforeach> with node attribute
   (see "xpathforeach_example1" target).
- You can loop on node values by using <xpathforeach> 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.

   <target name="xpathforeach_example3">
     <xpathforeach node="ear" context="dom1" path="build_config/ears/ear">
       <xpathsingle context="ear" path="@name" property="destdir"/>
       <antcall target="vpp" inheritRefs="true">
         <param name="srcdir" value="."/>
         <param name="destdir" value="${destdir}"/>
       </antcall>
     </xpathforeach>
   </target>

- Also, please see "wrong_example1" and "wrong_example2". It prints the
  same value as the first iteration for each iteration. So you must use
  <antcall> 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+#set($ear = $project.getReference('ear').getNode())
+
+<!DOCTYPE application PUBLIC
+    "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN"
+    "http://java.sun.com/dtd/application_1_3.dtd">
+
+<application>
+  <display-name>$xp.value($ear, '@name')</display-name>
+#foreach($w in $xp.list($ear, 'war'))
+  <module>
+    <web>
+      <web-uri>$xp.value($w, '@filename')</web-uri>
+      <context-root>$xp.value($w, '@context_root')</context-root>
+    </web>
+  </module>
+#end
+#foreach($e in $xp.list($ear, 'ejb'))
+  <module>
+    <ejb>$xp.value($e, '@filename')</ejb>
+  </module>
+#end
+</application>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="XPathForEachSample" default="deploy" basedir=".">
+  <property name="ANT_HOME" value="C:/jakarta-ant-1.5.1"/>
+
+  <target name="compile">
+    <mkdir dir="classes"/>
+    <javac srcdir="src"
+           destdir="classes"
+           debug="true"
+           deprecation="true"
+           optimize="true" >
+      <classpath>
+        <pathelement location="${ANT_HOME}/lib/ant.jar"/>
+      </classpath>
+    </javac>
+  </target>
+
+  <target name="build" depends="compile">
+    <jar jarfile="mysample.jar" basedir="classes"/>
+  </target>
+
+  <target name="deploy" depends="build">
+    <copy file="mysample.jar" todir="${ANT_HOME}/lib"/>
+  </target>
+
+  <target name="init_config">
+    <typedef name="domnode"      classname="sample.ant.types.DOMNode"/>
+
+    <taskdef name="readxml"      classname="sample.ant.taskdefs.ReadXML"/>
+    <taskdef name="xpathsingle"  classname="sample.ant.taskdefs.XPathSingle"/>
+    <taskdef name="xpathforeach" classname="sample.ant.taskdefs.XPathForEach"/>
+
+    <readxml domid="dom1" file="config.xml"/>
+  </target>
+
+  <target name="test" depends="init_config">
+    <antcall target="xpathsingle_example1" inheritRefs="true"/>
+    <antcall target="xpathsingle_example2" inheritRefs="true"/>
+    <antcall target="xpathforeach_example1" inheritRefs="true"/>
+    <antcall target="xpathforeach_example2" inheritRefs="true"/>
+    <antcall target="xpathforeach_example3" inheritRefs="true"/>
+    <antcall target="wrong_example1" inheritRefs="true"/>
+    <antcall target="wrong_example2" inheritRefs="true"/>
+  </target>
+
+  <target name="xpathsingle_example1">
+    <xpathsingle context="dom1" path="build_config/ears/ear[1]/@name"
+        property="earname"/>
+    <echo message="earname=${earname}"/>
+  </target>
+
+  <target name="xpathsingle_example2">
+    <xpathsingle context="dom1" path="build_config/ears/ear[2]" node="ear"/>
+    <xpathsingle context="ear" path="@name" property="earname"/>
+    <echo message="earname=${earname}"/>
+  </target>
+
+  <target name="xpathforeach_example1">
+    <xpathforeach node="ear" context="dom1" path="build_config/ears/ear">
+      <xpathsingle context="ear" path="@name" property="earname"/>
+      <antcall target="echo_earname"/>
+    </xpathforeach>
+  </target>
+
+  <target name="echo_earname">
+    <echo message="earname=${earname}"/>
+  </target>
+
+  <target name="xpathforeach_example2">
+    <xpathforeach property="earname"
+        context="dom1" path="build_config/ears/ear/@name">
+      <antcall target="echo_earname"/>
+    </xpathforeach>
+  </target>
+
+  <target name="xpathforeach_example3">
+    <xpathforeach node="ear" context="dom1" path="build_config/ears/ear">
+      <xpathsingle context="ear" path="@name" property="destdir"/>
+      <antcall target="vpp" inheritRefs="true">
+        <param name="srcdir" value="."/>
+        <param name="destdir" value="${destdir}"/>
+      </antcall>
+    </xpathforeach>
+  </target>
+
+  <target name="wrong_example1">
+    <xpathforeach node="ear" context="dom1" path="build_config/ears/ear">
+      <xpathsingle context="ear" path="@name" property="earname"/>
+      <echo message="unchanged_over_iteration -> ${earname}"/>
+    </xpathforeach>
+  </target>
+
+  <target name="wrong_example2">
+   <xpathforeach property="earname"
+       context="dom1" path="build_config/ears/ear/@name">
+     <echo message="unchanged_over_iteration -> ${earname}"/>
+   </xpathforeach>
+  </target>
+
+  <target name="vpp">
+    <mkdir dir="${destdir}"
+        description="Creates destdir even if srcdir doesn't exist."/>
+    <available property="vpp_srcdir_exists" file="${srcdir}" type="dir"/>
+    <antcall target="vpp_helper" inheritRefs="true"/>
+  </target>
+  <target name="vpp_helper" if="vpp_srcdir_exists">
+    <mkdir dir="${destdir}"/>
+    <copy todir="${destdir}">
+      <fileset dir="${srcdir}" includes="**/*.vpp"/>
+      <mapper type="glob" from="*.vpp" to="*"/>
+      <filterchain>
+        <filterreader classname="foundrylogic.vpp.VPPFilter">
+          <param type="engine" name="runtime.log" value="vpp.log"/>
+          <param type="class" name="xp" value="sample.velocity.XPathTool"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="clean" depends="init_config">
+    <xpathforeach property="earname"
+        context="dom1" path="build_config/ears/ear/@name">
+      <antcall target="delete_ear_dir"/>
+    </xpathforeach>
+    <delete file="vpp.log"/>
+    <delete file="mysample.jar"/>
+    <delete dir="classes"/>
+  </target>
+
+  <target name="delete_ear_dir">
+    <delete dir="${earname}"/>
+  </target>
+</project>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<build_config>
+  <ears>
+    <ear name="ear1" filename="ear1.ear">
+      <war name="war1" filename="war1.war" context_root="/war1"/>
+      <war name="war2" filename="war2.war" context_root="/war2"/>
+      <ejb name="ejb1" filename="ejb1.jar"/>
+      <ejb name="ejb2" filename="ejb2.jar"/>
+      <ejb name="ejb3" filename="ejb3.jar"/>
+    </ear>
+    <ear name="ear2" filename="ear2.ear">
+      <war name="war2" filename="war2.war" context_root="/war2"/>
+      <war name="war3" filename="war3.war" context_root="/war3"/>
+      <ejb name="ejb1" filename="ejb1.jar"/>
+      <ejb name="ejb2" filename="ejb2.jar"/>
+      <ejb name="ejb4" filename="ejb4.jar"/>
+    </ear>
+  </ears>
+</build_config>
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.
+     * <p>
+     * @param nestedTask  Nested task to execute Sequential
+     * <p>
+     */
+    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


Mime
View raw message