New tests.
[mono.git] / mcs / class / System.Xml.Linq / System.Xml.Linq / XNodeNavigator.cs
1 //
2 // Authors:
3 //   Atsushi Enomoto
4 //
5 // Copyright 2007 Novell (http://www.novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26
27 #if !MOONLIGHT
28
29 using System;
30 using System.IO;
31 using System.Text;
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Xml.XPath;
35
36 using XPI = System.Xml.Linq.XProcessingInstruction;
37
38 namespace System.Xml.Linq
39 {
40         internal class XNodeNavigator : XPathNavigator
41         {
42                 static readonly XAttribute attr_ns_xml = new XAttribute (XNamespace.Xmlns.GetName ("xml"), XNamespace.Xml.NamespaceName);
43
44                 XNode node;
45                 XAttribute attr;
46                 XmlNameTable name_table;
47
48                 public XNodeNavigator (XNode node, XmlNameTable nameTable)
49                 {
50                         this.node = node;
51                         this.name_table = nameTable;
52                 }
53
54                 public XNodeNavigator (XNodeNavigator other)
55                 {
56                         this.node = other.node;
57                         this.attr = other.attr;
58                         this.name_table = other.name_table;
59                 }
60
61                 public override string BaseURI {
62                         get { return node.BaseUri ?? String.Empty; }
63                 }
64
65                 public override bool CanEdit {
66                         get { return true; }
67                 }
68
69                 public override bool HasAttributes {
70                         get {
71                                 XElement el = node as XElement;
72                                 return el != null && el.HasAttributes;
73                         }
74                 }
75
76                 public override bool HasChildren {
77                         get {
78                                 XContainer c = node as XContainer;
79                                 return c != null && c.FirstNode != null;
80                         }
81                 }
82
83                 public override bool IsEmptyElement {
84                         get {
85                                 XElement el = node as XElement;
86                                 return el != null && el.IsEmpty;
87                         }
88                 }
89
90                 public override string LocalName {
91                         get {
92                                 switch (NodeType) {
93                                 case XPathNodeType.Namespace:
94                                         return attr.Name.Namespace == XNamespace.None ? String.Empty : attr.Name.LocalName;
95                                 case XPathNodeType.Attribute:
96                                         return attr.Name.LocalName;
97                                 case XPathNodeType.Element:
98                                         return ((XElement) node).Name.LocalName;
99                                 case XPathNodeType.ProcessingInstruction:
100                                         return ((XPI) node).Target;
101                                 default:
102                                         return String.Empty;
103                                 }
104                         }
105                 }
106
107                 public override string Name {
108                         get {
109                                 XName name = null;
110                                 switch (NodeType) {
111                                 case XPathNodeType.Attribute:
112                                         name = attr.Name;
113                                         break;
114                                 case XPathNodeType.Element:
115                                         name = ((XElement) node).Name;
116                                         break;
117                                 default:
118                                         return LocalName;
119                                 }
120                                 if (name.Namespace == XNamespace.None)
121                                         return name.LocalName;
122                                 XElement el = (node as XElement) ?? node.Parent;
123                                 if (el == null)
124                                         return name.LocalName;
125                                 string prefix = el.GetPrefixOfNamespace (name.Namespace);
126                                 return prefix.Length > 0 ? String.Concat (prefix, ":", name.LocalName) : name.LocalName;
127                         }
128                 }
129
130                 public override string NamespaceURI {
131                         get {
132                                 switch (NodeType) {
133                                 case XPathNodeType.Namespace:
134                                         return attr.Value;
135                                 case XPathNodeType.Attribute:
136                                         return attr.Name.NamespaceName;
137                                 case XPathNodeType.Element:
138                                         return ((XElement) node).Name.NamespaceName;
139                                 default:
140                                         return String.Empty;
141                                 }
142                         }
143                 }
144
145                 public override XmlNameTable NameTable {
146                         get { return name_table; }
147                 }
148
149                 public override XPathNodeType NodeType {
150                         get {
151                                 if (attr != null)
152                                         return  attr.IsNamespaceDeclaration ?
153                                                 XPathNodeType.Namespace :
154                                                 XPathNodeType.Attribute;
155                                 switch (node.NodeType) {
156                                 case XmlNodeType.Element:
157                                         return XPathNodeType.Element;
158                                 case XmlNodeType.Document:
159                                         return XPathNodeType.Root;
160                                 case XmlNodeType.Comment:
161                                         return XPathNodeType.Comment;
162                                 case XmlNodeType.ProcessingInstruction:
163                                         return XPathNodeType.ProcessingInstruction;
164                                 default:
165                                         return XPathNodeType.Text;
166                                 }
167                         }
168                 }
169
170                 public override string Prefix {
171                         get {
172                                 XName name = null;
173                                 switch (NodeType) {
174                                 case XPathNodeType.Attribute:
175                                         name = attr.Name;
176                                         break;
177                                 case XPathNodeType.Element:
178                                         name = ((XElement) node).Name;
179                                         break;
180                                 default:
181                                         return LocalName;
182                                 }
183                                 if (name.Namespace == XNamespace.None)
184                                         return String.Empty;
185                                 XElement el = (node as XElement) ?? node.Parent;
186                                 if (el == null)
187                                         return String.Empty;
188                                 return el.GetPrefixOfNamespace (name.Namespace);
189                         }
190                 }
191
192                 public override IXmlSchemaInfo SchemaInfo {
193                         get { return null; }
194                 }
195
196                 public override object UnderlyingObject {
197                         get { return attr != null ? (object) attr : node; }
198                 }
199
200                 public override string Value {
201                         get {
202                                 if (attr != null)
203                                         return attr.Value;
204                                 else
205                                 switch (NodeType) {
206                                 case XPathNodeType.Comment:
207                                         return ((XComment) node).Value;
208                                 case XPathNodeType.ProcessingInstruction:
209                                         return ((XPI) node).Data;
210                                 case XPathNodeType.Text:
211                                         return ((XText) node).Value;
212                                 case XPathNodeType.Element:
213                                 case XPathNodeType.Root:
214                                         return GetInnerText ((XContainer) node);
215                                 }
216                                 return String.Empty;
217                         }
218                 }
219
220                 string GetInnerText (XContainer node)
221                 {
222                         StringBuilder sb = null;
223                         foreach (XNode n in node.Nodes ())
224                                 GetInnerText (n, ref sb);
225                         return sb != null ? sb.ToString () : String.Empty;
226                 }
227
228                 void GetInnerText (XNode n, ref StringBuilder sb)
229                 {
230                         switch (n.NodeType) {
231                         case XmlNodeType.Element:
232                                 foreach (XNode c in ((XElement) n).Nodes ())
233                                         GetInnerText (c, ref sb);
234                                 break;
235                         case XmlNodeType.Text:
236                         case XmlNodeType.CDATA:
237                                 if (sb == null)
238                                         sb = new StringBuilder ();
239                                 sb.Append (((XText) n).Value);
240                                 break;
241                         }
242                 }
243
244                 public override XPathNavigator Clone ()
245                 {
246                         return new XNodeNavigator (this);
247                 }
248
249                 public override bool IsSamePosition (XPathNavigator other)
250                 {
251                         XNodeNavigator nav = other as XNodeNavigator;
252                         if (nav == null || nav.node.Owner != node.Owner)
253                                 return false;
254                         return node == nav.node && attr == nav.attr;
255                 }
256
257                 public override bool MoveTo (XPathNavigator other)
258                 {
259                         XNodeNavigator nav = other as XNodeNavigator;
260                         if (nav == null || nav.node.Owner != node.Owner)
261                                 return false;
262                         node = nav.node;
263                         attr = nav.attr;
264                         return true;
265                 }
266
267                 public override bool MoveToFirstAttribute ()
268                 {
269                         XElement el = node as XElement;
270                         if (el == null || !el.HasAttributes)
271                                 return false;
272                         foreach (XAttribute a in el.Attributes ())
273                                 if (!a.IsNamespaceDeclaration) {
274                                         attr = a;
275                                         return true;
276                                 }
277                         return false;
278                 }
279
280                 public override bool MoveToFirstChild ()
281                 {
282                         XContainer c = node as XContainer;
283                         if (c == null || c.FirstNode == null)
284                                 return false;
285                         node = c.FirstNode;
286                         attr = null;
287                         return true;
288                 }
289
290                 public override bool MoveToFirstNamespace (XPathNamespaceScope scope)
291                 {
292                         for (XElement el = node as XElement; el != null; el = el.Parent) {
293                                 foreach (XAttribute a in el.Attributes ())
294                                         if (a.IsNamespaceDeclaration) {
295                                                 attr = a;
296                                                 return true;
297                                         }
298                                 if (scope == XPathNamespaceScope.Local)
299                                         return false;
300                         }
301                         if (scope != XPathNamespaceScope.All)
302                                 return false;
303                         attr = attr_ns_xml;
304                         return true;
305                 }
306
307                 public override bool MoveToId (string id)
308                 {
309                         throw new NotSupportedException ("This XPathNavigator does not support IDs");
310                 }
311
312                 public override bool MoveToNext ()
313                 {
314                         if (node.NextNode == null)
315                                 return false;
316                         node = node.NextNode;
317                         attr = null;
318                         return true;
319                 }
320
321                 public override bool MoveToNextAttribute ()
322                 {
323                         if (attr == null)
324                                 return false;
325                         if (attr.NextAttribute == null)
326                                 return false;
327                         for (XAttribute a = attr.NextAttribute; a != null; a = a.NextAttribute)
328                                 if (!a.IsNamespaceDeclaration) {
329                                         attr = a;
330                                         return true;
331                                 }
332                         return false;
333                 }
334
335                 public override bool MoveToNextNamespace (XPathNamespaceScope scope)
336                 {
337                         if (attr == null)
338                                 return false;
339                         for (XAttribute a = attr.NextAttribute; a != null; a = a.NextAttribute)
340                                 if (a.IsNamespaceDeclaration) {
341                                         attr = a;
342                                         return true;
343                                 }
344
345                         if (scope == XPathNamespaceScope.Local)
346                                 return false;
347
348                         for (XElement el = ((XElement) attr.Parent).Parent; el != null; el = el.Parent) {
349                                 foreach (XAttribute a in el.Attributes ())
350                                         if (a.IsNamespaceDeclaration) {
351                                                 attr = a;
352                                                 return true;
353                                         }
354                         }
355                         if (scope != XPathNamespaceScope.All)
356                                 return false;
357                         attr = attr_ns_xml;
358                         return true;
359                 }
360
361                 public override bool MoveToParent ()
362                 {
363                         if (attr != null) {
364                                 attr = null;
365                                 return true;
366                         }
367                         if (node.Parent == null)
368                                 return false;
369                         node = node.Parent;
370                         return true;
371                 }
372
373                 public override bool MoveToPrevious ()
374                 {
375                         if (node.PreviousNode == null)
376                                 return false;
377                         node = node.PreviousNode;
378                         attr = null;
379                         return true;
380                 }
381
382                 public override void MoveToRoot ()
383                 {
384                         node = node.Owner;
385                         attr = null;
386                 }
387         }
388 }
389
390 #endif