[Practicalxml-commits] SF.net SVN: practicalxml:[52] trunk/src
Brought to you by:
kdgregory
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-14 17:07:49
|
Revision: 52
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=52&view=rev
Author: kdgregory
Date: 2008-12-14 17:07:45 +0000 (Sun, 14 Dec 2008)
Log Message:
-----------
DomUtil: add variant of getAbsolutePath() that takes NamespaceResolver (so path can be used)
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/DomUtil.java
trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
Added Paths:
-----------
trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java
Modified: trunk/src/main/java/net/sf/practicalxml/DomUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-14 15:15:44 UTC (rev 51)
+++ trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-14 17:07:45 UTC (rev 52)
@@ -13,6 +13,8 @@
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+import net.sf.practicalxml.misc.NamespaceResolver;
+
import org.apache.commons.lang.StringUtils;
@@ -439,9 +441,9 @@
/**
* Returns the path from the root of the document to the specified
- * element, consisting of each node's nodename separated by slashes.
- * Accepts an arbitrary number of attribute names, and inserts these
- * as predicates into the path nodes where they apply.
+ * element, consisting of each node's qualified name, separated by
+ * slashes. Accepts an arbitrary number of attribute names, and
+ * inserts these as predicates into the path nodes where they apply.
* <p>
* This method is meant primarily for logging and debugging. While the
* returned path can by passed to an XPath evaluator, it has several
@@ -449,8 +451,10 @@
* use qualified names where they appear in the document. Second, it
* doesn't properly escape quotes in attribute values. Third, and most
* important, it doesn't differentiate between sibling nodes with the
- * same name and attribute values; if that's important, use {@link
- * #getAbsolutePath}.
+ * same name and attribute values.
+ * <p>
+ * If you want a path that can later be used to select the element,
+ * see {@link #getAbsolutePath}
*/
public static String getPath(Element elem, String... attrNames)
{
@@ -465,11 +469,15 @@
* element, as an XPath expression using positional predicates to
* differentiate between nodes with the same local name, ignoring
* namespace.
+ * <p>
+ * <em>Warning:</em> if your document has namespaces, you will not
+ * be able to use the returned path to select the same node. Use
+ * one of the other variants of this method instead.
*/
public static String getAbsolutePath(Element elem)
{
StringBuilder sb = new StringBuilder();
- buildAbsolutePath(elem, sb, null, null);
+ buildAbsolutePath(elem, sb, null, null, null);
return sb.toString();
}
@@ -486,17 +494,55 @@
* <p>
* If <code>nsLookup</code> does not have a mapping for a given
* namespace, the returned path will contain a dummy prefix of the
- * form "NSx", where "x" is incremented for each unknown namespace,
- * whether or not the namespace has been seen elsewhere in the path.
+ * form "NSx", where "x" is incremented for each unknown namespace.
+ * In this case, you will not be able to use the returned path to
+ * select the element, without adding context entries for those
+ * generated namespaces.
+ * <p>
+ * Note that any prefixes in the source document are ignored. If an
+ * element has a prefix in the source document, but that element's
+ * namespace is not present in <code>nsLookup</code>, the path will
+ * contain a generated prefix. Similarly, if <code>nsLookup.getPrefix()
+ * </code> returns a value for the prefix, that value is used for the
+ * generated path.
*/
public static String getAbsolutePath(Element elem, NamespaceContext nsLookup)
{
StringBuilder sb = new StringBuilder();
- buildAbsolutePath(elem, sb, nsLookup, new int[] {0});
+ buildAbsolutePath(elem, sb, nsLookup, new NamespaceResolver(), new int[] {0});
return sb.toString();
}
+ /**
+ * Returns the path from the root of the document to the specified
+ * element, as an XPath expression using positional predicates to
+ * differentiate between nodes with the same name and namespace.
+ * <p>
+ * The <code>nsLookup</code> parameter is used to retrieve prefixes
+ * for the passed element and its ancestors. If it does not contain
+ * a mapping for a given namespace, one will be added with a prefix
+ * of the form "NSx" (where "x" is a number that's incremented for
+ * each unknown namespace).
+ * <p>
+ * Note that any prefixes in the source document are ignored. If an
+ * element has a prefix in the source document, but that element's
+ * namespace is not present in <code>nsLookup</code>, the path will
+ * contain a generated prefix. Similarly, if <code>nsLookup.getPrefix()
+ * </code> returns a value for the prefix, that value is used for the
+ * generated path.
+ * <p>
+ * The returned path may be used to select the element, provided that
+ * <code>nsLookup</code> is provided as the namespace context.
+ */
+ public static String getAbsolutePath(Element elem, NamespaceResolver nsLookup)
+ {
+ StringBuilder sb = new StringBuilder();
+ buildAbsolutePath(elem, sb, nsLookup, nsLookup, new int[] {0});
+ return sb.toString();
+ }
+
+
//----------------------------------------------------------------------------
// Internals
//----------------------------------------------------------------------------
@@ -566,21 +612,22 @@
* @param sb A buffer used to build the path.
* @param nsLookup Used to resolve defined namespaces. May be null, in
* which case returned path will not have any namespaces.
+ * @param genLookup Holds generated namespace mappings.
* @param nsCounter Used to generate prefixes for unresolved namespaces:
* contains a single element that is incremented for each
* unmapped namespace.
*/
private static void buildAbsolutePath(
Element elem, StringBuilder sb,
- NamespaceContext nsLookup, int[] nsCounter)
+ NamespaceContext nsLookup, NamespaceResolver genLookup, int[] nsCounter)
{
Node parent = elem.getParentNode();
if (parent instanceof Element)
{
- buildAbsolutePath((Element)parent, sb, nsLookup, nsCounter);
+ buildAbsolutePath((Element)parent, sb, nsLookup, genLookup, nsCounter);
}
- String prefix = getPrefix(elem, nsLookup, nsCounter);
+ String prefix = getPrefix(elem, nsLookup, genLookup, nsCounter);
String localName = getLocalName(elem);
List<Element> siblings = (nsLookup == null)
? getSiblings(elem, getLocalName(elem))
@@ -597,9 +644,14 @@
/**
* Helper method for {@link #buildAbsolutePath} that returns the prefix
- * for a given element, using the passed namespace resolver.
+ * for an element. Will first look in <code>nsLookup</code>; if it doesn't
+ * find the namespace there, will look in <code>genLookup</code>; if still
+ * unable to resolve the namespace, will use <code>nsCounter</code> to
+ * generate a new mapping, that's added to <code>genLookup</code>.
*/
- private static String getPrefix(Element elem, NamespaceContext nsLookup, int[] nsCounter)
+ private static String getPrefix(
+ Element elem, NamespaceContext nsLookup,
+ NamespaceResolver genLookup, int[] nsCounter)
{
if (nsLookup == null)
return null;
@@ -609,8 +661,21 @@
return null;
String prefix = nsLookup.getPrefix(nsUri);
- if (prefix == null)
+ if (prefix != null)
+ return prefix;
+
+ prefix = genLookup.getPrefix(nsUri);
+ if (prefix != null)
+ return prefix;
+
+ // make sure we don't reuse a prefix
+ while (prefix == null)
+ {
prefix = "NS" + nsCounter[0]++;
+ if ((nsLookup.getNamespaceURI(prefix) != null) || (genLookup.getNamespaceURI(prefix) != null))
+ prefix = null;
+ }
+ genLookup.addNamespace(prefix, nsUri);
return prefix;
}
Modified: trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-14 15:15:44 UTC (rev 51)
+++ trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-14 17:07:45 UTC (rev 52)
@@ -2,15 +2,15 @@
import java.util.List;
-import javax.xml.namespace.NamespaceContext;
-
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
-import net.sf.practicalxml.misc.SimpleNamespaceResolver;
-
+/**
+ * Tests all DomUtil methods except <code>getPath()</code> and
+ * <code>getAbsolutePath()</code>.
+ */
public class TestDomUtil
extends AbstractTestCase
{
@@ -309,105 +309,4 @@
// success
}
}
-
-
- public void testGetPath() throws Exception
- {
- Element root = DomUtil.newDocument("foo");
- Element child1 = DomUtil.appendChild(root, null, "bargle");
- Element child2 = DomUtil.appendChild(root, "argle", "bargle");
- Element child3 = DomUtil.appendChild(root, "argle", "w:wargle");
- Element child1a = DomUtil.appendChild(child1, null, "zargle");
- child1.setAttribute("poi", "1234");
- child2.setAttribute("poi", "5678");
- child2.setAttribute("qwe", "asd");
- child1a.setAttribute("qwe", "zxc");
-
- assertEquals("/foo",
- DomUtil.getPath(root));
- assertEquals("/foo/bargle",
- DomUtil.getPath(child1));
- assertEquals("/foo/bargle",
- DomUtil.getPath(child2));
- assertEquals("/foo/w:wargle",
- DomUtil.getPath(child3));
- assertEquals("/foo/bargle/zargle",
- DomUtil.getPath(child1a));
-
- assertEquals("/foo",
- DomUtil.getPath(root, "poi", "qwe"));
- assertEquals("/foo/bargle[poi='1234']",
- DomUtil.getPath(child1, "poi", "qwe"));
- assertEquals("/foo/bargle[poi='5678'][qwe='asd']",
- DomUtil.getPath(child2, "poi", "qwe"));
- }
-
-
- public void testGetAbsolutePath() throws Exception
- {
- Element root = DomUtil.newDocument("foo");
- Element child1 = DomUtil.appendChild(root, null, "bargle");
- Element child2 = DomUtil.appendChild(root, null, "wargle");
- Element child3 = DomUtil.appendChild(root, null, "wargle");
- Element child4 = DomUtil.appendChild(root, "argle", "w:zargle");
- Element child5 = DomUtil.appendChild(root, "argle", "zargle");
- Element child6 = DomUtil.appendChild(root, "qargle", "zargle");
- Element child7 = DomUtil.appendChild(root, "argle", "zargle");
- Element child1a = DomUtil.appendChild(child1, null, "bargle");
- Element child3a = DomUtil.appendChild(child3, null, "zargle");
- Element child4a = DomUtil.appendChild(child4, null, "bargle");
- Element child4b = DomUtil.appendChild(child4, "argle", "bargle");
-
- assertEquals("/foo",
- DomUtil.getAbsolutePath(root));
- assertEquals("/foo/bargle",
- DomUtil.getAbsolutePath(child1));
- assertEquals("/foo/bargle/bargle",
- DomUtil.getAbsolutePath(child1a));
- assertEquals("/foo/wargle[1]",
- DomUtil.getAbsolutePath(child2));
- assertEquals("/foo/wargle[2]",
- DomUtil.getAbsolutePath(child3));
- assertEquals("/foo/wargle[2]/zargle",
- DomUtil.getAbsolutePath(child3a));
- assertEquals("/foo/zargle[1]",
- DomUtil.getAbsolutePath(child4));
- assertEquals("/foo/zargle[1]/bargle[1]",
- DomUtil.getAbsolutePath(child4a));
- assertEquals("/foo/zargle[1]/bargle[2]",
- DomUtil.getAbsolutePath(child4b));
- assertEquals("/foo/zargle[2]",
- DomUtil.getAbsolutePath(child5));
- assertEquals("/foo/zargle[3]",
- DomUtil.getAbsolutePath(child6));
- assertEquals("/foo/zargle[4]",
- DomUtil.getAbsolutePath(child7));
-
- NamespaceContext nsLookup = new SimpleNamespaceResolver("arg", "argle");
-
- assertEquals("/foo",
- DomUtil.getAbsolutePath(root, nsLookup));
- assertEquals("/foo/bargle",
- DomUtil.getAbsolutePath(child1, nsLookup));
- assertEquals("/foo/bargle/bargle",
- DomUtil.getAbsolutePath(child1a, nsLookup));
- assertEquals("/foo/wargle[1]",
- DomUtil.getAbsolutePath(child2, nsLookup));
- assertEquals("/foo/wargle[2]",
- DomUtil.getAbsolutePath(child3, nsLookup));
- assertEquals("/foo/wargle[2]/zargle",
- DomUtil.getAbsolutePath(child3a, nsLookup));
- assertEquals("/foo/arg:zargle[1]",
- DomUtil.getAbsolutePath(child4, nsLookup));
- assertEquals("/foo/arg:zargle[1]/bargle",
- DomUtil.getAbsolutePath(child4a, nsLookup));
- assertEquals("/foo/arg:zargle[1]/arg:bargle",
- DomUtil.getAbsolutePath(child4b, nsLookup));
- assertEquals("/foo/arg:zargle[2]",
- DomUtil.getAbsolutePath(child5, nsLookup));
- assertEquals("/foo/NS0:zargle",
- DomUtil.getAbsolutePath(child6, nsLookup));
- assertEquals("/foo/arg:zargle[3]",
- DomUtil.getAbsolutePath(child7, nsLookup));
- }
}
Added: trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java (rev 0)
+++ trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java 2008-12-14 17:07:45 UTC (rev 52)
@@ -0,0 +1,205 @@
+package net.sf.practicalxml;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import net.sf.practicalxml.misc.NamespaceResolver;
+import net.sf.practicalxml.misc.SimpleNamespaceResolver;
+
+
+/**
+ * Tests the methods <code>getPath()</code> and <code>getAbsolutePath()</code>,
+ * because these have multiple tests that use the same complex DOM tree.
+ */
+public class TestDomUtilGetPath
+extends AbstractTestCase
+{
+//----------------------------------------------------------------------------
+// Setup -- no need for a method, we can do everything at initialization
+// -- I think I want to keep the literal element names, rather than
+// making them all constants, because I want to make sure that
+// we're really testing different conditions
+//----------------------------------------------------------------------------
+
+ Element root = DomUtil.newDocument("root");
+ Element child1 = DomUtil.appendChild(root, null, "bargle");
+ Element child2 = DomUtil.appendChild(root, null, "wargle");
+ Element child3 = DomUtil.appendChild(root, null, "wargle");
+ Element child4 = DomUtil.appendChild(root, "argle", "w:zargle");
+ Element child5 = DomUtil.appendChild(root, "argle", "zargle");
+ Element child6 = DomUtil.appendChild(root, "qargle", "zargle");
+ Element child7 = DomUtil.appendChild(root, "argle", "zargle");
+ Element child8 = DomUtil.appendChild(root, "margle", "m:zargle");
+ Element child1a = DomUtil.appendChild(child1, null, "bargle");
+ Element child3a = DomUtil.appendChild(child3, null, "zargle");
+ Element child4a = DomUtil.appendChild(child4, null, "bargle");
+ Element child4b = DomUtil.appendChild(child4, "argle", "bargle");
+ Element child6a = DomUtil.appendChild(child6, "qargle", "zargle");
+
+ Document dom = root.getOwnerDocument();
+
+ Element[] allElements = new Element[]
+ {
+ root,
+ child1, child2, child3, child4, child5,
+ child6, child7, child8,
+ child1a, child3a, child4a, child4b, child6a
+ };
+
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
+ public void testGetPath() throws Exception
+ {
+ child1.setAttribute("poi", "1234");
+ child2.setAttribute("poi", "5678");
+ child2.setAttribute("qwe", "asd");
+ child1a.setAttribute("qwe", "zxc");
+
+ assertEquals("/root",
+ DomUtil.getPath(root));
+ assertEquals("/root/bargle",
+ DomUtil.getPath(child1));
+ assertEquals("/root/wargle",
+ DomUtil.getPath(child2));
+ assertEquals("/root/w:zargle",
+ DomUtil.getPath(child4));
+ assertEquals("/root/wargle/zargle",
+ DomUtil.getPath(child3a));
+
+ assertEquals("/root",
+ DomUtil.getPath(root, "poi", "qwe"));
+ assertEquals("/root/bargle[poi='1234']",
+ DomUtil.getPath(child1, "poi", "qwe"));
+ assertEquals("/root/wargle[poi='5678'][qwe='asd']",
+ DomUtil.getPath(child2, "poi", "qwe"));
+ }
+
+
+ public void testGetAbsolutePathWithoutNamespaces() throws Exception
+ {
+ assertEquals("/root",
+ DomUtil.getAbsolutePath(root));
+ assertEquals("/root/bargle",
+ DomUtil.getAbsolutePath(child1));
+ assertEquals("/root/bargle/bargle",
+ DomUtil.getAbsolutePath(child1a));
+ assertEquals("/root/wargle[1]",
+ DomUtil.getAbsolutePath(child2));
+ assertEquals("/root/wargle[2]",
+ DomUtil.getAbsolutePath(child3));
+ assertEquals("/root/wargle[2]/zargle",
+ DomUtil.getAbsolutePath(child3a));
+ assertEquals("/root/zargle[1]",
+ DomUtil.getAbsolutePath(child4));
+ assertEquals("/root/zargle[1]/bargle[1]",
+ DomUtil.getAbsolutePath(child4a));
+ assertEquals("/root/zargle[1]/bargle[2]",
+ DomUtil.getAbsolutePath(child4b));
+ assertEquals("/root/zargle[2]",
+ DomUtil.getAbsolutePath(child5));
+ assertEquals("/root/zargle[3]",
+ DomUtil.getAbsolutePath(child6));
+ assertEquals("/root/zargle[4]",
+ DomUtil.getAbsolutePath(child7));
+ }
+
+
+ public void testGetAbsolutePathWithPredefinedNamespaces() throws Exception
+ {
+ NamespaceContext nsLookup1 = new SimpleNamespaceResolver("arg", "argle");
+
+ assertEquals("/root",
+ DomUtil.getAbsolutePath(root, nsLookup1));
+ assertEquals("/root/bargle",
+ DomUtil.getAbsolutePath(child1, nsLookup1));
+ assertEquals("/root/bargle/bargle",
+ DomUtil.getAbsolutePath(child1a, nsLookup1));
+ assertEquals("/root/wargle[1]",
+ DomUtil.getAbsolutePath(child2, nsLookup1));
+ assertEquals("/root/wargle[2]",
+ DomUtil.getAbsolutePath(child3, nsLookup1));
+ assertEquals("/root/wargle[2]/zargle",
+ DomUtil.getAbsolutePath(child3a, nsLookup1));
+ assertEquals("/root/arg:zargle[1]",
+ DomUtil.getAbsolutePath(child4, nsLookup1));
+ assertEquals("/root/arg:zargle[1]/bargle",
+ DomUtil.getAbsolutePath(child4a, nsLookup1));
+ assertEquals("/root/arg:zargle[1]/arg:bargle",
+ DomUtil.getAbsolutePath(child4b, nsLookup1));
+ assertEquals("/root/arg:zargle[2]",
+ DomUtil.getAbsolutePath(child5, nsLookup1));
+ assertEquals("/root/NS0:zargle",
+ DomUtil.getAbsolutePath(child6, nsLookup1));
+ assertEquals("/root/NS0:zargle/NS0:zargle",
+ DomUtil.getAbsolutePath(child6a, nsLookup1));
+ assertEquals("/root/arg:zargle[3]",
+ DomUtil.getAbsolutePath(child7, nsLookup1));
+ assertEquals("/root/NS0:zargle",
+ DomUtil.getAbsolutePath(child8, nsLookup1));
+ }
+
+
+ public void testGetAbsolutePathWithUpdatableNamespaces() throws Exception
+ {
+ NamespaceResolver nsLookup = new NamespaceResolver()
+ .addNamespace("arg", "argle")
+ .addNamespace("NS0", "asdf")
+ .addNamespace("NS1", "asdf");
+
+ assertEquals("/root",
+ DomUtil.getAbsolutePath(root, nsLookup));
+ assertEquals("/root/bargle",
+ DomUtil.getAbsolutePath(child1, nsLookup));
+ assertEquals("/root/bargle/bargle",
+ DomUtil.getAbsolutePath(child1a, nsLookup));
+ assertEquals("/root/wargle[1]",
+ DomUtil.getAbsolutePath(child2, nsLookup));
+ assertEquals("/root/wargle[2]",
+ DomUtil.getAbsolutePath(child3, nsLookup));
+ assertEquals("/root/wargle[2]/zargle",
+ DomUtil.getAbsolutePath(child3a, nsLookup));
+ assertEquals("/root/arg:zargle[1]",
+ DomUtil.getAbsolutePath(child4, nsLookup));
+ assertEquals("/root/arg:zargle[1]/bargle",
+ DomUtil.getAbsolutePath(child4a, nsLookup));
+ assertEquals("/root/arg:zargle[1]/arg:bargle",
+ DomUtil.getAbsolutePath(child4b, nsLookup));
+ assertEquals("/root/arg:zargle[2]",
+ DomUtil.getAbsolutePath(child5, nsLookup));
+ assertEquals("/root/NS2:zargle",
+ DomUtil.getAbsolutePath(child6, nsLookup));
+ // note: previous call already added the namespace binding
+ assertEquals("/root/NS2:zargle/NS2:zargle",
+ DomUtil.getAbsolutePath(child6a, nsLookup));
+ assertEquals("/root/arg:zargle[3]",
+ DomUtil.getAbsolutePath(child7, nsLookup));
+ assertEquals("/root/NS3:zargle",
+ DomUtil.getAbsolutePath(child8, nsLookup));
+
+ // verify that the resolver has been updated from all calls
+
+ assertEquals("qargle", nsLookup.getNamespaceURI("NS2"));
+ assertEquals("margle", nsLookup.getNamespaceURI("NS3"));
+ }
+
+
+ public void testGetAbsolutePathWillSelectElement() throws Exception
+ {
+ for (Element elem : allElements)
+ {
+ NamespaceResolver nsLookup = new NamespaceResolver();
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ xpath.setNamespaceContext(nsLookup);
+ assertSame(elem, xpath.evaluate(
+ DomUtil.getAbsolutePath(elem, nsLookup),
+ dom, XPathConstants.NODE));
+ }
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|