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