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/";
73 internal XmlNamespaceManager () {}
74 public XmlNamespaceManager (XmlNameTable nameTable)
76 this.nameTable = nameTable;
78 nameTable.Add ("xmlns");
79 nameTable.Add ("xml");
80 nameTable.Add (String.Empty);
81 nameTable.Add (XmlnsXmlns);
82 nameTable.Add (XmlnsXml);
91 public virtual string DefaultNamespace {
92 get { return defaultNamespace == null ? string.Empty : defaultNamespace; }
95 public XmlNameTable NameTable {
96 get { return nameTable; }
103 public virtual void AddNamespace (string prefix, string uri)
106 throw new ArgumentNullException ("prefix", "Value cannot be null.");
109 throw new ArgumentNullException ("uri", "Value cannot be null.");
111 prefix = nameTable.Add (prefix);
112 uri = nameTable.Add (uri);
114 IsValidDeclaration (prefix, uri, true);
116 if (prefix == string.Empty)
117 defaultNamespace = uri;
119 for (int i = declPos; i > declPos - count; i--) {
120 if (decls [i].Prefix == prefix) {
129 if (declPos == decls.Length)
131 decls [declPos].Prefix = prefix;
132 decls [declPos].Uri = uri;
135 internal static string IsValidDeclaration (string prefix, string uri, bool throwException)
137 string message = null;
138 if (prefix == "xml" && uri != XmlnsXml)
139 message = String.Format ("Prefix \"xml\" is only allowed to the fixed uri \"{0}\"", XmlnsXml);
140 else if (uri == XmlnsXml)
141 message = String.Format ("Namespace URI \"{0}\" can only be declared with the fixed prefix \"xml\"", XmlnsXml);
142 if (message == null && prefix == "xmlns")
143 message = "Declaring prefix named \"xmlns\" is not allowed to any namespace.";
144 if (message == null && uri == XmlnsXmlns)
145 message = String.Format ("Namespace URI \"{0}\" cannot be declared with any namespace.", XmlnsXmlns);
146 if (message != null && throwException)
147 throw new ArgumentException (message);
152 public virtual IEnumerator GetEnumerator ()
154 // In fact it returns such table's enumerator that contains all the namespaces.
155 // while HasNamespace() ignores pushed namespaces.
157 Hashtable ht = new Hashtable ();
158 for (int i = 0; i <= declPos; i++) {
159 if (decls [i].Prefix != string.Empty && decls [i].Uri != null) {
160 ht [decls [i].Prefix] = decls [i].Uri;
164 ht [string.Empty] = DefaultNamespace;
165 ht ["xml"] = XmlnsXml;
166 ht ["xmlns"] = XmlnsXmlns;
168 return ht.Keys.GetEnumerator ();
171 public virtual bool HasNamespace (string prefix)
173 if (prefix == null || count == 0)
176 for (int i = declPos; i > declPos - count; i--) {
177 if (decls [i].Prefix == prefix)
184 public virtual string LookupNamespace (string prefix)
188 return nameTable.Get (XmlnsXmlns);
190 return nameTable.Get (XmlnsXml);
192 return DefaultNamespace;
195 for (int i = declPos; i >= 0; i--) {
196 if (decls [i].Prefix == prefix && decls [i].Uri != null /* null == flag for removed */)
197 return decls [i].Uri;
203 public virtual string LookupPrefix (string uri)
208 if (uri == DefaultNamespace)
212 return nameTable.Add ("xml");
214 if (uri == XmlnsXmlns)
215 return nameTable.Add ("xmlns");
218 for (int i = declPos; i >= 0; i--) {
219 if (decls [i].Uri == uri && decls [i].Prefix != string.Empty) // we already looked for ""
220 return decls [i].Prefix;
223 // ECMA specifies that this method returns String.Empty
224 // in case of no match. But actually MS.NET returns null.
225 // For more information,see
226 // http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
227 //return String.Empty;
231 public virtual bool PopScope ()
237 defaultNamespace = scopes [scopePos].DefaultNamespace;
238 count = scopes [scopePos].DeclCount;
243 public virtual void PushScope ()
246 if (scopePos == scopes.Length)
249 scopes [scopePos].DefaultNamespace = defaultNamespace;
250 scopes [scopePos].DeclCount = count;
254 public virtual void RemoveNamespace (string prefix, string uri)
257 throw new ArgumentNullException ("prefix");
260 throw new ArgumentNullException ("uri");
265 for (int i = declPos; i > declPos - count; i--) {
266 if (decls [i].Prefix == prefix && decls [i].Uri == uri)
267 decls [i].Uri = null;