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;
16 public class XmlNamespaceManager : IEnumerable
20 public string Prefix, Uri;
25 public string DefaultNamespace;
34 string defaultNamespace;
39 decls = new NsDecl [10];
40 scopes = new NsScope [40];
43 // precondition declPos == nsDecl.Length
46 NsDecl [] old = decls;
47 decls = new NsDecl [declPos * 2 + 1];
49 Array.Copy (old, 0, decls, 0, declPos);
52 // precondition scopePos == scopes.Length
55 NsScope [] old = scopes;
56 scopes = new NsScope [scopePos * 2 + 1];
58 Array.Copy (old, 0, scopes, 0, scopePos);
65 private XmlNameTable nameTable;
66 internal const string XmlnsXml = "http://www.w3.org/XML/1998/namespace";
67 internal const string XmlnsXmlns = "http://www.w3.org/2000/xmlns/";
68 internal const string PrefixXml = "xml";
69 internal const string PrefixXmlns = "xmlns";
75 internal XmlNamespaceManager () {}
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 ();
183 public virtual bool HasNamespace (string prefix)
185 if (prefix == null || count == 0)
188 for (int i = declPos; i > declPos - count; i--) {
189 if (decls [i].Prefix == prefix)
196 public virtual string LookupNamespace (string prefix)
198 return LookupNamespace (prefix, false);
202 public string LookupNamespace (string prefix, bool atomizedName)
204 internal string LookupNamespace (string prefix, bool atomizedName)
209 return nameTable.Get (XmlnsXmlns);
211 return nameTable.Get (XmlnsXml);
213 return DefaultNamespace;
218 for (int i = declPos; i >= 0; i--) {
219 if (CompareString (decls [i].Prefix, prefix, atomizedName) && decls [i].Uri != null /* null == flag for removed */)
220 return decls [i].Uri;
226 public virtual string LookupPrefix (string uri)
228 return LookupPrefix (uri, false);
231 private bool CompareString (string s1, string s2, bool atomizedNames)
234 return object.ReferenceEquals (s1, s2);
240 public string LookupPrefix (string uri, bool atomizedName)
242 internal string LookupPrefix (string uri, bool atomizedName)
248 if (CompareString (uri, DefaultNamespace, atomizedName))
251 if (CompareString (uri, XmlnsXml, atomizedName))
254 if (CompareString (uri, XmlnsXmlns, atomizedName))
257 for (int i = declPos; i >= 0; i--) {
258 if (CompareString (decls [i].Uri, uri, atomizedName) && decls [i].Prefix.Length > 0) // we already looked for ""
259 return decls [i].Prefix;
262 // ECMA specifies that this method returns String.Empty
263 // in case of no match. But actually MS.NET returns null.
264 // For more information,see
265 // http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
266 //return String.Empty;
270 public virtual bool PopScope ()
276 defaultNamespace = scopes [scopePos].DefaultNamespace;
277 count = scopes [scopePos].DeclCount;
282 public virtual void PushScope ()
285 if (scopePos == scopes.Length)
288 scopes [scopePos].DefaultNamespace = defaultNamespace;
289 scopes [scopePos].DeclCount = count;
293 // It is rarely used, so we don't need NameTable optimization on it.
294 public virtual void RemoveNamespace (string prefix, string uri)
296 RemoveNamespace (prefix, uri, false);
300 public virtual void RemoveNamespace (string prefix, string uri, bool atomizedNames)
302 internal virtual void RemoveNamespace (string prefix, string uri, bool atomizedNames)
306 throw new ArgumentNullException ("prefix");
309 throw new ArgumentNullException ("uri");
314 for (int i = declPos; i > declPos - count; i--) {
315 if (CompareString (decls [i].Prefix, prefix, atomizedNames) && CompareString (decls [i].Uri, uri, atomizedNames))
316 decls [i].Uri = null;