2 // XmlNamespaceManager.cs
5 // Jason Diamond (jason@injektilo.org)
6 // Ben Maurer (bmaurer@users.sourceforge.net)
8 // (C) 2001 Jason Diamond http://injektilo.org/
12 using System.Collections;
13 using System.Collections.Specialized;
17 public class XmlNamespaceManager : IEnumerable
21 public string Prefix, Uri;
26 public string DefaultNamespace;
35 string defaultNamespace;
40 decls = new NsDecl [10];
41 scopes = new NsScope [40];
44 // precondition declPos == nsDecl.Length
47 NsDecl [] old = decls;
48 decls = new NsDecl [declPos * 2 + 1];
50 Array.Copy (old, 0, decls, 0, declPos);
53 // precondition scopePos == scopes.Length
56 NsScope [] old = scopes;
57 scopes = new NsScope [scopePos * 2 + 1];
59 Array.Copy (old, 0, scopes, 0, scopePos);
66 private XmlNameTable nameTable;
67 internal const string XmlnsXml = "http://www.w3.org/XML/1998/namespace";
68 internal const string XmlnsXmlns = "http://www.w3.org/2000/xmlns/";
69 internal const string PrefixXml = "xml";
70 internal const string PrefixXmlns = "xmlns";
76 public XmlNamespaceManager (XmlNameTable nameTable)
78 this.nameTable = nameTable;
80 nameTable.Add (PrefixXmlns);
81 nameTable.Add (PrefixXml);
82 nameTable.Add (String.Empty);
83 nameTable.Add (XmlnsXmlns);
84 nameTable.Add (XmlnsXml);
93 public virtual string DefaultNamespace {
94 get { return defaultNamespace == null ? string.Empty : defaultNamespace; }
97 public XmlNameTable NameTable {
98 get { return nameTable; }
105 public virtual void AddNamespace (string prefix, string uri)
107 AddNamespace (prefix, uri, false);
111 public virtual void AddNamespace (string prefix, string uri, bool atomizedNames)
113 internal virtual void AddNamespace (string prefix, string uri, bool atomizedNames)
117 throw new ArgumentNullException ("prefix", "Value cannot be null.");
120 throw new ArgumentNullException ("uri", "Value cannot be null.");
121 if (!atomizedNames) {
122 prefix = nameTable.Add (prefix);
123 uri = nameTable.Add (uri);
126 IsValidDeclaration (prefix, uri, true);
128 if (prefix.Length == 0)
129 defaultNamespace = uri;
131 for (int i = declPos; i > declPos - count; i--) {
132 if (object.ReferenceEquals (decls [i].Prefix, prefix)) {
141 if (declPos == decls.Length)
143 decls [declPos].Prefix = prefix;
144 decls [declPos].Uri = uri;
147 internal static string IsValidDeclaration (string prefix, string uri, bool throwException)
149 string message = null;
150 if (prefix == PrefixXml && uri != XmlnsXml)
151 message = String.Format ("Prefix \"xml\" is only allowed to the fixed uri \"{0}\"", XmlnsXml);
152 else if (uri == XmlnsXml)
153 message = String.Format ("Namespace URI \"{0}\" can only be declared with the fixed prefix \"xml\"", XmlnsXml);
154 if (message == null && prefix == "xmlns")
155 message = "Declaring prefix named \"xmlns\" is not allowed to any namespace.";
156 if (message == null && uri == XmlnsXmlns)
157 message = String.Format ("Namespace URI \"{0}\" cannot be declared with any namespace.", XmlnsXmlns);
158 if (message != null && throwException)
159 throw new ArgumentException (message);
164 public virtual IEnumerator GetEnumerator ()
166 // In fact it returns such table's enumerator that contains all the namespaces.
167 // while HasNamespace() ignores pushed namespaces.
169 Hashtable ht = new Hashtable ();
170 for (int i = 0; i <= declPos; i++) {
171 if (decls [i].Prefix != string.Empty && decls [i].Uri != null) {
172 ht [decls [i].Prefix] = decls [i].Uri;
176 ht [string.Empty] = DefaultNamespace;
177 ht [PrefixXml] = XmlnsXml;
178 ht [PrefixXmlns] = XmlnsXmlns;
180 return ht.Keys.GetEnumerator ();
184 public virtual StringDictionary GetNamespacesInScope (XmlNamespaceScope scope)
186 throw new NotImplementedException ();
190 public virtual bool HasNamespace (string prefix)
192 if (prefix == null || count == 0)
195 for (int i = declPos; i > declPos - count; i--) {
196 if (decls [i].Prefix == prefix)
203 public virtual string LookupNamespace (string prefix)
205 return LookupNamespace (prefix, true);
209 public virtual string LookupNamespace (string prefix, bool atomizedName)
211 internal virtual string LookupNamespace (string prefix, bool atomizedName)
216 return nameTable.Get (XmlnsXmlns);
218 return nameTable.Get (XmlnsXml);
220 return DefaultNamespace;
225 for (int i = declPos; i >= 0; i--) {
226 if (CompareString (decls [i].Prefix, prefix, atomizedName) && decls [i].Uri != null /* null == flag for removed */)
227 return decls [i].Uri;
233 public virtual string LookupPrefix (string uri)
235 return LookupPrefix (uri, true);
238 private bool CompareString (string s1, string s2, bool atomizedNames)
241 return object.ReferenceEquals (s1, s2);
247 public string LookupPrefix (string uri, bool atomizedName)
249 internal string LookupPrefix (string uri, bool atomizedName)
255 if (CompareString (uri, DefaultNamespace, atomizedName))
258 if (CompareString (uri, XmlnsXml, atomizedName))
261 if (CompareString (uri, XmlnsXmlns, atomizedName))
264 for (int i = declPos; i >= 0; i--) {
265 if (CompareString (decls [i].Uri, uri, atomizedName) && decls [i].Prefix.Length > 0) // we already looked for ""
266 return decls [i].Prefix;
269 // ECMA specifies that this method returns String.Empty
270 // in case of no match. But actually MS.NET returns null.
271 // For more information,see
272 // http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
273 //return String.Empty;
277 public virtual bool PopScope ()
283 defaultNamespace = scopes [scopePos].DefaultNamespace;
284 count = scopes [scopePos].DeclCount;
289 public virtual void PushScope ()
292 if (scopePos == scopes.Length)
295 scopes [scopePos].DefaultNamespace = defaultNamespace;
296 scopes [scopePos].DeclCount = count;
300 // It is rarely used, so we don't need NameTable optimization on it.
301 public virtual void RemoveNamespace (string prefix, string uri)
303 RemoveNamespace (prefix, uri, false);
307 public virtual void RemoveNamespace (string prefix, string uri, bool atomizedNames)
309 internal virtual void RemoveNamespace (string prefix, string uri, bool atomizedNames)
313 throw new ArgumentNullException ("prefix");
316 throw new ArgumentNullException ("uri");
321 for (int i = declPos; i > declPos - count; i--) {
322 if (CompareString (decls [i].Prefix, prefix, atomizedNames) && CompareString (decls [i].Uri, uri, atomizedNames))
323 decls [i].Uri = null;