2003-05-16 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[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
21                 #endregion
22
23                 #region Constructor
24
25                 public XmlNamespaceManager (XmlNameTable nameTable)
26                 {
27                         this.nameTable = nameTable;
28
29                         nameTable.Add ("xmlns");
30                         nameTable.Add ("xml");
31                         nameTable.Add (String.Empty);
32                         nameTable.Add ("http://www.w3.org/2000/xmlns/");
33                         nameTable.Add ("http://www.w3.org/XML/1998/namespace");
34
35                         PushScope ();
36                         currentScope.Namespaces = new Hashtable ();
37                         currentScope.Namespaces.Add ("xml", "http://www.w3.org/XML/1998/namespace");
38                         currentScope.Namespaces.Add ("xmlns", "http://www.w3.org/2000/xmlns/");
39                 }
40
41                 #endregion
42
43                 #region Properties
44
45                 public virtual string DefaultNamespace {
46                         get { return LookupNamespace (String.Empty); }
47                 }
48
49                 public XmlNameTable NameTable {
50                         get { return nameTable; }
51                 }
52
53                 #endregion
54
55                 #region Methods
56
57                 public virtual void AddNamespace (string prefix, string uri)
58                 {
59                         if (prefix == null)
60                                 throw new ArgumentNullException ("prefix", "Value cannot be null.");
61
62                         if (uri == null)
63                                 throw new ArgumentNullException ("uri", "Value cannot be null.");
64
65                         if (prefix.Length > 2 && prefix.Substring (0, 3).ToLower () == "xml")
66                                 throw new ArgumentException ( "Prefixes beginning with \"xml\" (regardless " + "of whether the characters are uppercase, lowercase, or some combination thereof) are reserved for use by XML.", "prefix");
67
68                         if (currentScope.Namespaces == null)
69                                 currentScope.Namespaces = new Hashtable ();
70
71                         if (prefix != String.Empty)
72                                 nameTable.Add (prefix);
73                         currentScope.Namespaces [prefix] = nameTable.Add (uri);
74                 }
75
76                 public virtual IEnumerator GetEnumerator ()
77                 {
78                         if (currentScope.Namespaces == null)
79                                 currentScope.Namespaces = new Hashtable ();
80
81                         return currentScope.Namespaces.Keys.GetEnumerator ();
82                 }
83
84                 public virtual bool HasNamespace (string prefix)
85                 {
86                         return currentScope != null && currentScope.Namespaces != null && currentScope.Namespaces.Contains (prefix);
87                 }
88
89                 public virtual string LookupNamespace (string prefix)
90                 {
91                         NamespaceScope scope = currentScope;
92
93                         while (scope != null) {
94                                 if (scope.Namespaces != null && scope.Namespaces.Contains (prefix))
95                                         return scope.Namespaces[prefix] as string;
96                                 scope = scope.Next;
97                         }
98
99                         switch (prefix) {
100                         case "xmlns":
101                                 return nameTable.Get ("http://www.w3.org/2000/xmlns/");
102                         case "xml":
103                                 return nameTable.Get ("http://www.w3.org/XML/1998/namespace");
104                         case "":
105                                 return nameTable.Get (String.Empty);
106                         }
107
108                         return null;
109                 }
110
111                 public virtual string LookupPrefix (string uri)
112                 {
113                         if (uri == null)
114                                 return null;
115
116                         NamespaceScope scope = currentScope;
117
118                         while (scope != null) 
119                         {
120                                 if (scope.Namespaces != null && scope.Namespaces.ContainsValue (uri)) {
121                                         foreach (DictionaryEntry entry in scope.Namespaces) {
122                                                 if (entry.Value.ToString() == uri)
123                                                         return nameTable.Get (entry.Key as string) as string;
124                                         }
125                                 }
126
127                                 scope = scope.Next;
128                         }
129
130                         // ECMA specifies that this method returns String.Empty
131                         // in case of no match. But actually MS.NET returns null.
132                         // For more information,see
133                         //  http://lists.ximian.com/archives/public/mono-list/2003-January/005071.html
134                         //return String.Empty;
135                         return null;
136                 }
137
138                 public virtual bool PopScope ()
139                 {
140                         if (currentScope != null)
141                                 currentScope = currentScope.Next;
142
143                         return currentScope != null;
144                 }
145
146                 public virtual void PushScope ()
147                 {
148                         NamespaceScope newScope = new NamespaceScope ();
149                         newScope.Next = currentScope;
150                         currentScope = newScope;
151                 }
152
153                 public virtual void RemoveNamespace (string prefix, string uri)
154                 {
155                         if (prefix == null)
156                                 throw new ArgumentNullException ("prefix");
157
158                         if (uri == null)
159                                 throw new ArgumentNullException ("uri");
160
161                         if (currentScope == null || currentScope.Namespaces == null)
162                                 return;
163
164                         string p = nameTable.Get (prefix);
165                         string u = nameTable.Get (uri);
166                         if (p == null || u == null)
167                                 return;
168                                 
169                         string storedUri = currentScope.Namespaces [p] as string;
170                         if (storedUri == null || storedUri != u)
171                                 return;
172
173                         currentScope.Namespaces.Remove (p);
174                 }
175
176                 #endregion
177         }
178
179         internal class NamespaceScope
180         {
181                 internal NamespaceScope Next;
182                 internal Hashtable Namespaces;
183         }
184 }