2 // XmlNamespaceManager.cs
5 // Jason Diamond (jason@injektilo.org)
7 // (C) 2001 Jason Diamond http://injektilo.org/
10 using System.Collections;
14 public class XmlNamespaceManager : IEnumerable
18 private XmlNameTable nameTable;
20 HighWaterStack decls = new HighWaterStack (50);
21 HighWaterStack scopes = new HighWaterStack (50);
22 Namespace defaultNamespace;
25 internal const string XmlnsXml = "http://www.w3.org/XML/1998/namespace";
26 internal const string XmlnsXmlns = "http://www.w3.org/2000/xmlns/";
28 string XMLNS, XML, XMLNS_URL, XML_URL;
33 public XmlNamespaceManager (XmlNameTable nameTable)
35 this.nameTable = nameTable;
37 XMLNS = nameTable.Add ("xmlns");
38 XML = nameTable.Add ("xml");
39 XMLNS_URL = nameTable.Add (XmlnsXmlns);
40 XML_URL = nameTable.Add (XmlnsXml);
47 public virtual string DefaultNamespace {
48 get { return (defaultNamespace == null) ? String.Empty : defaultNamespace.Uri; }
51 public XmlNameTable NameTable {
52 get { return nameTable; }
59 public virtual void AddNamespace (string prefix, string uri)
62 throw new ArgumentNullException ("prefix", "Value cannot be null.");
65 throw new ArgumentNullException ("uri", "Value cannot be null.");
67 IsValidDeclaration (prefix, uri, true);
69 prefix = nameTable.Add (prefix);
70 uri = nameTable.Add (uri);
72 // Is it already in the table?
73 for (int i = decls.Length - 1; i >= decls.Length - count; i--) {
74 Namespace decl = (Namespace)decls [i];
75 if (AtomicStringEquals (decl.Prefix, prefix)) {
82 // Otherwise, we are going to add it as a new object
83 Namespace newDecl = (Namespace) decls.Push ();
84 if (newDecl == null) {
85 newDecl = new Namespace ();
86 decls.AddToTop (newDecl);
88 newDecl.Prefix = prefix;
91 if (prefix == String.Empty)
92 defaultNamespace = newDecl;
95 internal static string IsValidDeclaration (string prefix, string uri, bool throwException)
97 string message = null;
98 if (prefix == "xml" && uri != XmlnsXml)
99 message = String.Format ("Prefix \"xml\" is only allowed to the fixed uri \"{0}\"", XmlnsXml);
100 else if (uri == XmlnsXml)
101 message = String.Format ("Namespace URI \"{0}\" can only be declared with the fixed prefix \"xml\"", XmlnsXml);
102 if (message == null && prefix == "xmlns")
103 message = "Declaring prefix named \"xmlns\" is not allowed to any namespace.";
104 if (message == null && uri == XmlnsXmlns)
105 message = String.Format ("Namespace URI \"{0}\" cannot be declared with any namespace.", XmlnsXmlns);
106 if (message != null && throwException)
107 throw new ArgumentException (message);
112 public virtual IEnumerator GetEnumerator ()
114 Hashtable p = new Hashtable (count);
115 for (int i = decls.Length - 1; i >= decls.Length - count; i--) {
116 Namespace decl = (Namespace)decls [i];
117 if (decl.Prefix != String.Empty && decl.Uri != null)
118 p [decl.Prefix] = decl.Uri;
120 p [String.Empty] = DefaultNamespace;
122 p [XMLNS] = XMLNS_URL;
123 return p.Keys.GetEnumerator ();
126 public virtual bool HasNamespace (string prefix)
128 if (prefix == null) return false;
130 for (int i = decls.Length - 1; i >= decls.Length - count; i--) {
131 Namespace decl = (Namespace)decls [i];
132 if (AtomicStringEquals (decl.Prefix, prefix) && decl.Uri != null)
138 public virtual string LookupNamespace (string prefix)
143 if (prefix == String.Empty)
144 return DefaultNamespace;
146 if (AtomicStringEquals (XML, prefix))
149 if (AtomicStringEquals (XMLNS, prefix))
152 for (int i = decls.Length - 1; i >= 0; i--) {
153 Namespace decl = (Namespace)decls [i];
154 if (AtomicStringEquals (decl.Prefix, prefix) && decl.Uri != null)
161 public virtual string LookupPrefix (string uri)
166 if (AtomicStringEquals (DefaultNamespace, uri))
169 if (AtomicStringEquals (XML_URL, uri))
172 if (AtomicStringEquals (XMLNS_URL, uri))
176 for (int i = decls.Length - 1; i >= 0; i--) {
177 Namespace decl = (Namespace)decls [i];
178 if (AtomicStringEquals (decl.Uri, uri) && decl.Uri != null)
182 // ECMA specifies that this method returns String.Empty
183 // in case of no match. But actually MS.NET returns null.
184 // For more information,see
185 // http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
186 //return String.Empty;
190 public virtual bool PopScope ()
192 Scope current = (Scope)scopes.Pop ();
193 if (current == null) {
196 for (int i = 0; i < count; i++)
199 defaultNamespace = current.DefaultNamespace;
200 count = current.Count;
205 public virtual void PushScope ()
207 Scope current = (Scope)scopes.Push ();
208 if (current == null) {
209 current = new Scope ();
210 scopes.AddToTop (current);
212 current.DefaultNamespace = defaultNamespace;
213 current.Count = count;
217 public virtual void RemoveNamespace (string prefix, string uri)
220 throw new ArgumentNullException ("prefix");
223 throw new ArgumentNullException ("uri");
225 string p = nameTable.Get (prefix);
226 string u = nameTable.Get (uri);
227 if (p == null || u == null)
230 for (int i = decls.Length - 1; i >= decls.Length - count; i--) {
231 Namespace n = (Namespace)decls [i];
232 if (AtomicStringEquals (n.Prefix, p) && AtomicStringEquals (n.Uri, u))
237 bool AtomicStringEquals (string a, string b) {
238 if (String.Equals (a, b) && !Object.ReferenceEquals (a, b)) {
239 // Console.Error.WriteLine ("WARNING: {0} not interned", a);
242 return String.Equals (a, b);
248 public string Prefix, Uri;
252 public Namespace DefaultNamespace;