for TARGET_J2EE only:
[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 using System;
28 using System.IO;
29 using System.Text;
30 using System.Xml;
31 using System.Xml.Schema;
32 using System.Xml.XPath;
33
34 using XPI = System.Xml.Linq.XProcessingInstruction;
35
36 namespace System.Xml.Linq
37 {
38         internal class XNodeNavigator : XPathNavigator
39         {
40                 static readonly XAttribute attr_ns_xml = new XAttribute (XNamespace.Xmlns.GetName ("xml"), XNamespace.Xml.NamespaceName);
41
42                 XNode node;
43                 XAttribute attr;
44                 XmlNameTable name_table;
45
46                 public XNodeNavigator (XNode node, XmlNameTable nameTable)
47                 {
48                         this.node = node;
49                         this.name_table = nameTable;
50                 }
51
52                 public XNodeNavigator (XNodeNavigator other)
53                 {
54                         this.node = other.node;
55                         this.attr = other.attr;
56                         this.name_table = other.name_table;
57                 }
58
59                 public override string BaseURI {
60                         get { return node.BaseUri ?? String.Empty; }
61                 }
62
63                 public override bool CanEdit {
64                         get { return true; }
65                 }
66
67                 public override bool HasAttributes {
68                         get {
69                                 XElement el = node as XElement;
70                                 return el != null && el.HasAttributes;
71                         }
72                 }
73
74                 public override bool HasChildren {
75                         get {
76                                 XContainer c = node as XContainer;
77                                 return c != null && c.FirstNode != null;
78                         }
79                 }
80
81                 public override bool IsEmptyElement {
82                         get {
83                                 XElement el = node as XElement;
84                                 return el != null && el.IsEmpty;
85                         }
86                 }
87
88                 public override string LocalName {
89                         get {
90                                 switch (NodeType) {
91                                 case XPathNodeType.Namespace:
92                                         return attr.Name.Namespace == XNamespace.Blank ? String.Empty : attr.Name.LocalName;
93                                 case XPathNodeType.Attribute:
94                                         return attr.Name.LocalName;
95                                 case XPathNodeType.Element:
96                                         return ((XElement) node).Name.LocalName;
97                                 case XPathNodeType.ProcessingInstruction:
98                                         return ((XPI) node).Target;
99                                 default:
100                                         return String.Empty;
101                                 }
102                         }
103                 }
104
105                 public override string Name {
106                         get {
107                                 XName name = null;
108                                 switch (NodeType) {
109                                 case XPathNodeType.Attribute:
110                                         name = attr.Name;
111                                         break;
112                                 case XPathNodeType.Element:
113                                         name = ((XElement) node).Name;
114                                         break;
115                                 default:
116                                         return LocalName;
117                                 }
118                                 if (name.Namespace == XNamespace.Blank)
119                                         return name.LocalName;
120                                 XElement el = (node as XElement) ?? node.Parent;
121                                 if (el == null)
122                                         return name.LocalName;
123                                 string prefix = el.GetPrefixOfNamespace (name.Namespace);
124                                 return prefix.Length > 0 ? String.Concat (prefix, ":", name.LocalName) : name.LocalName;
125                         }
126                 }
127
128                 public override string NamespaceURI {
129                         get {
130                                 switch (NodeType) {
131                                 case XPathNodeType.Namespace:
132                                         return attr.Value;
133                                 case XPathNodeType.Attribute:
134                                         return attr.Name.NamespaceName;
135                                 case XPathNodeType.Element:
136                                         return ((XElement) node).Name.NamespaceName;
137                                 default:
138                                         return String.Empty;
139                                 }
140                         }
141                 }
142
143                 public override XmlNameTable NameTable {
144                         get { return name_table; }
145                 }
146
147                 public override XPathNodeType NodeType {
148                         get {
149                                 if (attr != null)
150                                         return  attr.IsNamespaceDeclaration ?
151                                                 XPathNodeType.Namespace :
152                                                 XPathNodeType.Attribute;
153                                 switch (node.NodeType) {
154                                 case XmlNodeType.Element:
155                                         return XPathNodeType.Element;
156                                 case XmlNodeType.Document:
157                                         return XPathNodeType.Root;
158                                 case XmlNodeType.Comment:
159                                         return XPathNodeType.Comment;
160                                 case XmlNodeType.ProcessingInstruction:
161                                         return XPathNodeType.ProcessingInstruction;
162                                 default:
163                                         return XPathNodeType.Text;
164                                 }
165                         }
166                 }
167
168                 public override string Prefix {
169                         get {
170                                 XName name = null;
171                                 switch (NodeType) {
172                                 case XPathNodeType.Attribute:
173                                         name = attr.Name;
174                                         break;
175                                 case XPathNodeType.Element:
176                                         name = ((XElement) node).Name;
177                                         break;
178                                 default:
179                                         return LocalName;
180                                 }
181                                 if (name.Namespace == XNamespace.Blank)
182                                         return String.Empty;
183                                 XElement el = (node as XElement) ?? node.Parent;
184                                 if (el == null)
185                                         return String.Empty;
186                                 return el.GetPrefixOfNamespace (name.Namespace);
187                         }
188                 }
189
190                 [MonoTODO]
191                 public override IXmlSchemaInfo SchemaInfo {
192                         get { throw new NotImplementedException (); }
193                 }
194
195                 public override object UnderlyingObject {
196                         get { return attr != null ? (object) attr : node; }
197                 }
198
199                 public override string Value {
200                         get {
201                                 if (attr != null)
202                                         return attr.Value;
203                                 else
204                                 switch (NodeType) {
205                                 case XPathNodeType.Comment:
206                                         return ((XComment) node).Value;
207                                 case XPathNodeType.ProcessingInstruction:
208                                         return ((XPI) node).Data;
209                                 case XPathNodeType.Text:
210                                         return ((XText) node).Value;
211                                 case XPathNodeType.Element:
212                                 case XPathNodeType.Root:
213                                         return GetInnerText ((XContainer) node);
214                                 }
215                                 return String.Empty;
216                         }
217                 }
218
219                 string GetInnerText (XContainer node)
220                 {
221                         StringBuilder sb = null;
222                         foreach (XNode n in node.Nodes ())
223                                 GetInnerText (n, ref sb);
224                         return sb != null ? sb.ToString () : String.Empty;
225                 }
226
227                 void GetInnerText (XNode n, ref StringBuilder sb)
228                 {
229                         switch (n.NodeType) {
230                         case XmlNodeType.Element:
231                                 foreach (XNode c in ((XElement) n).Nodes ())
232                                         GetInnerText (c, ref sb);
233                                 break;
234                         case XmlNodeType.Text:
235                         case XmlNodeType.CDATA:
236                                 if (sb == null)
237                                         sb = new StringBuilder ();
238                                 sb.Append (((XText) n).Value);
239                                 break;
240                         }
241                 }
242
243                 public override XPathNavigator Clone ()
244                 {
245                         return new XNodeNavigator (this);
246                 }
247
248                 public override bool IsSamePosition (XPathNavigator other)
249                 {
250                         XNodeNavigator nav = other as XNodeNavigator;
251                         if (nav == null || nav.node.Owner != node.Owner)
252                                 return false;
253                         return node == nav.node && attr == nav.attr;
254                 }
255
256                 public override bool MoveTo (XPathNavigator other)
257                 {
258                         XNodeNavigator nav = other as XNodeNavigator;
259                         if (nav == null || nav.node.Owner != node.Owner)
260                                 return false;
261                         node = nav.node;
262                         attr = nav.attr;
263                         return true;
264                 }
265
266                 public override bool MoveToFirstAttribute ()
267                 {
268                         XElement el = node as XElement;
269                         if (el == null || !el.HasAttributes)
270                                 return false;
271                         foreach (XAttribute a in el.Attributes ())
272                                 if (!a.IsNamespaceDeclaration) {
273                                         attr = a;
274                                         return true;
275                                 }
276                         return false;
277                 }
278
279                 public override bool MoveToFirstChild ()
280                 {
281                         XContainer c = node as XContainer;
282                         if (c == null)
283                                 return false;
284                         node = c.FirstNode;
285                         attr = null;
286                         return true;
287                 }
288
289                 public override bool MoveToFirstNamespace (XPathNamespaceScope scope)
290                 {
291                         for (XElement el = node as XElement; el != null; el = el.Parent) {
292                                 foreach (XAttribute a in el.Attributes ())
293                                         if (a.IsNamespaceDeclaration) {
294                                                 attr = a;
295                                                 return true;
296                                         }
297                                 if (scope == XPathNamespaceScope.Local)
298                                         return false;
299                         }
300                         if (scope != XPathNamespaceScope.All)
301                                 return false;
302                         attr = attr_ns_xml;
303                         return true;
304                 }
305
306                 [MonoTODO]
307                 public override bool MoveToId (string id)
308                 {
309                         return false;
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 false;
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 }