2005-05-05 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / Mono.Xml.XPath / XPathDocument2Navigator.cs
1 //\r
2 // Mono.Xml.XPath.XPathDocument2Navigator.cs\r
3 //\r
4 // Author:\r
5 //      Atsushi Enomoto <atsushi@ximian.com>\r
6 //\r
7 // (C)2004 Novell Inc.\r
8 //\r
9 // read-only XPathNavigator for editable XPathDocument.\r
10 //\r
11 \r
12 //\r
13 // Permission is hereby granted, free of charge, to any person obtaining\r
14 // a copy of this software and associated documentation files (the\r
15 // "Software"), to deal in the Software without restriction, including\r
16 // without limitation the rights to use, copy, modify, merge, publish,\r
17 // distribute, sublicense, and/or sell copies of the Software, and to\r
18 // permit persons to whom the Software is furnished to do so, subject to\r
19 // the following conditions:\r
20 // \r
21 // The above copyright notice and this permission notice shall be\r
22 // included in all copies or substantial portions of the Software.\r
23 // \r
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
31 //\r
32 #if NET_2_0\r
33 using System;\r
34 using System.Collections;\r
35 using System.Collections.Specialized;\r
36 using System.IO;\r
37 using System.Text;\r
38 using System.Xml;\r
39 using System.Xml.XPath;\r
40 \r
41 namespace Mono.Xml.XPath\r
42 {\r
43         public class XomNavigator : XPathNavigator, IHasXomNode\r
44         {\r
45                 XomRoot root;\r
46                 XomNode current;\r
47                 XomNamespace currentNS;\r
48 \r
49                 public XomNavigator (XomRoot root)\r
50                 {\r
51                         this.root = root;\r
52                         current = root;\r
53                 }\r
54 \r
55                 public override string BaseURI {\r
56                         get { return current.BaseURI; }\r
57                 }\r
58 \r
59                 public override bool IsEmptyElement {\r
60                         get { return currentNS == null && current.IsEmptyElement; }\r
61                 }\r
62 \r
63                 public override bool HasChildren {\r
64                         get { return currentNS == null && current.ChildCount != 0; }\r
65                 }\r
66 \r
67                 public override bool HasAttributes {\r
68                         get {\r
69                                 if (currentNS != null || current.NodeType != XPathNodeType.Element)\r
70                                         return false;\r
71                                 XomElement el = current as XomElement;\r
72                                 return el.AttributeCount != 0;\r
73                         }\r
74                 }\r
75 \r
76                 XomNode IHasXomNode.GetNode ()\r
77                 {\r
78                         return currentNS != null ? currentNS : current;\r
79                 }\r
80 \r
81                 public override string GetAttribute (string name, string ns)\r
82                 {\r
83                         if (currentNS != null || current.NodeType != XPathNodeType.Element)\r
84                                 return String.Empty;\r
85                         XomElement el = current as XomElement;\r
86                         XomAttribute attr = el.GetAttribute (name, ns);\r
87                         return attr != null ? attr.Value : String.Empty;\r
88                 }\r
89 \r
90                 public override XmlNameTable NameTable {\r
91                         get { return current.Root.NameTable; }\r
92                 }\r
93 \r
94                 public override string LocalName {\r
95                         get { return current.LocalName; }\r
96                 }\r
97 \r
98                 public override string Name {\r
99                         get { return current.PrefixedName; }\r
100                 }\r
101 \r
102                 public override string NamespaceURI {\r
103                         get { return current.Namespace; }\r
104                 }\r
105 \r
106                 public override string Prefix {\r
107                         get { return current.Prefix; }\r
108                 }\r
109 \r
110                 public override string Value {\r
111                         get {\r
112                                 switch (NodeType) {\r
113                                 case XPathNodeType.Attribute:\r
114                                 case XPathNodeType.Comment:\r
115                                 case XPathNodeType.ProcessingInstruction:\r
116                                         return current.Value;\r
117                                 case XPathNodeType.Text:\r
118                                 case XPathNodeType.Whitespace:\r
119                                 case XPathNodeType.SignificantWhitespace:\r
120                                         string value = current.Value;\r
121                                         for (XomNode n = current.NextSibling; n != null; n = n.NextSibling) {\r
122                                                 switch (n.NodeType) {\r
123                                                 case XPathNodeType.Text:\r
124                                                 case XPathNodeType.Whitespace:\r
125                                                 case XPathNodeType.SignificantWhitespace:\r
126                                                         value += n.Value;\r
127                                                         continue;\r
128                                                 }\r
129                                                 break;\r
130                                         }\r
131                                         return value;\r
132                                 case XPathNodeType.Element:\r
133                                 case XPathNodeType.Root:\r
134                                         return current.Value;\r
135                                 case XPathNodeType.Namespace:\r
136                                         return currentNS.Value;\r
137                                 }\r
138                                 return String.Empty;\r
139                         }\r
140                 }\r
141 \r
142                 public override string XmlLang {\r
143                         get { return current.XmlLang; }\r
144                 }\r
145 \r
146                 public override XPathNodeType NodeType {\r
147                         get { return current.NodeType; }\r
148                 }\r
149 \r
150                 public override XPathNavigator Clone ()\r
151                 {\r
152                         XomNavigator n = new XomNavigator (root);\r
153                         n.current = current;\r
154                         n.currentNS = currentNS;\r
155                         return n;\r
156                 }\r
157 \r
158                 public override void MoveToRoot ()\r
159                 {\r
160                         current = root;\r
161                         currentNS = null;\r
162                 }\r
163 \r
164                 public override bool MoveToParent ()\r
165                 {\r
166                         if (currentNS != null) {\r
167                                 currentNS = null;\r
168                                 return true;\r
169                         }\r
170                         XomParentNode parent = current.Parent;\r
171                         if (parent == null)\r
172                                 return false;\r
173                         current = parent;\r
174                         return true;\r
175                 }\r
176 \r
177                 public override bool MoveToFirstChild ()\r
178                 {\r
179                         if (currentNS != null || current.NodeType == XPathNodeType.Attribute || current.ChildCount == 0)\r
180                                 return false;\r
181                         current = current.FirstChild;\r
182                         return true;\r
183                 }\r
184 \r
185                 public override bool MoveToFirst ()\r
186                 {\r
187                         if (currentNS != null || current.NodeType == XPathNodeType.Attribute)\r
188                                 return false;\r
189                         XomParentNode pn = current.Parent;\r
190                         if (pn == null)\r
191                                 return false;\r
192                         XomNode n = pn.FirstChild;\r
193                         if (n == current)\r
194                                 return false;\r
195                         current = n;\r
196                         return true;\r
197                 }\r
198 \r
199                 public override bool MoveToFirstAttribute ()\r
200                 {\r
201                         if (currentNS != null)\r
202                                 return false;\r
203                         XomElement el = current as XomElement;\r
204                         if (el == null)\r
205                                 return false;\r
206                         if (el.AttributeCount == 0)\r
207                                 return false;\r
208                         current = el.GetAttribute (0);\r
209                         return true;\r
210                 }\r
211 \r
212                 public override bool MoveToNextAttribute ()\r
213                 {\r
214                         XomAttribute attr = current as XomAttribute;\r
215                         if (attr == null)\r
216                                 return false;\r
217                         XomElement owner = attr.Parent as XomElement;\r
218                         if (owner == null)\r
219                                 return false;\r
220                         XomAttribute next = owner.GetNextAttribute (attr);\r
221                         if (next == null)\r
222                                 return false;\r
223                         current = next;\r
224                         return true;\r
225                 }\r
226 \r
227                 public override bool MoveToAttribute (string name, string ns)\r
228                 {\r
229                         if (currentNS != null || current.NodeType != XPathNodeType.Element)\r
230                                 return false;\r
231                         XomElement el = current as XomElement;\r
232                         XomAttribute attr = el.GetAttribute (name, ns);\r
233                         if (attr == null)\r
234                                 return false;\r
235                         current = attr;\r
236                         return true;\r
237                 }\r
238 \r
239                 public override string GetNamespace (string prefix)\r
240                 {\r
241                         if (currentNS != null)\r
242                                 return String.Empty;\r
243                         XomNamespace n = GetXomNamespace (prefix);\r
244                         if (n == null)\r
245                                 return String.Empty;\r
246                         else\r
247                                 return n.Namespace;\r
248                 }\r
249                 \r
250                 private XomNamespace GetXomNamespace (string prefix)\r
251                 {\r
252                         if (current.NodeType != XPathNodeType.Element)\r
253                                 return null;\r
254                         if (prefix == "xml")\r
255                                 return XomNamespace.Xml;\r
256                         XomElement el = current as XomElement;\r
257                         do {\r
258                                 XomNamespace n = el.GetLocalNamespace (prefix);\r
259                                 if (n != null)\r
260                                         return n;\r
261                                 el = el.Parent as XomElement;\r
262                         } while (el != null);\r
263                         return null;\r
264                 }\r
265 \r
266                 public override bool MoveToNamespace (string prefix)\r
267                 {\r
268                         if (currentNS != null)\r
269                                 return false;\r
270                         XomNamespace n = GetXomNamespace (prefix);\r
271                         if (n == null)\r
272                                 return false;\r
273                         currentNS = n;\r
274                         return true;\r
275                 }\r
276 \r
277                 public override bool MoveToFirstNamespace (XPathNamespaceScope scope)\r
278                 {\r
279                         if (currentNS != null || current.NodeType != XPathNodeType.Element)\r
280                                 return false;\r
281                         XomElement el = current as XomElement;\r
282                         XomNamespace n = null;\r
283                         switch (scope) {\r
284                         case XPathNamespaceScope.Local:\r
285                                 if (el.NamespaceCount > 0)\r
286                                         n = el.GetLocalNamespace (0);\r
287                                 break;\r
288                         default:\r
289                                 do {\r
290                                         if (el.NamespaceCount > 0) {\r
291                                                 n = el.GetLocalNamespace (0);\r
292                                                 break;\r
293                                         }\r
294                                         el = el.Parent as XomElement;\r
295                                 } while (el != null);\r
296                                 break;\r
297                         }\r
298                         if (n != null) {\r
299                                 currentNS = n;\r
300                                 return true;\r
301                         }\r
302                         else if (scope == XPathNamespaceScope.All) {\r
303                                 currentNS = XomNamespace.Xml;\r
304                                 return true;\r
305                         }\r
306                         return false;\r
307                 }\r
308 \r
309                 public override bool MoveToNextNamespace (XPathNamespaceScope scope)\r
310                 {\r
311                         if (currentNS == null || currentNS == XomNamespace.Xml)\r
312                                 return false;\r
313                         XomElement el = currentNS.Parent as XomElement;\r
314                         XomNamespace n = el.GetNextLocalNamespace (currentNS);\r
315                         if (n != null) {\r
316                                 currentNS = n;\r
317                                 return true;\r
318                         }\r
319                         switch (scope) {\r
320                         case XPathNamespaceScope.Local:\r
321                                 return false;\r
322                         default:\r
323                                 el = el.Parent as XomElement;\r
324                                 while (el != null) {\r
325                                         if (el.NamespaceCount > 0) {\r
326                                                 n = el.GetLocalNamespace (0);\r
327                                                 break;\r
328                                         }\r
329                                         el = el.Parent as XomElement;\r
330                                 }\r
331                                 break;\r
332                         }\r
333                         if (n != null) {\r
334                                 currentNS = n;\r
335                                 return true;\r
336                         }\r
337                         else if (scope == XPathNamespaceScope.All) {\r
338                                 currentNS = XomNamespace.Xml;\r
339                                 return true;\r
340                         }\r
341                         return false;\r
342                 }\r
343 \r
344                 public override bool MoveToNext ()\r
345                 {\r
346                         if (currentNS != null)\r
347                                 return false;\r
348                         switch (NodeType) {\r
349                         case XPathNodeType.Text:\r
350                         case XPathNodeType.SignificantWhitespace:\r
351                         case XPathNodeType.Whitespace:\r
352                                 for (XomNode t = current.NextSibling; t != null; t = t.NextSibling) {\r
353                                         switch (t.NodeType) {\r
354                                         case XPathNodeType.Text:\r
355                                         case XPathNodeType.SignificantWhitespace:\r
356                                         case XPathNodeType.Whitespace:\r
357                                                 continue;\r
358                                         }\r
359                                         current = t;\r
360                                         return true;\r
361                                 }\r
362                                 return false;\r
363                         default:\r
364                                 XomNode n = current.NextSibling;\r
365                                 if (n == null)\r
366                                         return false;\r
367                                 current = n;\r
368                                 return true;\r
369                         }\r
370                 }\r
371 \r
372                 public override bool MoveToPrevious ()\r
373                 {\r
374                         if (currentNS != null)\r
375                                 return false;\r
376                         XomNode n = current.PreviousSibling;\r
377                         if (n == null)\r
378                                 return false;\r
379                         current = n;\r
380 \r
381                         switch (NodeType) {\r
382                         case XPathNodeType.Text:\r
383                         case XPathNodeType.SignificantWhitespace:\r
384                         case XPathNodeType.Whitespace:\r
385                                 for (XomNode t = current.PreviousSibling; t != null; t = t.NextSibling) {\r
386                                         switch (t.NodeType) {\r
387                                         case XPathNodeType.Text:\r
388                                         case XPathNodeType.SignificantWhitespace:\r
389                                         case XPathNodeType.Whitespace:\r
390                                                 current = t;\r
391                                                 continue;\r
392                                         }\r
393                                         break;\r
394                                 }\r
395                                 break;\r
396                         }\r
397 \r
398                         return true;\r
399                 }\r
400 \r
401                 public override bool IsSamePosition (XPathNavigator other)\r
402                 {\r
403                         XomNavigator xom = other as XomNavigator;\r
404                         if (xom == null || root != xom.root)\r
405                                 return false;\r
406                         return current == xom.current && currentNS == xom.currentNS;\r
407                 }\r
408 \r
409                 public override bool MoveTo (XPathNavigator other)\r
410                 {\r
411                         XomNavigator xom = other as XomNavigator;\r
412                         if (xom == null)\r
413                                 return false;\r
414                         current = xom.current;\r
415                         currentNS = xom.currentNS;\r
416                         return true;\r
417                 }\r
418 \r
419                 public override bool MoveToId (string id)\r
420                 {\r
421                         XomElement el = root.GetIdenticalNode (id);\r
422                         if (el == null)\r
423                                 return false;\r
424                         current = el;\r
425                         return true;\r
426                 }\r
427         }\r
428 }\r
429 #endif\r