*** empty log message ***
[mono.git] / mcs / class / System.XML / System.Xml / XmlNamespaceManager.cs
1 //
2 // XmlNamespaceManager.cs
3 //
4 // Author:
5 //   Jason Diamond (jason@injektilo.org)
6 //
7 // (C) 2001 Jason Diamond  http://injektilo.org/
8 //
9
10 using System.Collections;
11
12 namespace System.Xml
13 {
14         public class XmlNamespaceManager : IEnumerable
15         {
16                 #region Fields
17
18                 private XmlNameTable nameTable;
19                 private NamespaceScope currentScope;
20                 internal const string XmlnsXml = "http://www.w3.org/XML/1998/namespace";
21                 internal const string XmlnsXmlns = "http://www.w3.org/2000/xmlns/";
22
23                 #endregion
24
25                 #region Constructor
26
27                 internal XmlNamespaceManager () {}
28                 public XmlNamespaceManager (XmlNameTable nameTable)
29                 {
30                         this.nameTable = nameTable;
31
32                         nameTable.Add ("xmlns");
33                         nameTable.Add ("xml");
34                         nameTable.Add (String.Empty);
35                         nameTable.Add (XmlnsXmlns);
36                         nameTable.Add (XmlnsXml);
37
38                         PushScope ();
39                         currentScope.Namespaces = new Hashtable ();
40                         currentScope.Namespaces.Add ("", "");
41                         currentScope.Namespaces.Add ("xml", XmlnsXml);
42                         currentScope.Namespaces.Add ("xmlns", XmlnsXmlns);
43                 }
44
45                 #endregion
46
47                 #region Properties
48
49                 public virtual string DefaultNamespace {
50                         get { return LookupNamespace (String.Empty); }
51                 }
52
53                 public XmlNameTable NameTable {
54                         get { return nameTable; }
55                 }
56
57                 #endregion
58
59                 #region Methods
60
61                 public virtual void AddNamespace (string prefix, string uri)
62                 {
63                         if (prefix == null)
64                                 throw new ArgumentNullException ("prefix", "Value cannot be null.");
65
66                         if (uri == null)
67                                 throw new ArgumentNullException ("uri", "Value cannot be null.");
68
69                         IsValidDeclaration (prefix, uri, true);
70
71                         if (currentScope.Namespaces == null)
72                                 currentScope.Namespaces = new Hashtable ();
73
74                         if (prefix != String.Empty)
75                                 nameTable.Add (prefix);
76                         currentScope.Namespaces [prefix] = nameTable.Add (uri);
77                 }
78
79                 internal static string IsValidDeclaration (string prefix, string uri, bool throwException)
80                 {
81                         string message = null;
82                         if (prefix == "xml" && uri != XmlnsXml)
83                                 message = String.Format ("Prefix \"xml\" is only allowed to the fixed uri \"{0}\"", XmlnsXml);
84                         else if (uri == XmlnsXml)
85                                 message = String.Format ("Namespace URI \"{0}\" can only be declared with the fixed prefix \"xml\"", XmlnsXml);
86                         if (message == null && prefix == "xmlns")
87                                 message = "Declaring prefix named \"xmlns\" is not allowed to any namespace.";
88                         if (message == null && uri == XmlnsXmlns)
89                                 message = String.Format ("Namespace URI \"{0}\" cannot be declared with any namespace.", XmlnsXmlns);
90                         if (message != null && throwException)
91                                 throw new ArgumentException (message);
92                         else
93                                 return message;
94                 }
95
96                 public virtual IEnumerator GetEnumerator ()
97                 {
98                         /*
99                         if (currentScope.Namespaces == null)
100                                 currentScope.Namespaces = new Hashtable ();
101
102                         return currentScope.Namespaces.Keys.GetEnumerator ();
103                         */
104
105                         // In fact it returns such table's enumerator that contains all the namespaces.
106                         // while HasNamespace() ignores pushed namespaces.
107                         Hashtable ht = new Hashtable ();
108                         NamespaceScope scope = currentScope;
109
110                         while (scope != null) {
111                                 if (scope.Namespaces != null) {
112                                         IEnumerator e = scope.Namespaces.Keys.GetEnumerator ();
113                                         while (e.MoveNext ()) {
114                                                 if (!ht.ContainsKey (e.Current))
115                                                         ht.Add (e.Current, scope.Namespaces [e.Current]);
116                                         }
117                                 }
118                                 scope = scope.Next;
119                         }
120                         return ht.Keys.GetEnumerator ();
121                 }
122
123                 public virtual bool HasNamespace (string prefix)
124                 {
125                         return currentScope != null && currentScope.Namespaces != null && currentScope.Namespaces.Contains (prefix);
126                 }
127
128                 public virtual string LookupNamespace (string prefix)
129                 {
130                         NamespaceScope scope = currentScope;
131
132                         while (scope != null) {
133                                 if (scope.Namespaces != null) {
134                                         string s = scope.Namespaces [prefix] as string;
135                                         if (s != null) return s;
136                                 }
137                                 scope = scope.Next;
138                         }
139
140                         switch (prefix) {
141                         case "xmlns":
142                                 return nameTable.Get (XmlnsXmlns);
143                         case "xml":
144                                 return nameTable.Get (XmlnsXml);
145                         case "":
146                                 return nameTable.Get (String.Empty);
147                         }
148
149                         return null;
150                 }
151
152                 public virtual string LookupPrefix (string uri)
153                 {
154                         if (uri == null)
155                                 return null;
156
157                         NamespaceScope scope = currentScope;
158
159                         while (scope != null) 
160                         {
161                                 if (scope.Namespaces != null && scope.Namespaces.ContainsValue (uri)) {
162                                         foreach (DictionaryEntry entry in scope.Namespaces) {
163                                                 if (entry.Value.ToString() == uri)
164                                                         return nameTable.Get (entry.Key as string) as string;
165                                         }
166                                 }
167
168                                 scope = scope.Next;
169                         }
170
171                         // ECMA specifies that this method returns String.Empty
172                         // in case of no match. But actually MS.NET returns null.
173                         // For more information,see
174                         //  http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
175                         //return String.Empty;
176                         return null;
177                 }
178
179                 public virtual bool PopScope ()
180                 {
181                         if (currentScope != null)
182                                 currentScope = currentScope.Next;
183
184                         return currentScope != null;
185                 }
186
187                 public virtual void PushScope ()
188                 {
189                         NamespaceScope newScope = new NamespaceScope ();
190                         newScope.Next = currentScope;
191                         currentScope = newScope;
192                 }
193
194                 public virtual void RemoveNamespace (string prefix, string uri)
195                 {
196                         if (prefix == null)
197                                 throw new ArgumentNullException ("prefix");
198
199                         if (uri == null)
200                                 throw new ArgumentNullException ("uri");
201
202                         if (currentScope == null || currentScope.Namespaces == null)
203                                 return;
204
205                         string p = nameTable.Get (prefix);
206                         string u = nameTable.Get (uri);
207                         if (p == null || u == null)
208                                 return;
209                                 
210                         string storedUri = currentScope.Namespaces [p] as string;
211                         if (storedUri == null || storedUri != u)
212                                 return;
213
214                         currentScope.Namespaces.Remove (p);
215                 }
216
217                 #endregion
218         }
219
220         internal class NamespaceScope
221         {
222                 internal NamespaceScope Next;
223                 internal Hashtable Namespaces;
224         }
225 }