[Practicalxml-commits] SF.net SVN: practicalxml:[35] trunk/src
Brought to you by:
kdgregory
From: Auto-Generated S. C. M. <pra...@li...> - 2008-11-28 21:29:25
|
Revision: 35 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=35&view=rev Author: kdgregory Date: 2008-11-28 21:29:19 +0000 (Fri, 28 Nov 2008) Log Message: ----------- add NamespaceResolver, SimpleNamespaceResolver Added Paths: ----------- trunk/src/main/java/net/sf/practicalxml/misc/NamespaceResolver.java trunk/src/main/java/net/sf/practicalxml/misc/SimpleNamespaceResolver.java trunk/src/test/java/net/sf/practicalxml/misc/TestNamespaceResolver.java trunk/src/test/java/net/sf/practicalxml/misc/TestSimpleNamespaceResolver.java Added: trunk/src/main/java/net/sf/practicalxml/misc/NamespaceResolver.java =================================================================== --- trunk/src/main/java/net/sf/practicalxml/misc/NamespaceResolver.java (rev 0) +++ trunk/src/main/java/net/sf/practicalxml/misc/NamespaceResolver.java 2008-11-28 21:29:19 UTC (rev 35) @@ -0,0 +1,217 @@ +package net.sf.practicalxml.misc; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; + + +/** + * Maintains a bi-directional lookup table for mappings between namespace URIs + * and prefixes. Follows the "builder" pattern, in that the methods to add + * mappings may be chained: a resolver can be created and fully configured in + * a single expression. + * <p> + * Usage note: <code>NamespaceContext</code> allows multiple prefixes per URI, + * in keeping with the Namespace spec. This implementation supports that, but + * it's a bad idea to actually use this feature when writing an XPath. You'll + * be much happier if you limit yourself to a 1:1 mapping. + * <p> + * If you have a single namespace mapping, this implementation is overkill. + * Instead, use {@link SimpleNamespaceResolver}. + */ +public class NamespaceResolver +implements NamespaceContext +{ + private final static SortedSet<String> DEFAULT_PREFIXES = + new TreeSet<String>(); + private final static SortedSet<String> XML_NS_URI_PREFIXES = + new TreeSet<String>(); + private final static SortedSet<String> XML_NS_ATTR_PREFIXES = + new TreeSet<String>(); + static + { + DEFAULT_PREFIXES.add(""); + XML_NS_URI_PREFIXES.add(XMLConstants.XML_NS_PREFIX); + XML_NS_ATTR_PREFIXES.add(XMLConstants.XMLNS_ATTRIBUTE); + } + + private Map<String,String> _prefix2ns = new HashMap<String,String>(); + private Map<String,SortedSet<String>> _ns2prefix = new HashMap<String,SortedSet<String>>(); + private String _defaultNS = ""; + + +//---------------------------------------------------------------------------- +// Public methods +//---------------------------------------------------------------------------- + + /** + * Adds a namespace to this resolver. + * + * @return The resolver instance, so that calls may be chained. + * + * @throws IllegalArgumentException if either <code>prefix</code> + * or <code>nsURI</code> is <code>null</code>. + */ + public NamespaceResolver addNamespace(String prefix, String nsURI) + { + if (prefix == null) + throw new IllegalArgumentException("prefix may not be null"); + if (nsURI == null) + throw new IllegalArgumentException("nsURI may not be null"); + + _prefix2ns.put(prefix, nsURI); + getPrefixSet(nsURI).add(prefix); + return this; + } + + + /** + * Sets the default namespace -- the namespace that will be returned + * when an empty string is passed to the resolver. + * + * @return The resolver instance, so that calls may be chained. + * + * @throws IllegalArgumentException if <code>nsURI</code> is + * <code>null</code>. + */ + public NamespaceResolver setDefaultNamespace(String nsURI) + { + if (nsURI == null) + throw new IllegalArgumentException("nsURI may not be null"); + + _defaultNS = nsURI; + return this; + } + + +//---------------------------------------------------------------------------- +// NamespaceContext implementation +//---------------------------------------------------------------------------- + + /** + * Returns the namespace URI bound to a given prefix, <code>null</code> + * if no URI is bound to the specified prefix. See interface doc for + * default bindings. + */ + public String getNamespaceURI(String prefix) + { + if (prefix == null) + throw new IllegalArgumentException("prefix may not be null"); + else if ("".equals(prefix)) + return _defaultNS; + else if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + return XMLConstants.XML_NS_URI; + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + else + return _prefix2ns.get(prefix); + } + + + /** + * Returns the first prefix in alphabetical order bound to this namespace + * URI, <code>null</code> if there is no binding for the namespace. See + * interface doc for default bindings. + */ + public String getPrefix(String nsURI) + { + Iterator<String> itx = getPrefixes(nsURI); + return itx.hasNext() ? itx.next() : null; + } + + + /** + * Returns an iterator over all prefixes bound to this namespace URI, in + * alphabetical order, an empty iterator if there are no bindings. See + * interface doc for default bindings. + */ + public Iterator<String> getPrefixes(String nsURI) + { + if (nsURI == null) + throw new IllegalArgumentException("nsURI may not be null"); + else if (_defaultNS.equals(nsURI)) + return DEFAULT_PREFIXES.iterator(); + else if (XMLConstants.XML_NS_URI.equals(nsURI)) + return XML_NS_URI_PREFIXES.iterator(); + else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(nsURI)) + return XML_NS_ATTR_PREFIXES.iterator(); + else + return getPrefixSet(nsURI).iterator(); + } + + +//---------------------------------------------------------------------------- +// Object overrides +//---------------------------------------------------------------------------- + + /** + * Two instances are considered equal if they have the same mappings, + * including default namespace. + */ + @Override + public final boolean equals(Object obj) + { + if (obj instanceof NamespaceResolver) + { + NamespaceResolver that = (NamespaceResolver)obj; + return this._prefix2ns.equals(that._prefix2ns) + && this._defaultNS.equals(that._defaultNS); + } + return false; + } + + + @Override + public int hashCode() + { + // rely on these objects caching their hashcode + return _prefix2ns.hashCode() ^ _defaultNS.hashCode(); + } + + + /** + * Returns a string containing the the <code>xmlns</code> attribute + * specifications that would result from this resolver. + */ + @Override + public String toString() + { + StringBuilder buf = new StringBuilder(50 * _prefix2ns.size()); + if (!"".equals(_defaultNS)) + { + buf.append("xmlns=\"").append(_defaultNS).append("\""); + } + for (String prefix : new TreeSet<String>(_prefix2ns.keySet())) + { + if (buf.length() > 0) + buf.append(" "); + buf.append("xmlns:").append(prefix).append("=\"") + .append(_prefix2ns.get(prefix)).append("\""); + } + return buf.toString(); + } + + +//---------------------------------------------------------------------------- +// Internals +//---------------------------------------------------------------------------- + + /** + * Returns the set of prefixes for a given namespace, creating a new + * entry if one doesn't already exist. + */ + private SortedSet<String> getPrefixSet(String nsURI) + { + SortedSet<String> prefixes = _ns2prefix.get(nsURI); + if (prefixes == null) + { + prefixes = new TreeSet<String>(); + _ns2prefix.put(nsURI, prefixes); + } + return prefixes; + } +} Property changes on: trunk/src/main/java/net/sf/practicalxml/misc/NamespaceResolver.java ___________________________________________________________________ Added: svn:executable + * Added: trunk/src/main/java/net/sf/practicalxml/misc/SimpleNamespaceResolver.java =================================================================== --- trunk/src/main/java/net/sf/practicalxml/misc/SimpleNamespaceResolver.java (rev 0) +++ trunk/src/main/java/net/sf/practicalxml/misc/SimpleNamespaceResolver.java 2008-11-28 21:29:19 UTC (rev 35) @@ -0,0 +1,141 @@ +package net.sf.practicalxml.misc; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; + + +/** + * Implements a bidirectional lookup between a single namespace URI and its + * prefix, for use with XPath expressions. Does not support the "default" + * namespace, unless explicitly created with a prefix "". + */ +public class SimpleNamespaceResolver +implements NamespaceContext +{ + private final String _prefix; + private final String _nsURI; + private final List<String> _prefixes; + + public SimpleNamespaceResolver(String prefix, String nsURI) + { + _prefix = prefix; + _nsURI = nsURI; + _prefixes = Arrays.asList(prefix); + } + + +//---------------------------------------------------------------------------- +// NamespaceContext implementation +//---------------------------------------------------------------------------- + + /** + * Returns the namespace URI bound to the passed prefix, <code>null</code> + * if the prefix does not correspond to the binding defined by this + * instance. Also supports "standard" bindings; see JDK doc for details. + */ + public String getNamespaceURI(String prefix) + { + if (prefix == null) + throw new IllegalArgumentException("prefix may not be null"); + else if (_prefix.equals(prefix)) + return _nsURI; + else if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + return XMLConstants.XML_NS_URI; + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + + else + return null; + } + + + /** + * Returns the prefix bound to the passed namespace URI, <code>null</code> + * if the URI does not correspond to the binding defined by this instance. + * Also supports "standard" bindings; see JDK doc for details. + */ + public String getPrefix(String nsURI) + { + if (nsURI == null) + throw new IllegalArgumentException("nsURI may not be null"); + else if (nsURI.equals(_nsURI)) + return _prefix; + else if (nsURI.equals(XMLConstants.XML_NS_URI)) + return XMLConstants.XML_NS_PREFIX; + else if (nsURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) + return XMLConstants.XMLNS_ATTRIBUTE; + else + return null; + } + + + /** + * Returns an iterator over prefixes for the passed URI, an empty iterator + * if the URI does not correspond to the binding defined by this instance. + * Also supports "standard" bindings; see JDK doc for details. + */ + public Iterator<String> getPrefixes(String nsURI) + { + String prefix = getPrefix(nsURI); + if (_prefix.equals(prefix)) + return _prefixes.iterator(); + else if (_prefix == null) + return Collections.<String>emptyList().iterator(); + else + return Arrays.asList(prefix).iterator(); + } + + +//---------------------------------------------------------------------------- +// Object overrides +//---------------------------------------------------------------------------- + + /** + * Two instances are considered equal if they have the same mappings, + * including default namespace. + */ + @Override + public final boolean equals(Object obj) + { + if (obj instanceof SimpleNamespaceResolver) + { + SimpleNamespaceResolver that = (SimpleNamespaceResolver)obj; + return this._prefix.equals(that._prefix) + && this._nsURI.equals(that._nsURI); + } + return false; + } + + + @Override + public int hashCode() + { + return _prefix.hashCode() ^ _nsURI.hashCode(); + } + + + /** + * Returns a string containing the the <code>xmlns</code> attribute + * specifications that would result from this resolver. + */ + @Override + public String toString() + { + StringBuilder buf = new StringBuilder(_prefix.length() + _nsURI.length() + 10); + if ("".equals(_prefix)) + { + buf.append("xmlns=\"").append(_nsURI).append("\""); + } + else + { + buf.append("xmlns:").append(_prefix).append("=\"") + .append(_nsURI).append("\""); + } + return buf.toString(); + } +} Property changes on: trunk/src/main/java/net/sf/practicalxml/misc/SimpleNamespaceResolver.java ___________________________________________________________________ Added: svn:executable + * Added: trunk/src/test/java/net/sf/practicalxml/misc/TestNamespaceResolver.java =================================================================== --- trunk/src/test/java/net/sf/practicalxml/misc/TestNamespaceResolver.java (rev 0) +++ trunk/src/test/java/net/sf/practicalxml/misc/TestNamespaceResolver.java 2008-11-28 21:29:19 UTC (rev 35) @@ -0,0 +1,198 @@ +package net.sf.practicalxml.misc; + +import java.util.Iterator; +import javax.xml.XMLConstants; + +import net.sf.practicalxml.AbstractTestCase; + + +public class TestNamespaceResolver extends AbstractTestCase +{ + public void testSingleNamespace() throws Exception + { + final String prefix = "foo"; + final String nsURI = "bar"; + + NamespaceResolver resolv = new NamespaceResolver(); + + assertSame(resolv, resolv.addNamespace(prefix, nsURI)); + + assertEquals(nsURI, resolv.getNamespaceURI(prefix)); + assertEquals(prefix, resolv.getPrefix(nsURI)); + + Iterator<String> itx = resolv.getPrefixes(nsURI); + assertEquals(prefix, itx.next()); + assertFalse(itx.hasNext()); + } + + + public void testTwoNamespaces() throws Exception + { + final String prefix1 = "foo"; + final String nsURI1 = "bar"; + final String prefix2 = "argle"; + final String nsURI2 = "bargle"; + + NamespaceResolver resolv = new NamespaceResolver() + .addNamespace(prefix1, nsURI1) + .addNamespace(prefix2, nsURI2); + + assertEquals(nsURI1, resolv.getNamespaceURI(prefix1)); + assertEquals(nsURI2, resolv.getNamespaceURI(prefix2)); + + assertEquals(prefix1, resolv.getPrefix(nsURI1)); + assertEquals(prefix2, resolv.getPrefix(nsURI2)); + + Iterator<String> itx1 = resolv.getPrefixes(nsURI1); + assertEquals(prefix1, itx1.next()); + assertFalse(itx1.hasNext()); + + Iterator<String> itx2 = resolv.getPrefixes(nsURI2); + assertEquals(prefix2, itx2.next()); + assertFalse(itx2.hasNext()); + } + + + public void testOneNamespaceTwoPrefixes() throws Exception + { + final String prefix1 = "foo"; + final String prefix2 = "argle"; + final String nsURI = "bargle"; + + NamespaceResolver resolv = new NamespaceResolver() + .addNamespace(prefix1, nsURI) + .addNamespace(prefix2, nsURI); + + assertEquals(nsURI, resolv.getNamespaceURI(prefix1)); + assertEquals(nsURI, resolv.getNamespaceURI(prefix2)); + + assertEquals(prefix2, resolv.getPrefix(nsURI)); + + Iterator<String> itx1 = resolv.getPrefixes(nsURI); + assertEquals(prefix2, itx1.next()); + assertEquals(prefix1, itx1.next()); + assertFalse(itx1.hasNext()); + } + + + public void testStandardMappings() throws Exception + { + NamespaceResolver resolv = new NamespaceResolver(); + + assertEquals(XMLConstants.XML_NS_URI, resolv.getNamespaceURI(XMLConstants.XML_NS_PREFIX)); + assertEquals(XMLConstants.XML_NS_PREFIX, resolv.getPrefix(XMLConstants.XML_NS_URI)); + Iterator<String> itx1 = resolv.getPrefixes(XMLConstants.XML_NS_URI); + assertEquals(XMLConstants.XML_NS_PREFIX, itx1.next()); + assertFalse(itx1.hasNext()); + + assertEquals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, resolv.getNamespaceURI(XMLConstants.XMLNS_ATTRIBUTE)); + assertEquals(XMLConstants.XMLNS_ATTRIBUTE, resolv.getPrefix(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)); + Iterator<String> itx2 = resolv.getPrefixes(XMLConstants.XMLNS_ATTRIBUTE_NS_URI); + assertEquals(XMLConstants.XMLNS_ATTRIBUTE, itx2.next()); + assertFalse(itx2.hasNext()); + + try + { + resolv.getNamespaceURI(null); + fail("should throw IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + // success + } + + try + { + resolv.getPrefix(null); + fail("should throw IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + // success + } + + try + { + resolv.getPrefixes(null); + fail("should throw IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + // success + } + } + + + public void testDefaultNamespace() throws Exception + { + NamespaceResolver resolv = new NamespaceResolver(); + + assertEquals("", resolv.getNamespaceURI("")); + assertEquals("", resolv.getPrefix("")); + Iterator<String> itx1 = resolv.getPrefixes(""); + assertEquals("", itx1.next()); + assertFalse(itx1.hasNext()); + + assertSame(resolv, resolv.setDefaultNamespace("foo")); + + assertEquals("foo", resolv.getNamespaceURI("")); + assertEquals("", resolv.getPrefix("foo")); + Iterator<String> itx2 = resolv.getPrefixes("foo"); + assertEquals("", itx2.next()); + assertFalse(itx2.hasNext()); + } + + + public void testEqualsAndHashCode() throws Exception + { + NamespaceResolver resolv1 = new NamespaceResolver() + .addNamespace("foo", "bar") + .setDefaultNamespace("zippy"); + NamespaceResolver resolv2 = new NamespaceResolver() + .addNamespace("foo", "bar") + .setDefaultNamespace("zippy"); + NamespaceResolver resolv3 = new NamespaceResolver() + .addNamespace("foo", "bar"); + NamespaceResolver resolv4 = new NamespaceResolver() + .addNamespace("argle", "bargle"); + + assertTrue(resolv1.equals(resolv2)); + assertTrue(resolv2.equals(resolv1)); + assertEquals(resolv1.hashCode(), resolv2.hashCode()); + + assertFalse(resolv1.equals(resolv3)); + assertFalse(resolv3.equals(resolv1)); + + assertFalse(resolv3.equals(resolv4)); + assertFalse(resolv4.equals(resolv3)); + + // this works today ... assume that the underlying calcs don't change + assertFalse(resolv3.hashCode() == resolv4.hashCode()); + } + + + public void testToString() throws Exception + { + NamespaceResolver resolv = new NamespaceResolver(); + String str0 = resolv.toString(); + assertEquals(0, str0.length()); + + resolv.setDefaultNamespace("foo"); + String str1 = resolv.toString(); + assertTrue(str1.contains("xmlns=\"foo\"")); + assertEquals(1, str1.split(" +").length); + + resolv.addNamespace("argle", "bargle"); + String str2 = resolv.toString(); + assertTrue(str2.contains("xmlns=\"foo\"")); + assertTrue(str2.contains("xmlns:argle=\"bargle\"")); + assertEquals(2, str2.split(" +").length); + + resolv.addNamespace("zippy", "pinhead"); + String str3 = resolv.toString(); + assertTrue(str3.contains("xmlns=\"foo\"")); + assertTrue(str3.contains("xmlns:argle=\"bargle\"")); + assertTrue(str3.contains("xmlns:zippy=\"pinhead\"")); + assertEquals(3, str3.split(" +").length); + } +} Property changes on: trunk/src/test/java/net/sf/practicalxml/misc/TestNamespaceResolver.java ___________________________________________________________________ Added: svn:executable + * Added: trunk/src/test/java/net/sf/practicalxml/misc/TestSimpleNamespaceResolver.java =================================================================== --- trunk/src/test/java/net/sf/practicalxml/misc/TestSimpleNamespaceResolver.java (rev 0) +++ trunk/src/test/java/net/sf/practicalxml/misc/TestSimpleNamespaceResolver.java 2008-11-28 21:29:19 UTC (rev 35) @@ -0,0 +1,101 @@ +package net.sf.practicalxml.misc; + +import java.util.Iterator; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; + +import net.sf.practicalxml.AbstractTestCase; + + +public class TestSimpleNamespaceResolver extends AbstractTestCase +{ + public void testLookup() throws Exception + { + final String prefix = "foo"; + final String nsURI = "bar"; + + NamespaceContext resolv = new SimpleNamespaceResolver(prefix, nsURI); + + assertEquals(nsURI, resolv.getNamespaceURI(prefix)); + assertEquals(prefix, resolv.getPrefix(nsURI)); + + Iterator<String> itx = resolv.getPrefixes(nsURI); + assertEquals(prefix, itx.next()); + assertFalse(itx.hasNext()); + } + + + public void testStandardMappings() throws Exception + { + NamespaceResolver resolv = new NamespaceResolver(); + + assertEquals(XMLConstants.XML_NS_URI, resolv.getNamespaceURI(XMLConstants.XML_NS_PREFIX)); + assertEquals(XMLConstants.XML_NS_PREFIX, resolv.getPrefix(XMLConstants.XML_NS_URI)); + Iterator<String> itx1 = resolv.getPrefixes(XMLConstants.XML_NS_URI); + assertEquals(XMLConstants.XML_NS_PREFIX, itx1.next()); + assertFalse(itx1.hasNext()); + + assertEquals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, resolv.getNamespaceURI(XMLConstants.XMLNS_ATTRIBUTE)); + assertEquals(XMLConstants.XMLNS_ATTRIBUTE, resolv.getPrefix(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)); + Iterator<String> itx2 = resolv.getPrefixes(XMLConstants.XMLNS_ATTRIBUTE_NS_URI); + assertEquals(XMLConstants.XMLNS_ATTRIBUTE, itx2.next()); + assertFalse(itx2.hasNext()); + + try + { + resolv.getNamespaceURI(null); + fail("should throw IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + // success + } + + try + { + resolv.getPrefix(null); + fail("should throw IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + // success + } + + try + { + resolv.getPrefixes(null); + fail("should throw IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + // success + } + } + + + public void testEqualsAndHashCode() throws Exception + { + Object resolv1 = new SimpleNamespaceResolver("foo", "bar"); + Object resolv2 = new SimpleNamespaceResolver("foo", "bar"); + Object resolv3 = new SimpleNamespaceResolver("argle", "bargle"); + + assertTrue(resolv1.equals(resolv2)); + assertTrue(resolv2.equals(resolv1)); + assertTrue(resolv1.hashCode() == resolv2.hashCode()); + + assertFalse(resolv1.equals(resolv3)); + assertFalse(resolv3.equals(resolv1)); + // this works today ... assume that the underlying calcs don't change + assertFalse(resolv1.hashCode() == resolv3.hashCode()); + } + + + public void testToString() throws Exception + { + String str1 = new SimpleNamespaceResolver("", "foo").toString(); + assertEquals("xmlns=\"foo\"", str1); + + String str2 = new SimpleNamespaceResolver("foo", "bar").toString(); + assertEquals("xmlns:foo=\"bar\"", str2); + } +} Property changes on: trunk/src/test/java/net/sf/practicalxml/misc/TestSimpleNamespaceResolver.java ___________________________________________________________________ Added: svn:executable + * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |