NamespaceBinding.java 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright (c) 2003, 2006 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.xml;
  4. import java.io.*;
  5. /** A "namespace node" as a link in a linked list.
  6. *
  7. * The list may contain duplicates - i.e. multiple namespace bindings
  8. * for the same prefix but (usually) different uris. In that case the
  9. * first binding "wins". One reason for allowing duplicates it to allow
  10. * sharing of the lists between a child and its parent element.
  11. */
  12. public final class NamespaceBinding implements Externalizable
  13. {
  14. /** Namespace prefix. An interned String.
  15. * A default namespace declaration is represented using null. */
  16. public final String getPrefix () { return prefix; }
  17. public final void setPrefix (String prefix) { this.prefix = prefix; }
  18. String prefix;
  19. /** Namespace uri. An interned String.
  20. * The value null "undeclares" any following namespaces with the same prefix;
  21. * it corresponds to an empty uri as in the
  22. * XML Namespaces 1.1 Candidate Recommendation. */
  23. public final String getUri () { return uri; }
  24. public final void setUri (String uri) { this.uri = uri; }
  25. String uri;
  26. NamespaceBinding next;
  27. int depth;
  28. public final NamespaceBinding getNext () { return next; }
  29. public final void setNext (NamespaceBinding next)
  30. {
  31. this.next = next;
  32. this.depth = next == null ? 0 : next.depth + 1;
  33. }
  34. /** Chain the first list in front of the second list.
  35. * (The name {@code nconc} comes from Common Lisp.)
  36. */
  37. public final static NamespaceBinding
  38. nconc (NamespaceBinding list1, NamespaceBinding list2)
  39. {
  40. if (list1 == null)
  41. return list2;
  42. list1.setNext(nconc(list1.next, list2));
  43. return list1;
  44. }
  45. // public NamespaceBinding () { }
  46. public NamespaceBinding (String prefix, String uri, NamespaceBinding next)
  47. {
  48. this.prefix = prefix;
  49. this.uri = uri;
  50. setNext(next);
  51. }
  52. public static final String XML_NAMESPACE
  53. = "http://www.w3.org/XML/1998/namespace";
  54. public static final NamespaceBinding predefinedXML
  55. = new NamespaceBinding("xml", XML_NAMESPACE, null);
  56. /** Resolve a prefix.
  57. * @param prefix an interned namespace prefix to search for.
  58. * @return a uri or null if not bound
  59. */
  60. public String resolve (String prefix)
  61. {
  62. for (NamespaceBinding ns = this; ns != null; ns = ns.next)
  63. {
  64. if (ns.prefix == prefix)
  65. return ns.uri;
  66. }
  67. return null;
  68. }
  69. /** Resolve a prefix, in the initial part of this list.
  70. * @param prefix an interned namespace prefix to search for.
  71. * @param fencePost only search this list until then.
  72. * @return a uri or null if not bound
  73. */
  74. public String resolve (String prefix, NamespaceBinding fencePost)
  75. {
  76. for (NamespaceBinding ns = this; ns != fencePost; ns = ns.next)
  77. {
  78. if (ns.prefix == prefix)
  79. return ns.uri;
  80. }
  81. return null;
  82. }
  83. public static NamespaceBinding commonAncestor (NamespaceBinding ns1,
  84. NamespaceBinding ns2)
  85. {
  86. if (ns1.depth > ns2.depth)
  87. {
  88. NamespaceBinding tmp = ns1;
  89. ns1 = ns2;
  90. ns2 = tmp;
  91. }
  92. while (ns2.depth > ns1.depth)
  93. ns2 = ns2.next;
  94. while (ns1 != ns2)
  95. {
  96. ns1 = ns1.next;
  97. ns2 = ns2.next;
  98. }
  99. return ns1;
  100. }
  101. /* For debugging:
  102. void check ()
  103. {
  104. NamespaceBinding ns = this;
  105. int d = depth;
  106. for (;;)
  107. {
  108. if (ns == null)
  109. throw new Error("null ns");
  110. if (ns.depth != d)
  111. throw new Error("bad depth "+ns.depth+" shoudl be "+d);
  112. ns = ns.next;
  113. if (ns == null && d == 0)
  114. return;
  115. d--;
  116. }
  117. }
  118. */
  119. /** Reverse the chain, until a fencePost. */
  120. public NamespaceBinding reversePrefix (NamespaceBinding fencePost)
  121. {
  122. NamespaceBinding prev = fencePost;
  123. NamespaceBinding t = this;
  124. int depth = fencePost == null ? -1 : fencePost.depth;
  125. while (t != fencePost)
  126. {
  127. NamespaceBinding next = t.next;
  128. t.next = prev;
  129. prev = t;
  130. t.depth = ++depth;
  131. t = next;
  132. }
  133. return prev;
  134. }
  135. /** Return the number of bindings before the <code>fencePost</code>. */
  136. public int count (NamespaceBinding fencePost)
  137. {
  138. int count = 0;
  139. for (NamespaceBinding ns = this; ns != fencePost; ns = ns.next)
  140. count++;
  141. return count;
  142. }
  143. /** Append a new NamespaceBinding if not redundant. */
  144. public static NamespaceBinding maybeAdd(String prefix, String uri,
  145. NamespaceBinding bindings)
  146. {
  147. if (bindings == null)
  148. {
  149. if (uri == null)
  150. return bindings;
  151. bindings = predefinedXML;
  152. }
  153. String found = bindings.resolve(prefix);
  154. if (found == null ? uri == null : found.equals(uri))
  155. return bindings;
  156. return new NamespaceBinding(prefix, uri, bindings);
  157. }
  158. /** Return a String showing just a single namespace binding. */
  159. public String toString()
  160. {
  161. return "Namespace{"+prefix+"="+uri+", depth:"+depth+"}";
  162. }
  163. /** Return a String showing the full namespace binding list. */
  164. public String toStringAll()
  165. {
  166. StringBuffer sbuf = new StringBuffer("Namespaces{");
  167. for (NamespaceBinding ns = this; ns != null; ns = ns.next)
  168. {
  169. sbuf.append(ns.prefix);
  170. sbuf.append("=\"");
  171. sbuf.append(ns.uri);
  172. sbuf.append(ns == null ? "\"" : "\", ");
  173. }
  174. sbuf.append('}');
  175. return sbuf.toString();
  176. }
  177. public void writeExternal(ObjectOutput out) throws IOException
  178. {
  179. out.writeUTF(prefix);
  180. out.writeUTF(uri);
  181. out.writeObject(next);
  182. }
  183. public void readExternal(ObjectInput in)
  184. throws IOException, ClassNotFoundException
  185. {
  186. prefix = in.readUTF();
  187. uri = in.readUTF();
  188. next = (NamespaceBinding) in.readObject();
  189. }
  190. }