2007-09-27 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlDocumentNavigator.cs
1 //
2 // System.Xml.XmlDocumentNavigator
3 //
4 // Authors:
5 //   Jason Diamond <jason@injektilo.org>
6 //   Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
7 //
8 // (C) 2002 Jason Diamond
9 // (C) 2003 Atsushi Enomoto
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Xml;
36 using System.Xml.Schema;
37 using System.Xml.XPath;
38
39 namespace System.Xml
40 {
41         internal class XmlDocumentNavigator : XPathNavigator, IHasXmlNode
42         {
43                 #region Constructors
44
45                 internal XmlDocumentNavigator (XmlNode node)
46                         : this (node, null)
47                 {
48                         nsNodeXml = document.CreateAttribute ("xmlns", "xml", Xmlns);
49                         nsNodeXml.Value = XmlnsXML;
50                         if (node.NodeType == XmlNodeType.Attribute && node.NamespaceURI == XmlNamespaceManager.XmlnsXmlns) {
51                                 nsNode = (XmlAttribute) node; 
52                                 node = nsNode.OwnerElement;
53                         }
54                 }
55
56                 private XmlDocumentNavigator (XmlNode node, XmlAttribute nsNodeXml)
57                 {
58                         this.node = node;
59                         this.document = node.NodeType == XmlNodeType.Document ?
60                                 node as XmlDocument : node.OwnerDocument;
61                         this.nsNodeXml = nsNodeXml;
62                 }
63
64                 #endregion
65
66                 #region Fields
67                 private const string Xmlns = "http://www.w3.org/2000/xmlns/";
68                 private const string XmlnsXML = "http://www.w3.org/XML/1998/namespace";
69
70                 private XmlAttribute nsNodeXml;
71                 private XmlNode node;
72                 private XmlDocument document;
73                 // Current namespace node (ancestor's attribute of current node).
74                 private XmlAttribute nsNode;
75                 private ArrayList iteratedNsNames;
76                 #endregion
77
78                 #region Properties
79
80                 public override string BaseURI {
81                         get {
82                                 return node.BaseURI;
83                         }
84                 }
85
86                 public override bool HasAttributes {
87                         get {
88                                 if (NsNode != null)
89                                         return false;
90
91                                 XmlElement el = node as XmlElement;
92                                 if (el == null || !el.HasAttributes)
93                                         return false;
94
95                                 for (int i = 0; i < node.Attributes.Count; i++)
96                                         if (node.Attributes [i].NamespaceURI != Xmlns)
97                                                 return true;
98                                 return false;
99                         }
100                 }
101
102                 public override bool HasChildren {
103                         get {
104                                 if (NsNode != null)
105                                         return false;
106
107                                 XPathNodeType nodeType = NodeType;
108                                 bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
109                                 return canHaveChildren && GetFirstChild (node) != null;
110                         }
111                 }
112
113                 public override bool IsEmptyElement {
114                         get {
115                                 if (NsNode != null)
116                                         return false;
117
118                                 return node.NodeType == XmlNodeType.Element 
119                                         && ((XmlElement) node).IsEmpty;
120                         }
121                 }
122
123                 public XmlAttribute NsNode {
124                         get { return nsNode; }
125                         set {
126                                 if (value == null)
127                                         iteratedNsNames = null;
128                                 else
129                                 {
130                                         if (iteratedNsNames == null)
131                                                 iteratedNsNames = new ArrayList();
132                                         else
133                                         {
134                                                 if (iteratedNsNames.IsReadOnly)
135                                                         iteratedNsNames = new ArrayList(iteratedNsNames);
136                                         }
137                                         iteratedNsNames.Add (value.Name);
138                                 }
139                                 nsNode = value;
140                         }
141                 }
142
143                 public override string LocalName {
144                         get {
145                                 XmlAttribute nsNode = NsNode;
146                                 if (nsNode != null) {
147                                         if (nsNode == nsNodeXml)
148                                                 return "xml";
149                                         else
150                                                 return (nsNode.Name == "xmlns") ? String.Empty : nsNode.LocalName;
151                                 }
152
153                                 XPathNodeType nodeType = NodeType;
154                                 bool canHaveName = 
155                                         nodeType == XPathNodeType.Element || 
156                                         nodeType == XPathNodeType.Attribute || 
157                                         nodeType == XPathNodeType.ProcessingInstruction ||
158                                         nodeType == XPathNodeType.Namespace;
159                                 return canHaveName ? node.LocalName : String.Empty;
160                         }
161                 }
162
163                 public override string Name {
164                         get {
165                                 if (NsNode != null)
166                                         return LocalName;
167
168                                 XPathNodeType nodeType = NodeType;
169                                 bool canHaveName = 
170                                         nodeType == XPathNodeType.Element || 
171                                         nodeType == XPathNodeType.Attribute || 
172                                         nodeType == XPathNodeType.ProcessingInstruction ||
173                                         nodeType == XPathNodeType.Namespace;
174                                 return canHaveName ? node.Name : String.Empty;
175                         }
176                 }
177
178                 public override string NamespaceURI {
179                         get { return (NsNode != null) ? String.Empty : node.NamespaceURI; }
180                 }
181
182                 public override XmlNameTable NameTable {
183                         get {
184                                 return document.NameTable;
185                         }
186                 }
187
188                 public override XPathNodeType NodeType {
189                         get {
190                                 if (NsNode != null)
191                                         return XPathNodeType.Namespace;
192                                 XmlNode n = node;
193                                 bool sw = false;
194                                 do {
195                                         switch (n.NodeType) {
196                                         case XmlNodeType.SignificantWhitespace:
197                                                 sw = true;
198                                                 n = GetNextSibling (n);
199                                                 break;
200                                         case XmlNodeType.Whitespace:
201                                                 n = GetNextSibling (n);
202                                                 break;
203                                         case XmlNodeType.Text:
204                                         case XmlNodeType.CDATA:
205                                                 return XPathNodeType.Text;
206                                         default:
207                                                 n = null;
208                                                 break;
209                                         }
210                                 } while (n != null);
211                                 return sw ?
212                                         XPathNodeType.SignificantWhitespace :
213                                         node.XPathNodeType;
214                         }
215                 }
216
217                 public override string Prefix {
218                         get { return (NsNode != null) ? String.Empty : node.Prefix; }
219                 }
220
221 #if NET_2_0
222                 public override IXmlSchemaInfo SchemaInfo {
223                         get { return NsNode != null ? null : node.SchemaInfo; }
224                 }
225
226                 public override object UnderlyingObject {
227                         get { return node; }
228                 }
229 #endif
230
231                 public override string Value {
232                         get {
233                                 switch (NodeType) {
234                                 case XPathNodeType.Attribute:
235                                 case XPathNodeType.Comment:
236                                 case XPathNodeType.ProcessingInstruction:
237                                         return node.Value;
238                                 case XPathNodeType.Text:
239                                 case XPathNodeType.Whitespace:
240                                 case XPathNodeType.SignificantWhitespace:
241                                         string value = node.Value;
242                                         for (XmlNode n = GetNextSibling (node); n != null; n = GetNextSibling (n)) {
243                                                 switch (n.XPathNodeType) {
244                                                 case XPathNodeType.Text:
245                                                 case XPathNodeType.Whitespace:
246                                                 case XPathNodeType.SignificantWhitespace:
247                                                         value += n.Value;
248                                                         continue;
249                                                 }
250                                                 break;
251                                         }
252                                         return value;
253                                 case XPathNodeType.Element:
254                                 case XPathNodeType.Root:
255                                         return node.InnerText;
256                                 case XPathNodeType.Namespace:
257                                         return NsNode == nsNodeXml ? XmlnsXML : NsNode.Value;
258                                 }
259                                 return String.Empty;
260                         }
261                 }
262
263                 public override string XmlLang {
264                         get {
265                                 return node.XmlLang;
266                         }
267                 }
268
269                 #endregion
270
271                 #region Methods
272
273                 private bool CheckNsNameAppearance (string name, string ns)
274                 {
275                         if (iteratedNsNames != null && iteratedNsNames.Contains (name))
276                                 return true;
277                         // default namespace erasure - just add name and never return this node
278                         if (ns == String.Empty) {
279                                 if (iteratedNsNames == null)
280                                         iteratedNsNames = new ArrayList();
281                                 else
282                                 {
283                                         if (iteratedNsNames.IsReadOnly)
284                                                 iteratedNsNames = new ArrayList(iteratedNsNames);
285                                 }
286                                 iteratedNsNames.Add ("xmlns");
287                                 return true;
288                         }
289
290                         return false;
291                 }
292
293                 public override XPathNavigator Clone ()
294                 {
295                         XmlDocumentNavigator clone = new XmlDocumentNavigator (node, nsNodeXml);
296                         clone.nsNode = nsNode;
297                         clone.iteratedNsNames = (iteratedNsNames == null || iteratedNsNames.IsReadOnly) ? iteratedNsNames : ArrayList.ReadOnly(iteratedNsNames);
298                         return clone;
299                 }
300
301                 public override string GetAttribute (string localName, string namespaceURI)
302                 {
303                         if (HasAttributes) {
304                                 XmlElement el = Node as XmlElement;
305                                 return el != null ? el.GetAttribute (localName, namespaceURI) : String.Empty;
306                         }
307                         return String.Empty;
308                 }
309
310                 public override string GetNamespace (string name)
311                 {
312                         // MSDN says "String.Empty if a matching namespace 
313                         // node is not found or if the navigator is not 
314                         // positioned on an element node", but in fact it
315                         // returns actual namespace for the other nodes.
316                         return Node.GetNamespaceOfPrefix (name);
317                 }
318
319                 public override bool IsDescendant (XPathNavigator other)
320                 {
321                         if (NsNode != null)
322                                 return false;
323                         XmlDocumentNavigator o = other as XmlDocumentNavigator;
324                         if (o == null)
325                                 return false;
326                         XmlNode n =
327                                 o.node.NodeType == XmlNodeType.Attribute ?
328                                 ((XmlAttribute) o.node).OwnerElement :
329                                 o.node.ParentNode;
330                         for (;n != null; n = n.ParentNode)
331                                 if (n == node)
332                                         return true;
333                         return false;
334                 }
335
336                 public override bool IsSamePosition (XPathNavigator other)
337                 {
338                         XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
339                         if (otherDocumentNavigator != null)
340                                 return node == otherDocumentNavigator.node
341                                         && NsNode == otherDocumentNavigator.NsNode;
342                         return false;
343                 }
344
345                 public override bool MoveTo (XPathNavigator other)
346                 {
347                         XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
348                         if (otherDocumentNavigator != null) {
349                                 if (document == otherDocumentNavigator.document) {
350                                         node = otherDocumentNavigator.node;
351                                         NsNode = otherDocumentNavigator.NsNode;
352                                         return true;
353                                 }
354                         }
355                         return false;
356                 }
357
358                 public override bool MoveToAttribute (string localName, string namespaceURI)
359                 {
360                         if (HasAttributes) {
361                                 XmlAttribute attr = node.Attributes [localName, namespaceURI];
362                                 if (attr != null) {
363                                         node = attr;
364                                         NsNode = null;
365                                         return true;
366                                 }
367                         }
368                         return false;
369                 }
370
371 #if NET_2_0
372 #else
373                 public override bool MoveToFirst ()
374                 {
375                         return MoveToFirstImpl ();
376                 }
377 #endif
378
379                 public override bool MoveToFirstAttribute ()
380                 {
381                         if (NodeType == XPathNodeType.Element) {
382                                 XmlElement el = node as XmlElement;
383                                 if (!el.HasAttributes)
384                                         return false;
385                                 for (int i = 0; i < node.Attributes.Count; i++) {
386                                         XmlAttribute attr = node.Attributes [i];
387                                         if (attr.NamespaceURI != Xmlns) {
388                                                 node = attr;
389                                                 NsNode = null;
390                                                 return true;
391                                         }
392                                 }
393                         }
394                         return false;
395                 }
396
397                 public override bool MoveToFirstChild ()
398                 {
399                         if (HasChildren) {
400                                 XmlNode n = GetFirstChild (node);
401                                 if (n == null)
402                                         return false;
403                                 node = n;
404                                 return true;
405                         }
406                         return false;
407                 }
408
409                 public override bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope)
410                 {
411                         if (NodeType != XPathNodeType.Element)
412                                 return false;
413                         XmlElement el = node as XmlElement;
414                         do {
415                                 if (el.HasAttributes) {
416                                         for (int i = 0; i < el.Attributes.Count; i++) {
417                                                 XmlAttribute attr = el.Attributes [i];
418                                                 if (attr.NamespaceURI == Xmlns) {
419                                                         if (CheckNsNameAppearance (attr.Name, attr.Value))
420                                                                 continue;
421                                                         NsNode = attr;
422                                                         return true;
423                                                 }
424                                         }
425                                 }
426                                 if (namespaceScope == XPathNamespaceScope.Local)
427                                         return false;
428                                 el = GetParentNode (el) as XmlElement;
429                         } while (el != null);
430
431                         if (namespaceScope == XPathNamespaceScope.All) {
432                                 if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
433                                         return false;
434                                 NsNode = nsNodeXml;
435                                 return true;
436                         }
437                         else
438                                 return false;
439                 }
440
441                 public override bool MoveToId (string id)
442                 {
443                         XmlElement eltNew = document.GetElementById (id);
444                         if (eltNew == null)
445                                 return false;
446
447                         node = eltNew;
448                         return true;
449                 }
450
451                 public override bool MoveToNamespace (string name)
452                 {
453                         if (name == "xml") {
454                                 NsNode = nsNodeXml;
455                                 return true;
456                         }
457
458                         if (NodeType != XPathNodeType.Element)
459                                 return false;
460
461                         XmlElement el = node as XmlElement;
462                         do {
463                                 if (el.HasAttributes) {
464                                         for (int i = 0; i < el.Attributes.Count; i++) {
465                                                 XmlAttribute attr = el.Attributes [i];
466                                                 if (attr.NamespaceURI == Xmlns && attr.Name == name) {
467                                                         NsNode = attr;
468                                                         return true;
469                                                 }
470                                         }
471                                 }
472                                 el = GetParentNode (node) as XmlElement;
473                         } while (el != null);
474                         return false;
475                 }
476
477                 public override bool MoveToNext ()
478                 {
479                         if (NsNode != null)
480                                 return false;
481
482                         XmlNode n = node;
483                         if (NodeType == XPathNodeType.Text) {
484                                 do {
485                                         n = GetNextSibling (n);
486                                         if (n == null)
487                                                 return false;
488                                         switch (n.NodeType) {
489                                         case XmlNodeType.CDATA:
490                                         case XmlNodeType.SignificantWhitespace:
491                                         case XmlNodeType.Text:
492                                         case XmlNodeType.Whitespace:
493                                                 continue;
494                                         default:
495                                                 break;
496                                         }
497                                         break;
498                                 } while (true);
499                         }
500                         else
501                                 n = GetNextSibling (n);
502                         if (n == null)
503                                 return false;
504                         node = n;
505                         return true;
506                 }
507
508                 public override bool MoveToNextAttribute ()
509                 {
510                         if (node == null)
511                                 return false;
512                         if (NodeType != XPathNodeType.Attribute)
513                                 return false;
514
515                         // Find current attribute.
516                         int pos = 0;
517                         XmlElement owner = ((XmlAttribute) node).OwnerElement;
518                         if (owner == null)
519                                 return false;
520
521                         int count = owner.Attributes.Count;
522                         for(; pos < count; pos++)
523                                 if (owner.Attributes [pos] == node)
524                                         break;
525                         if (pos == count)
526                                 return false;   // Where is current attribute? Maybe removed.
527
528                         // Find next attribute.
529                         for(pos++; pos < count; pos++) {
530                                 if (owner.Attributes [pos].NamespaceURI != Xmlns) {
531                                         node = owner.Attributes [pos];
532                                         NsNode = null;
533                                         return true;
534                                 }
535                         }
536                         return false;
537                 }
538
539                 public override bool MoveToNextNamespace (XPathNamespaceScope namespaceScope)
540                 {
541                         if (NsNode == nsNodeXml)
542                                 // Current namespace is "xml", so there should be no more namespace nodes.
543                                 return false;
544
545                         if (NsNode == null)
546                                 return false;
547
548                         // Get current attribute's position.
549                         int pos = 0;
550                         XmlElement owner = ((XmlAttribute) NsNode).OwnerElement;
551                         if (owner == null)
552                                 return false;
553
554                         int count = owner.Attributes.Count;
555                         for(; pos < count; pos++)
556                                 if (owner.Attributes [pos] == NsNode)
557                                         break;
558                         if (pos == count)
559                                 return false;   // Where is current attribute? Maybe removed.
560
561                         // Find next namespace from the same element as current ns node.
562                         for(pos++; pos < count; pos++) {
563                                 if (owner.Attributes [pos].NamespaceURI == Xmlns) {
564                                         XmlAttribute a = owner.Attributes [pos];
565                                         if (CheckNsNameAppearance (a.Name, a.Value))
566                                                 continue;
567                                         NsNode = a;
568                                         return true;
569                                 }
570                         }
571
572                         // If not found more, then find from ancestors.
573                         // But if scope is Local, then it returns false here.
574                         if (namespaceScope == XPathNamespaceScope.Local)
575                                 return false;
576                         owner = GetParentNode (owner) as XmlElement;
577                         while (owner != null) {
578                                 if (owner.HasAttributes) {
579                                         for (int i = 0; i < owner.Attributes.Count; i++) {
580                                                 XmlAttribute attr = owner.Attributes [i];
581                                                 if (attr.NamespaceURI == Xmlns) {
582                                                         if (CheckNsNameAppearance (attr.Name, attr.Value))
583                                                                 continue;
584                                                         NsNode = attr;
585                                                         return true;
586                                                 }
587                                         }
588                                 }
589                                 owner = GetParentNode (owner) as XmlElement;
590                         }
591
592                         if (namespaceScope == XPathNamespaceScope.All) {
593                                 if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
594                                         return false;
595                                 NsNode = nsNodeXml;
596                                 return true;
597                         }
598                         return false;
599                 }
600
601                 public override bool MoveToParent ()
602                 {
603                         if (NsNode != null) {
604                                 NsNode = null;
605                                 return true;
606                         }
607                         else if (node.NodeType == XmlNodeType.Attribute) {
608                                 XmlElement ownerElement = ((XmlAttribute)node).OwnerElement;
609                                 if (ownerElement != null) {
610                                         node = ownerElement;
611                                         NsNode = null;
612                                         return true;
613                                 }
614                                 else
615                                         return false;
616                         }
617                         XmlNode n = GetParentNode (node);
618                         if (n == null)
619                                 return false;
620                         node = n;
621                         NsNode = null;
622                         return true;
623                 }
624
625                 public override bool MoveToPrevious ()
626                 {
627                         if (NsNode != null)
628                                 return false;
629
630                         XmlNode p = GetPreviousSibling (node);
631                         if (p == null)
632                                 return false;
633                         node = p;
634                         return true;
635                 }
636
637                 public override void MoveToRoot ()
638                 {
639                         XmlAttribute attr = node as XmlAttribute;
640                         XmlNode tmp = attr != null ? attr.OwnerElement : node;
641                         for (XmlNode tmp2 = GetParentNode (tmp); tmp2 != null; tmp2 = GetParentNode (tmp2))
642                                 tmp = tmp2;
643                         node = tmp;
644                         NsNode = null;
645                 }
646
647                 private XmlNode Node { get { return NsNode != null ? NsNode : node; } }
648
649                 XmlNode IHasXmlNode.GetNode ()
650                 {
651                         return Node;
652                 }
653
654                 private XmlNode GetFirstChild (XmlNode n)
655                 {
656                         if (n.FirstChild == null)
657                                 return null;
658                         switch (n.FirstChild.NodeType) {
659                         case XmlNodeType.XmlDeclaration:
660                         case XmlNodeType.DocumentType:
661                                 return GetNextSibling (n.FirstChild);
662                         case XmlNodeType.EntityReference:
663                                 foreach (XmlNode c in n.ChildNodes) {
664                                         if (c.NodeType == XmlNodeType.EntityReference) {
665                                                 XmlNode ec = GetFirstChild (c);
666                                                 if (ec != null)
667                                                         return ec;
668                                         }
669                                         return c;
670                                 }
671                                 return null;
672                         default:
673                                 return n.FirstChild;
674                         }
675                 }
676
677                 private XmlNode GetLastChild (XmlNode n)
678                 {
679                         if (n.LastChild == null)
680                                 return null;
681                         switch (n.LastChild.NodeType) {
682                         case XmlNodeType.XmlDeclaration:
683                         case XmlNodeType.DocumentType:
684                                 return GetPreviousSibling (n.LastChild);
685                         case XmlNodeType.EntityReference:
686                                 for (XmlNode c = n.LastChild; c != null; c = c.PreviousSibling) {
687                                         if (c.NodeType == XmlNodeType.EntityReference) {
688                                                 XmlNode ec = GetLastChild (c);
689                                                 if (ec != null)
690                                                         return ec;
691                                         }
692                                         return c;
693                                 }
694                                 return null;
695                         default:
696                                 return n.LastChild;
697                         }
698                 }
699
700                 private XmlNode GetPreviousSibling (XmlNode n)
701                 {
702                         XmlNode p = n.PreviousSibling;
703                         if (p != null) {
704                                 switch (p.NodeType) {
705                                 case XmlNodeType.EntityReference:
706                                         XmlNode c = GetLastChild (p);
707                                         if (c != null)
708                                                 return c;
709                                         else // empty entity reference etc.
710                                                 return GetPreviousSibling (p);
711                                 case XmlNodeType.XmlDeclaration:
712                                 case XmlNodeType.DocumentType:
713                                         return GetPreviousSibling (p);
714                                 default:
715                                         return p;
716                                 }
717                         } else {
718                                 if (n.ParentNode == null || n.ParentNode.NodeType != XmlNodeType.EntityReference)
719                                         return null;
720                                 return GetPreviousSibling (n.ParentNode);
721                         }
722                 }
723
724                 private XmlNode GetNextSibling (XmlNode n)
725                 {
726                         XmlNode nx = n.NextSibling;
727                         if (nx != null) {
728                                 switch (nx.NodeType) {
729                                 case XmlNodeType.EntityReference:
730                                         XmlNode c = GetFirstChild (nx);
731                                         if (c != null)
732                                                 return c;
733                                         else // empty entity reference etc.
734                                                 return GetNextSibling (nx);
735                                 case XmlNodeType.XmlDeclaration:
736                                 case XmlNodeType.DocumentType:
737                                         return GetNextSibling (nx);
738                                 default:
739                                         return n.NextSibling;
740                                 }
741                         } else {
742                                 if (n.ParentNode == null || n.ParentNode.NodeType != XmlNodeType.EntityReference)
743                                         return null;
744                                 return GetNextSibling (n.ParentNode);
745                         }
746                 }
747
748                 private XmlNode GetParentNode (XmlNode n)
749                 {
750                         if (n.ParentNode == null)
751                                 return null;
752                         for (XmlNode p = n.ParentNode; p != null; p = p.ParentNode)
753                                 if (p.NodeType != XmlNodeType.EntityReference)
754                                         return p;
755                         return null;
756                 }
757
758                 #endregion
759         }
760 }