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 internal XmlNamespaceManager () {}
77 public XmlNamespaceManager (XmlNameTable nameTable)
79 this.nameTable = nameTable;
81 nameTable.Add (PrefixXmlns);
82 nameTable.Add (PrefixXml);
83 nameTable.Add (String.Empty);
84 nameTable.Add (XmlnsXmlns);
85 nameTable.Add (XmlnsXml);
94 public virtual string DefaultNamespace {
95 get { return defaultNamespace == null ? string.Empty : defaultNamespace; }
98 public XmlNameTable NameTable {
99 get { return nameTable; }
106 public virtual void AddNamespace (string prefix, string uri)
108 AddNamespace (prefix, uri, false);
112 public virtual void AddNamespace (string prefix, string uri, bool atomizedNames)
114 internal virtual void AddNamespace (string prefix, string uri, bool atomizedNames)
118 throw new ArgumentNullException ("prefix", "Value cannot be null.");
121 throw new ArgumentNullException ("uri", "Value cannot be null.");
122 if (!atomizedNames) {
123 prefix = nameTable.Add (prefix);
124 uri = nameTable.Add (uri);
127 IsValidDeclaration (prefix, uri, true);
129 if (prefix.Length == 0)
130 defaultNamespace = uri;
132 for (int i = declPos; i > declPos - count; i--) {
133 if (object.ReferenceEquals (decls [i].Prefix, prefix)) {
142 if (declPos == decls.Length)
144 decls [declPos].Prefix = prefix;
145 decls [declPos].Uri = uri;
148 internal static string IsValidDeclaration (string prefix, string uri, bool throwException)
150 string message = null;
151 if (prefix == PrefixXml && uri != XmlnsXml)
152 message = String.Format ("Prefix \"xml\" is only allowed to the fixed uri \"{0}\"", XmlnsXml);
153 else if (uri == XmlnsXml)
154 message = String.Format ("Namespace URI \"{0}\" can only be declared with the fixed prefix \"xml\"", XmlnsXml);
155 if (message == null && prefix == "xmlns")
156 message = "Declaring prefix named \"xmlns\" is not allowed to any namespace.";
157 if (message == null && uri == XmlnsXmlns)
158 message = String.Format ("Namespace URI \"{0}\" cannot be declared with any namespace.", XmlnsXmlns);
159 if (message != null && throwException)
160 throw new ArgumentException (message);
165 public virtual IEnumerator GetEnumerator ()
167 // In fact it returns such table's enumerator that contains all the namespaces.
168 // while HasNamespace() ignores pushed namespaces.
170 Hashtable ht = new Hashtable ();
171 for (int i = 0; i <= declPos; i++) {
172 if (decls [i].Prefix != string.Empty && decls [i].Uri != null) {
173 ht [decls [i].Prefix] = decls [i].Uri;
177 ht [string.Empty] = DefaultNamespace;
178 ht [PrefixXml] = XmlnsXml;
179 ht [PrefixXmlns] = XmlnsXmlns;
181 return ht.Keys.GetEnumerator ();
185 public virtual StringDictionary GetNamespacesInScope (XmlNamespaceScope scope)
187 throw new NotImplementedException ();
191 public virtual bool HasNamespace (string prefix)
193 if (prefix == null || count == 0)
196 for (int i = declPos; i > declPos - count; i--) {
197 if (decls [i].Prefix == prefix)
204 public virtual string LookupNamespace (string prefix)
206 return LookupNamespace (prefix, false);
210 public string LookupNamespace (string prefix, bool atomizedName)
212 internal string LookupNamespace (string prefix, bool atomizedName)
217 return nameTable.Get (XmlnsXmlns);
219 return nameTable.Get (XmlnsXml);
221 return DefaultNamespace;
226 for (int i = declPos; i >= 0; i--) {
227 if (CompareString (decls [i].Prefix, prefix, atomizedName) && decls [i].Uri != null /* null == flag for removed */)
228 return decls [i].Uri;
234 public virtual string LookupPrefix (string uri)
236 return LookupPrefix (uri, false);
239 private bool CompareString (string s1, string s2, bool atomizedNames)
242 return object.ReferenceEquals (s1, s2);
248 public string LookupPrefix (string uri, bool atomizedName)
250 internal string LookupPrefix (string uri, bool atomizedName)
256 if (CompareString (uri, DefaultNamespace, atomizedName))
259 if (CompareString (uri, XmlnsXml, atomizedName))
262 if (CompareString (uri, XmlnsXmlns, atomizedName))
265 for (int i = declPos; i >= 0; i--) {
266 if (CompareString (decls [i].Uri, uri, atomizedName) && decls [i].Prefix.Length > 0) // we already looked for ""
267 return decls [i].Prefix;
270 // ECMA specifies that this method returns String.Empty
271 // in case of no match. But actually MS.NET returns null.
272 // For more information,see
273 // http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
274 //return String.Empty;
278 public virtual bool PopScope ()
284 defaultNamespace = scopes [scopePos].DefaultNamespace;
285 count = scopes [scopePos].DeclCount;
290 public virtual void PushScope ()
293 if (scopePos == scopes.Length)
296 scopes [scopePos].DefaultNamespace = defaultNamespace;
297 scopes [scopePos].DeclCount = count;
301 // It is rarely used, so we don't need NameTable optimization on it.
302 public virtual void RemoveNamespace (string prefix, string uri)
304 RemoveNamespace (prefix, uri, false);
308 public virtual void RemoveNamespace (string prefix, string uri, bool atomizedNames)
310 internal virtual void RemoveNamespace (string prefix, string uri, bool atomizedNames)
314 throw new ArgumentNullException ("prefix");
317 throw new ArgumentNullException ("uri");
322 for (int i = declPos; i > declPos - count; i--) {
323 if (CompareString (decls [i].Prefix, prefix, atomizedNames) && CompareString (decls [i].Uri, uri, atomizedNames))
324 decls [i].Uri = null;