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) [EMAIL PROTECTED]
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 [EMAIL PROTECTED] 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]