1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Text;
9 using System.Xml.Schema;
10 using System.Xml.XPath;
11 using System.Diagnostics;
12 
13 namespace System.Xml
14 {
15     internal sealed class DocumentXPathNavigator : XPathNavigator, IHasXmlNode
16     {
17         private XmlDocument _document; // owner document
18         private XmlNode _source; // navigator position
19         private int _attributeIndex; // index in attribute collection for attribute
20         private XmlElement _namespaceParent; // parent for namespace
21 
DocumentXPathNavigator(XmlDocument document, XmlNode node)22         public DocumentXPathNavigator(XmlDocument document, XmlNode node)
23         {
24             _document = document;
25             ResetPosition(node);
26         }
27 
DocumentXPathNavigator(DocumentXPathNavigator other)28         public DocumentXPathNavigator(DocumentXPathNavigator other)
29         {
30             _document = other._document;
31             _source = other._source;
32             _attributeIndex = other._attributeIndex;
33             _namespaceParent = other._namespaceParent;
34         }
35 
Clone()36         public override XPathNavigator Clone()
37         {
38             return new DocumentXPathNavigator(this);
39         }
40 
SetValue(string value)41         public override void SetValue(string value)
42         {
43             if (value == null)
44             {
45                 throw new ArgumentNullException(nameof(value));
46             }
47 
48             XmlNode node = _source;
49             XmlNode end;
50 
51             switch (node.NodeType)
52             {
53                 case XmlNodeType.Attribute:
54                     if (((XmlAttribute)node).IsNamespace)
55                     {
56                         goto default;
57                     }
58                     node.InnerText = value;
59                     break;
60                 case XmlNodeType.Text:
61                 case XmlNodeType.CDATA:
62                 case XmlNodeType.Whitespace:
63                 case XmlNodeType.SignificantWhitespace:
64                     CalibrateText();
65 
66                     node = _source;
67                     end = TextEnd(node);
68                     if (node != end)
69                     {
70                         if (node.IsReadOnly)
71                         {
72                             throw new InvalidOperationException(SR.Xdom_Node_Modify_ReadOnly);
73                         }
74                         DeleteToFollowingSibling(node.NextSibling, end);
75                     }
76                     goto case XmlNodeType.Element;
77                 case XmlNodeType.Element:
78                 case XmlNodeType.ProcessingInstruction:
79                 case XmlNodeType.Comment:
80                     node.InnerText = value;
81                     break;
82                 default:
83                     throw new InvalidOperationException(SR.Xpn_BadPosition);
84             }
85         }
86 
87         public override XmlNameTable NameTable
88         {
89             get
90             {
91                 return _document.NameTable;
92             }
93         }
94 
95         public override XPathNodeType NodeType
96         {
97             get
98             {
99                 CalibrateText();
100 
101                 return (XPathNodeType)_source.XPNodeType;
102             }
103         }
104 
105         public override string LocalName
106         {
107             get
108             {
109                 return _source.XPLocalName;
110             }
111         }
112 
113         public override string NamespaceURI
114         {
115             get
116             {
117                 XmlAttribute attribute = _source as XmlAttribute;
118                 if (attribute != null
119                     && attribute.IsNamespace)
120                 {
121                     return string.Empty;
122                 }
123                 return _source.NamespaceURI;
124             }
125         }
126 
127         public override string Name
128         {
129             get
130             {
131                 switch (_source.NodeType)
132                 {
133                     case XmlNodeType.Element:
134                     case XmlNodeType.ProcessingInstruction:
135                         return _source.Name;
136                     case XmlNodeType.Attribute:
137                         if (((XmlAttribute)_source).IsNamespace)
138                         {
139                             string localName = _source.LocalName;
140                             if (Ref.Equal(localName, _document.strXmlns))
141                             {
142                                 return string.Empty; // xmlns declaration
143                             }
144                             return localName; // xmlns:name declaration
145                         }
146                         return _source.Name; // attribute
147                     default:
148                         return string.Empty;
149                 }
150             }
151         }
152 
153         public override string Prefix
154         {
155             get
156             {
157                 XmlAttribute attribute = _source as XmlAttribute;
158                 if (attribute != null
159                     && attribute.IsNamespace)
160                 {
161                     return string.Empty;
162                 }
163                 return _source.Prefix;
164             }
165         }
166 
167         public override string Value
168         {
169             get
170             {
171                 switch (_source.NodeType)
172                 {
173                     case XmlNodeType.Element:
174                     case XmlNodeType.DocumentFragment:
175                         return _source.InnerText;
176                     case XmlNodeType.Document:
177                         return ValueDocument;
178                     case XmlNodeType.Text:
179                     case XmlNodeType.CDATA:
180                     case XmlNodeType.Whitespace:
181                     case XmlNodeType.SignificantWhitespace:
182                         return ValueText;
183                     default:
184                         return _source.Value;
185                 }
186             }
187         }
188 
189         private string ValueDocument
190         {
191             get
192             {
193                 XmlElement element = _document.DocumentElement;
194                 if (element != null)
195                 {
196                     return element.InnerText;
197                 }
198                 return string.Empty;
199             }
200         }
201 
202         private string ValueText
203         {
204             get
205             {
206                 CalibrateText();
207 
208                 string value = _source.Value;
209                 XmlNode nextSibling = NextSibling(_source);
210                 if (nextSibling != null
211                     && nextSibling.IsText)
212                 {
213                     StringBuilder builder = new StringBuilder(value);
214                     do
215                     {
216                         builder.Append(nextSibling.Value);
217                         nextSibling = NextSibling(nextSibling);
218                     }
219                     while (nextSibling != null
220                            && nextSibling.IsText);
221                     value = builder.ToString();
222                 }
223                 return value;
224             }
225         }
226 
227         public override string BaseURI
228         {
229             get
230             {
231                 return _source.BaseURI;
232             }
233         }
234 
235         public override bool IsEmptyElement
236         {
237             get
238             {
239                 XmlElement element = _source as XmlElement;
240                 if (element != null)
241                 {
242                     return element.IsEmpty;
243                 }
244                 return false;
245             }
246         }
247 
248         public override string XmlLang
249         {
250             get
251             {
252                 return _source.XmlLang;
253             }
254         }
255 
256         public override object UnderlyingObject
257         {
258             get
259             {
260                 CalibrateText();
261 
262                 return _source;
263             }
264         }
265 
266         public override bool HasAttributes
267         {
268             get
269             {
270                 XmlElement element = _source as XmlElement;
271                 if (element != null
272                     && element.HasAttributes)
273                 {
274                     XmlAttributeCollection attributes = element.Attributes;
275                     for (int i = 0; i < attributes.Count; i++)
276                     {
277                         XmlAttribute attribute = attributes[i];
278                         if (!attribute.IsNamespace)
279                         {
280                             return true;
281                         }
282                     }
283                 }
284                 return false;
285             }
286         }
287 
GetAttribute(string localName, string namespaceURI)288         public override string GetAttribute(string localName, string namespaceURI)
289         {
290             return _source.GetXPAttribute(localName, namespaceURI);
291         }
292 
MoveToAttribute(string localName, string namespaceURI)293         public override bool MoveToAttribute(string localName, string namespaceURI)
294         {
295             XmlElement element = _source as XmlElement;
296             if (element != null
297                 && element.HasAttributes)
298             {
299                 XmlAttributeCollection attributes = element.Attributes;
300                 for (int i = 0; i < attributes.Count; i++)
301                 {
302                     XmlAttribute attribute = attributes[i];
303                     if (attribute.LocalName == localName
304                         && attribute.NamespaceURI == namespaceURI)
305                     {
306                         if (!attribute.IsNamespace)
307                         {
308                             _source = attribute;
309                             _attributeIndex = i;
310                             return true;
311                         }
312                         else
313                         {
314                             return false;
315                         }
316                     }
317                 }
318             }
319             return false;
320         }
321 
MoveToFirstAttribute()322         public override bool MoveToFirstAttribute()
323         {
324             XmlElement element = _source as XmlElement;
325             if (element != null
326                 && element.HasAttributes)
327             {
328                 XmlAttributeCollection attributes = element.Attributes;
329                 for (int i = 0; i < attributes.Count; i++)
330                 {
331                     XmlAttribute attribute = attributes[i];
332                     if (!attribute.IsNamespace)
333                     {
334                         _source = attribute;
335                         _attributeIndex = i;
336                         return true;
337                     }
338                 }
339             }
340             return false;
341         }
342 
MoveToNextAttribute()343         public override bool MoveToNextAttribute()
344         {
345             XmlAttribute attribute = _source as XmlAttribute;
346             if (attribute == null
347                 || attribute.IsNamespace)
348             {
349                 return false;
350             }
351             XmlAttributeCollection attributes;
352             if (!CheckAttributePosition(attribute, out attributes, _attributeIndex)
353                 && !ResetAttributePosition(attribute, attributes, out _attributeIndex))
354             {
355                 return false;
356             }
357             for (int i = _attributeIndex + 1; i < attributes.Count; i++)
358             {
359                 attribute = attributes[i];
360                 if (!attribute.IsNamespace)
361                 {
362                     _source = attribute;
363                     _attributeIndex = i;
364                     return true;
365                 }
366             }
367             return false;
368         }
369 
GetNamespace(string name)370         public override string GetNamespace(string name)
371         {
372             XmlNode node = _source;
373             while (node != null
374                    && node.NodeType != XmlNodeType.Element)
375             {
376                 XmlAttribute attribute = node as XmlAttribute;
377                 if (attribute != null)
378                 {
379                     node = attribute.OwnerElement;
380                 }
381                 else
382                 {
383                     node = node.ParentNode;
384                 }
385             }
386 
387             XmlElement element = node as XmlElement;
388             if (element != null)
389             {
390                 string localName;
391                 if (name != null
392                     && name.Length != 0)
393                 {
394                     localName = name;
395                 }
396                 else
397                 {
398                     localName = _document.strXmlns;
399                 }
400                 string namespaceUri = _document.strReservedXmlns;
401 
402                 do
403                 {
404                     XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri);
405                     if (attribute != null)
406                     {
407                         return attribute.Value;
408                     }
409                     element = element.ParentNode as XmlElement;
410                 }
411                 while (element != null);
412             }
413 
414             if (name == _document.strXml)
415             {
416                 return _document.strReservedXml;
417             }
418             else if (name == _document.strXmlns)
419             {
420                 return _document.strReservedXmlns;
421             }
422             return string.Empty;
423         }
424 
MoveToNamespace(string name)425         public override bool MoveToNamespace(string name)
426         {
427             if (name == _document.strXmlns)
428             {
429                 return false;
430             }
431             XmlElement element = _source as XmlElement;
432             if (element != null)
433             {
434                 string localName;
435                 if (name != null
436                     && name.Length != 0)
437                 {
438                     localName = name;
439                 }
440                 else
441                 {
442                     localName = _document.strXmlns;
443                 }
444                 string namespaceUri = _document.strReservedXmlns;
445 
446                 do
447                 {
448                     XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri);
449                     if (attribute != null)
450                     {
451                         _namespaceParent = (XmlElement)_source;
452                         _source = attribute;
453                         return true;
454                     }
455                     element = element.ParentNode as XmlElement;
456                 }
457                 while (element != null);
458 
459                 if (name == _document.strXml)
460                 {
461                     _namespaceParent = (XmlElement)_source;
462                     _source = _document.NamespaceXml;
463                     return true;
464                 }
465             }
466             return false;
467         }
468 
MoveToFirstNamespace(XPathNamespaceScope scope)469         public override bool MoveToFirstNamespace(XPathNamespaceScope scope)
470         {
471             XmlElement element = _source as XmlElement;
472             if (element == null)
473             {
474                 return false;
475             }
476             XmlAttributeCollection attributes;
477             int index = Int32.MaxValue;
478             switch (scope)
479             {
480                 case XPathNamespaceScope.Local:
481                     if (!element.HasAttributes)
482                     {
483                         return false;
484                     }
485                     attributes = element.Attributes;
486                     if (!MoveToFirstNamespaceLocal(attributes, ref index))
487                     {
488                         return false;
489                     }
490                     _source = attributes[index];
491                     _attributeIndex = index;
492                     _namespaceParent = element;
493                     break;
494                 case XPathNamespaceScope.ExcludeXml:
495                     attributes = element.Attributes;
496                     if (!MoveToFirstNamespaceGlobal(ref attributes, ref index))
497                     {
498                         return false;
499                     }
500                     XmlAttribute attribute = attributes[index];
501                     while (Ref.Equal(attribute.LocalName, _document.strXml))
502                     {
503                         if (!MoveToNextNamespaceGlobal(ref attributes, ref index))
504                         {
505                             return false;
506                         }
507                         attribute = attributes[index];
508                     }
509                     _source = attribute;
510                     _attributeIndex = index;
511                     _namespaceParent = element;
512                     break;
513                 case XPathNamespaceScope.All:
514                     attributes = element.Attributes;
515                     if (!MoveToFirstNamespaceGlobal(ref attributes, ref index))
516                     {
517                         _source = _document.NamespaceXml;
518                         // attributeIndex = 0;
519                     }
520                     else
521                     {
522                         _source = attributes[index];
523                         _attributeIndex = index;
524                     }
525                     _namespaceParent = element;
526                     break;
527                 default:
528                     Debug.Assert(false);
529                     return false;
530             }
531             return true;
532         }
533 
MoveToFirstNamespaceLocal(XmlAttributeCollection attributes, ref int index)534         private static bool MoveToFirstNamespaceLocal(XmlAttributeCollection attributes, ref int index)
535         {
536             Debug.Assert(attributes != null);
537             for (int i = attributes.Count - 1; i >= 0; i--)
538             {
539                 XmlAttribute attribute = attributes[i];
540                 if (attribute.IsNamespace)
541                 {
542                     index = i;
543                     return true;
544                 }
545             }
546             return false;
547         }
548 
MoveToFirstNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index)549         private static bool MoveToFirstNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index)
550         {
551             if (MoveToFirstNamespaceLocal(attributes, ref index))
552             {
553                 return true;
554             }
555 
556             Debug.Assert(attributes != null && attributes.parent != null);
557             XmlElement element = attributes.parent.ParentNode as XmlElement;
558             while (element != null)
559             {
560                 if (element.HasAttributes)
561                 {
562                     attributes = element.Attributes;
563                     if (MoveToFirstNamespaceLocal(attributes, ref index))
564                     {
565                         return true;
566                     }
567                 }
568                 element = element.ParentNode as XmlElement;
569             }
570             return false;
571         }
572 
MoveToNextNamespace(XPathNamespaceScope scope)573         public override bool MoveToNextNamespace(XPathNamespaceScope scope)
574         {
575             XmlAttribute attribute = _source as XmlAttribute;
576             if (attribute == null
577                 || !attribute.IsNamespace)
578             {
579                 return false;
580             }
581             XmlAttributeCollection attributes;
582             int index = _attributeIndex;
583             if (!CheckAttributePosition(attribute, out attributes, index)
584                 && !ResetAttributePosition(attribute, attributes, out index))
585             {
586                 return false;
587             }
588             Debug.Assert(_namespaceParent != null);
589             switch (scope)
590             {
591                 case XPathNamespaceScope.Local:
592                     if (attribute.OwnerElement != _namespaceParent)
593                     {
594                         return false;
595                     }
596                     if (!MoveToNextNamespaceLocal(attributes, ref index))
597                     {
598                         return false;
599                     }
600                     _source = attributes[index];
601                     _attributeIndex = index;
602                     break;
603                 case XPathNamespaceScope.ExcludeXml:
604                     string localName;
605                     do
606                     {
607                         if (!MoveToNextNamespaceGlobal(ref attributes, ref index))
608                         {
609                             return false;
610                         }
611                         attribute = attributes[index];
612                         localName = attribute.LocalName;
613                     }
614                     while (PathHasDuplicateNamespace(attribute.OwnerElement, _namespaceParent, localName)
615                            || Ref.Equal(localName, _document.strXml));
616                     _source = attribute;
617                     _attributeIndex = index;
618                     break;
619                 case XPathNamespaceScope.All:
620                     do
621                     {
622                         if (!MoveToNextNamespaceGlobal(ref attributes, ref index))
623                         {
624                             if (PathHasDuplicateNamespace(null, _namespaceParent, _document.strXml))
625                             {
626                                 return false;
627                             }
628                             else
629                             {
630                                 _source = _document.NamespaceXml;
631                                 // attributeIndex = 0;
632                                 return true;
633                             }
634                         }
635                         attribute = attributes[index];
636                     }
637                     while (PathHasDuplicateNamespace(attribute.OwnerElement, _namespaceParent, attribute.LocalName));
638                     _source = attribute;
639                     _attributeIndex = index;
640                     break;
641                 default:
642                     Debug.Assert(false);
643                     return false;
644             }
645             return true;
646         }
647 
MoveToNextNamespaceLocal(XmlAttributeCollection attributes, ref int index)648         private static bool MoveToNextNamespaceLocal(XmlAttributeCollection attributes, ref int index)
649         {
650             Debug.Assert(attributes != null);
651             Debug.Assert(0 <= index && index < attributes.Count);
652             for (int i = index - 1; i >= 0; i--)
653             {
654                 XmlAttribute attribute = attributes[i];
655                 if (attribute.IsNamespace)
656                 {
657                     index = i;
658                     return true;
659                 }
660             }
661             return false;
662         }
663 
MoveToNextNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index)664         private static bool MoveToNextNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index)
665         {
666             if (MoveToNextNamespaceLocal(attributes, ref index))
667             {
668                 return true;
669             }
670 
671             Debug.Assert(attributes != null && attributes.parent != null);
672             XmlElement element = attributes.parent.ParentNode as XmlElement;
673             while (element != null)
674             {
675                 if (element.HasAttributes)
676                 {
677                     attributes = element.Attributes;
678                     if (MoveToFirstNamespaceLocal(attributes, ref index))
679                     {
680                         return true;
681                     }
682                 }
683                 element = element.ParentNode as XmlElement;
684             }
685             return false;
686         }
687 
PathHasDuplicateNamespace(XmlElement top, XmlElement bottom, string localName)688         private bool PathHasDuplicateNamespace(XmlElement top, XmlElement bottom, string localName)
689         {
690             string namespaceUri = _document.strReservedXmlns;
691             while (bottom != null
692                    && bottom != top)
693             {
694                 XmlAttribute attribute = bottom.GetAttributeNode(localName, namespaceUri);
695                 if (attribute != null)
696                 {
697                     return true;
698                 }
699                 bottom = bottom.ParentNode as XmlElement;
700             }
701             return false;
702         }
703 
LookupNamespace(string prefix)704         public override string LookupNamespace(string prefix)
705         {
706             string ns = base.LookupNamespace(prefix);
707             if (ns != null)
708             {
709                 ns = this.NameTable.Add(ns);
710             }
711             return ns;
712         }
713 
MoveToNext()714         public override bool MoveToNext()
715         {
716             XmlNode sibling = NextSibling(_source);
717             if (sibling == null)
718             {
719                 return false;
720             }
721             if (sibling.IsText)
722             {
723                 if (_source.IsText)
724                 {
725                     sibling = NextSibling(TextEnd(sibling));
726                     if (sibling == null)
727                     {
728                         return false;
729                     }
730                 }
731             }
732             XmlNode parent = ParentNode(sibling);
733             Debug.Assert(parent != null);
734             while (!IsValidChild(parent, sibling))
735             {
736                 sibling = NextSibling(sibling);
737                 if (sibling == null)
738                 {
739                     return false;
740                 }
741             }
742             _source = sibling;
743             return true;
744         }
745 
MoveToPrevious()746         public override bool MoveToPrevious()
747         {
748             XmlNode sibling = PreviousSibling(_source);
749             if (sibling == null)
750             {
751                 return false;
752             }
753             if (sibling.IsText)
754             {
755                 if (_source.IsText)
756                 {
757                     sibling = PreviousSibling(TextStart(sibling));
758                     if (sibling == null)
759                     {
760                         return false;
761                     }
762                 }
763                 else
764                 {
765                     sibling = TextStart(sibling);
766                 }
767             }
768             XmlNode parent = ParentNode(sibling);
769             Debug.Assert(parent != null);
770             while (!IsValidChild(parent, sibling))
771             {
772                 sibling = PreviousSibling(sibling);
773                 if (sibling == null)
774                 {
775                     return false;
776                 }
777                 // if (sibling.IsText) {
778                 //     sibling = TextStart(sibling);
779                 // }
780             }
781             _source = sibling;
782             return true;
783         }
784 
MoveToFirst()785         public override bool MoveToFirst()
786         {
787             if (_source.NodeType == XmlNodeType.Attribute)
788             {
789                 return false;
790             }
791             XmlNode parent = ParentNode(_source);
792             if (parent == null)
793             {
794                 return false;
795             }
796             XmlNode sibling = FirstChild(parent);
797             Debug.Assert(sibling != null);
798             while (!IsValidChild(parent, sibling))
799             {
800                 sibling = NextSibling(sibling);
801                 if (sibling == null)
802                 {
803                     return false;
804                 }
805             }
806             _source = sibling;
807             return true;
808         }
809 
MoveToFirstChild()810         public override bool MoveToFirstChild()
811         {
812             XmlNode child;
813             switch (_source.NodeType)
814             {
815                 case XmlNodeType.Element:
816                     child = FirstChild(_source);
817                     if (child == null)
818                     {
819                         return false;
820                     }
821                     break;
822                 case XmlNodeType.DocumentFragment:
823                 case XmlNodeType.Document:
824                     child = FirstChild(_source);
825                     if (child == null)
826                     {
827                         return false;
828                     }
829                     while (!IsValidChild(_source, child))
830                     {
831                         child = NextSibling(child);
832                         if (child == null)
833                         {
834                             return false;
835                         }
836                     }
837                     break;
838                 default:
839                     return false;
840             }
841             _source = child;
842             return true;
843         }
844 
MoveToParent()845         public override bool MoveToParent()
846         {
847             XmlNode parent = ParentNode(_source);
848             if (parent != null)
849             {
850                 _source = parent;
851                 return true;
852             }
853             XmlAttribute attribute = _source as XmlAttribute;
854             if (attribute != null)
855             {
856                 parent = attribute.IsNamespace ? _namespaceParent : attribute.OwnerElement;
857                 if (parent != null)
858                 {
859                     _source = parent;
860                     _namespaceParent = null;
861                     return true;
862                 }
863             }
864             return false;
865         }
866 
MoveToRoot()867         public override void MoveToRoot()
868         {
869             for (;;)
870             {
871                 XmlNode parent = _source.ParentNode;
872                 if (parent == null)
873                 {
874                     XmlAttribute attribute = _source as XmlAttribute;
875                     if (attribute == null)
876                     {
877                         break;
878                     }
879                     parent = attribute.IsNamespace ? _namespaceParent : attribute.OwnerElement;
880                     if (parent == null)
881                     {
882                         break;
883                     }
884                 }
885                 _source = parent;
886             }
887             _namespaceParent = null;
888         }
889 
MoveTo(XPathNavigator other)890         public override bool MoveTo(XPathNavigator other)
891         {
892             DocumentXPathNavigator that = other as DocumentXPathNavigator;
893             if (that != null
894                 && _document == that._document)
895             {
896                 _source = that._source;
897                 _attributeIndex = that._attributeIndex;
898                 _namespaceParent = that._namespaceParent;
899                 return true;
900             }
901             return false;
902         }
903 
MoveToId(string id)904         public override bool MoveToId(string id)
905         {
906             XmlElement element = _document.GetElementById(id);
907             if (element != null)
908             {
909                 _source = element;
910                 _namespaceParent = null;
911                 return true;
912             }
913             return false;
914         }
915 
MoveToChild(string localName, string namespaceUri)916         public override bool MoveToChild(string localName, string namespaceUri)
917         {
918             if (_source.NodeType == XmlNodeType.Attribute)
919             {
920                 return false;
921             }
922 
923             XmlNode child = FirstChild(_source);
924             if (child != null)
925             {
926                 do
927                 {
928                     if (child.NodeType == XmlNodeType.Element
929                         && child.LocalName == localName
930                         && child.NamespaceURI == namespaceUri)
931                     {
932                         _source = child;
933                         return true;
934                     }
935                     child = NextSibling(child);
936                 }
937                 while (child != null);
938             }
939             return false;
940         }
941 
MoveToChild(XPathNodeType type)942         public override bool MoveToChild(XPathNodeType type)
943         {
944             if (_source.NodeType == XmlNodeType.Attribute)
945             {
946                 return false;
947             }
948 
949             XmlNode child = FirstChild(_source);
950             if (child != null)
951             {
952                 int mask = GetContentKindMask(type);
953                 if (mask == 0)
954                 {
955                     return false;
956                 }
957                 do
958                 {
959                     if (((1 << (int)child.XPNodeType) & mask) != 0)
960                     {
961                         _source = child;
962                         return true;
963                     }
964                     child = NextSibling(child);
965                 }
966                 while (child != null);
967             }
968             return false;
969         }
970 
MoveToFollowing(string localName, string namespaceUri, XPathNavigator end)971         public override bool MoveToFollowing(string localName, string namespaceUri, XPathNavigator end)
972         {
973             XmlNode pastFollowing = null;
974             DocumentXPathNavigator that = end as DocumentXPathNavigator;
975             if (that != null)
976             {
977                 if (_document != that._document)
978                 {
979                     return false;
980                 }
981                 switch (that._source.NodeType)
982                 {
983                     case XmlNodeType.Attribute:
984                         that = (DocumentXPathNavigator)that.Clone();
985                         if (!that.MoveToNonDescendant())
986                         {
987                             return false;
988                         }
989                         break;
990                 }
991                 pastFollowing = that._source;
992             }
993 
994             XmlNode following = _source;
995             if (following.NodeType == XmlNodeType.Attribute)
996             {
997                 following = ((XmlAttribute)following).OwnerElement;
998                 if (following == null)
999                 {
1000                     return false;
1001                 }
1002             }
1003             do
1004             {
1005                 XmlNode firstChild = following.FirstChild;
1006                 if (firstChild != null)
1007                 {
1008                     following = firstChild;
1009                 }
1010                 else
1011                 {
1012                     for (;;)
1013                     {
1014                         XmlNode nextSibling = following.NextSibling;
1015                         if (nextSibling != null)
1016                         {
1017                             following = nextSibling;
1018                             break;
1019                         }
1020                         else
1021                         {
1022                             XmlNode parent = following.ParentNode;
1023                             if (parent != null)
1024                             {
1025                                 following = parent;
1026                             }
1027                             else
1028                             {
1029                                 return false;
1030                             }
1031                         }
1032                     }
1033                 }
1034                 if (following == pastFollowing)
1035                 {
1036                     return false;
1037                 }
1038             }
1039             while (following.NodeType != XmlNodeType.Element
1040                    || following.LocalName != localName
1041                    || following.NamespaceURI != namespaceUri);
1042 
1043             _source = following;
1044             return true;
1045         }
1046 
MoveToFollowing(XPathNodeType type, XPathNavigator end)1047         public override bool MoveToFollowing(XPathNodeType type, XPathNavigator end)
1048         {
1049             XmlNode pastFollowing = null;
1050             DocumentXPathNavigator that = end as DocumentXPathNavigator;
1051             if (that != null)
1052             {
1053                 if (_document != that._document)
1054                 {
1055                     return false;
1056                 }
1057                 switch (that._source.NodeType)
1058                 {
1059                     case XmlNodeType.Attribute:
1060                         that = (DocumentXPathNavigator)that.Clone();
1061                         if (!that.MoveToNonDescendant())
1062                         {
1063                             return false;
1064                         }
1065                         break;
1066                 }
1067                 pastFollowing = that._source;
1068             }
1069 
1070             int mask = GetContentKindMask(type);
1071             if (mask == 0)
1072             {
1073                 return false;
1074             }
1075             XmlNode following = _source;
1076             switch (following.NodeType)
1077             {
1078                 case XmlNodeType.Attribute:
1079                     following = ((XmlAttribute)following).OwnerElement;
1080                     if (following == null)
1081                     {
1082                         return false;
1083                     }
1084                     break;
1085                 case XmlNodeType.Text:
1086                 case XmlNodeType.CDATA:
1087                 case XmlNodeType.SignificantWhitespace:
1088                 case XmlNodeType.Whitespace:
1089                     following = TextEnd(following);
1090                     break;
1091             }
1092             do
1093             {
1094                 XmlNode firstChild = following.FirstChild;
1095                 if (firstChild != null)
1096                 {
1097                     following = firstChild;
1098                 }
1099                 else
1100                 {
1101                     for (;;)
1102                     {
1103                         XmlNode nextSibling = following.NextSibling;
1104                         if (nextSibling != null)
1105                         {
1106                             following = nextSibling;
1107                             break;
1108                         }
1109                         else
1110                         {
1111                             XmlNode parent = following.ParentNode;
1112                             if (parent != null)
1113                             {
1114                                 following = parent;
1115                             }
1116                             else
1117                             {
1118                                 return false;
1119                             }
1120                         }
1121                     }
1122                 }
1123                 if (following == pastFollowing)
1124                 {
1125                     return false;
1126                 }
1127             }
1128             while (((1 << (int)following.XPNodeType) & mask) == 0);
1129 
1130             _source = following;
1131             return true;
1132         }
1133 
MoveToNext(string localName, string namespaceUri)1134         public override bool MoveToNext(string localName, string namespaceUri)
1135         {
1136             XmlNode sibling = NextSibling(_source);
1137             if (sibling == null)
1138             {
1139                 return false;
1140             }
1141             do
1142             {
1143                 if (sibling.NodeType == XmlNodeType.Element
1144                     && sibling.LocalName == localName
1145                     && sibling.NamespaceURI == namespaceUri)
1146                 {
1147                     _source = sibling;
1148                     return true;
1149                 }
1150                 sibling = NextSibling(sibling);
1151             }
1152             while (sibling != null);
1153             return false;
1154         }
1155 
MoveToNext(XPathNodeType type)1156         public override bool MoveToNext(XPathNodeType type)
1157         {
1158             XmlNode sibling = NextSibling(_source);
1159             if (sibling == null)
1160             {
1161                 return false;
1162             }
1163             if (sibling.IsText
1164                 && _source.IsText)
1165             {
1166                 sibling = NextSibling(TextEnd(sibling));
1167                 if (sibling == null)
1168                 {
1169                     return false;
1170                 }
1171             }
1172 
1173             int mask = GetContentKindMask(type);
1174             if (mask == 0)
1175             {
1176                 return false;
1177             }
1178             do
1179             {
1180                 if (((1 << (int)sibling.XPNodeType) & mask) != 0)
1181                 {
1182                     _source = sibling;
1183                     return true;
1184                 }
1185                 sibling = NextSibling(sibling);
1186             }
1187             while (sibling != null);
1188             return false;
1189         }
1190 
1191         public override bool HasChildren
1192         {
1193             get
1194             {
1195                 XmlNode child;
1196                 switch (_source.NodeType)
1197                 {
1198                     case XmlNodeType.Element:
1199                         child = FirstChild(_source);
1200                         if (child == null)
1201                         {
1202                             return false;
1203                         }
1204                         return true;
1205                     case XmlNodeType.DocumentFragment:
1206                     case XmlNodeType.Document:
1207                         child = FirstChild(_source);
1208                         if (child == null)
1209                         {
1210                             return false;
1211                         }
1212                         while (!IsValidChild(_source, child))
1213                         {
1214                             child = NextSibling(child);
1215                             if (child == null)
1216                             {
1217                                 return false;
1218                             }
1219                         }
1220                         return true;
1221                     default:
1222                         return false;
1223                 }
1224             }
1225         }
1226 
IsSamePosition(XPathNavigator other)1227         public override bool IsSamePosition(XPathNavigator other)
1228         {
1229             DocumentXPathNavigator that = other as DocumentXPathNavigator;
1230             if (that != null)
1231             {
1232                 this.CalibrateText();
1233                 that.CalibrateText();
1234 
1235                 return _source == that._source
1236                        && _namespaceParent == that._namespaceParent;
1237             }
1238             return false;
1239         }
1240 
IsDescendant(XPathNavigator other)1241         public override bool IsDescendant(XPathNavigator other)
1242         {
1243             DocumentXPathNavigator that = other as DocumentXPathNavigator;
1244             if (that != null)
1245             {
1246                 return IsDescendant(_source, that._source);
1247             }
1248             return false;
1249         }
1250 
1251         public override IXmlSchemaInfo SchemaInfo
1252         {
1253             get
1254             {
1255                 return _source.SchemaInfo;
1256             }
1257         }
1258 
CheckValidity(XmlSchemaSet schemas, ValidationEventHandler validationEventHandler)1259         public override bool CheckValidity(XmlSchemaSet schemas, ValidationEventHandler validationEventHandler)
1260         {
1261             XmlDocument ownerDocument;
1262 
1263             if (_source.NodeType == XmlNodeType.Document)
1264             {
1265                 ownerDocument = (XmlDocument)_source;
1266             }
1267             else
1268             {
1269                 ownerDocument = _source.OwnerDocument;
1270 
1271                 if (schemas != null)
1272                 {
1273                     throw new ArgumentException(SR.Format(SR.XPathDocument_SchemaSetNotAllowed, null));
1274                 }
1275             }
1276             if (schemas == null && ownerDocument != null)
1277             {
1278                 schemas = ownerDocument.Schemas;
1279             }
1280 
1281             if (schemas == null || schemas.Count == 0)
1282             {
1283                 throw new InvalidOperationException(SR.XmlDocument_NoSchemaInfo);
1284             }
1285 
1286             DocumentSchemaValidator validator = new DocumentSchemaValidator(ownerDocument, schemas, validationEventHandler);
1287             validator.PsviAugmentation = false;
1288             return validator.Validate(_source);
1289         }
1290 
OwnerNode(XmlNode node)1291         private static XmlNode OwnerNode(XmlNode node)
1292         {
1293             XmlNode parent = node.ParentNode;
1294             if (parent != null)
1295             {
1296                 return parent;
1297             }
1298             XmlAttribute attribute = node as XmlAttribute;
1299             if (attribute != null)
1300             {
1301                 return attribute.OwnerElement;
1302             }
1303             return null;
1304         }
1305 
GetDepth(XmlNode node)1306         private static int GetDepth(XmlNode node)
1307         {
1308             int depth = 0;
1309             XmlNode owner = OwnerNode(node);
1310             while (owner != null)
1311             {
1312                 depth++;
1313                 owner = OwnerNode(owner);
1314             }
1315             return depth;
1316         }
1317 
1318         //Assuming that node1 and node2 are in the same level; Except when they are namespace nodes, they should have the same parent node
1319         //the returned value is node2's position corresponding to node1
Compare(XmlNode node1, XmlNode node2)1320         private XmlNodeOrder Compare(XmlNode node1, XmlNode node2)
1321         {
1322             Debug.Assert(node1 != null);
1323             Debug.Assert(node2 != null);
1324             Debug.Assert(node1 != node2, "Should be handled by ComparePosition()");
1325             //Attribute nodes come before other children nodes except namespace nodes
1326             Debug.Assert(OwnerNode(node1) == OwnerNode(node2));
1327             if (node1.XPNodeType == XPathNodeType.Attribute)
1328             {
1329                 if (node2.XPNodeType == XPathNodeType.Attribute)
1330                 {
1331                     XmlElement element = ((XmlAttribute)node1).OwnerElement;
1332                     if (element.HasAttributes)
1333                     {
1334                         XmlAttributeCollection attributes = element.Attributes;
1335                         for (int i = 0; i < attributes.Count; i++)
1336                         {
1337                             XmlAttribute attribute = attributes[i];
1338                             if (attribute == node1)
1339                             {
1340                                 return XmlNodeOrder.Before;
1341                             }
1342                             else if (attribute == node2)
1343                             {
1344                                 return XmlNodeOrder.After;
1345                             }
1346                         }
1347                     }
1348                     return XmlNodeOrder.Unknown;
1349                 }
1350                 else
1351                 {
1352                     return XmlNodeOrder.Before;
1353                 }
1354             }
1355             if (node2.XPNodeType == XPathNodeType.Attribute)
1356             {
1357                 return XmlNodeOrder.After;
1358             }
1359 
1360             //neither of the node is Namespace node or Attribute node
1361             XmlNode nextNode = node1.NextSibling;
1362             while (nextNode != null && nextNode != node2)
1363                 nextNode = nextNode.NextSibling;
1364             if (nextNode == null)
1365                 //didn't meet node2 in the path to the end, thus it has to be in the front of node1
1366                 return XmlNodeOrder.After;
1367             else
1368                 //met node2 in the path to the end, so node1 is at front
1369                 return XmlNodeOrder.Before;
1370         }
1371 
ComparePosition(XPathNavigator other)1372         public override XmlNodeOrder ComparePosition(XPathNavigator other)
1373         {
1374             DocumentXPathNavigator that = other as DocumentXPathNavigator;
1375             if (that == null)
1376             {
1377                 return XmlNodeOrder.Unknown;
1378             }
1379 
1380             this.CalibrateText();
1381             that.CalibrateText();
1382 
1383             if (_source == that._source
1384                 && _namespaceParent == that._namespaceParent)
1385             {
1386                 return XmlNodeOrder.Same;
1387             }
1388 
1389             if (_namespaceParent != null
1390                 || that._namespaceParent != null)
1391             {
1392                 return base.ComparePosition(other);
1393             }
1394 
1395             XmlNode node1 = _source;
1396             XmlNode node2 = that._source;
1397 
1398             XmlNode parent1 = OwnerNode(node1);
1399             XmlNode parent2 = OwnerNode(node2);
1400             if (parent1 == parent2)
1401             {
1402                 if (parent1 == null)
1403                 {
1404                     return XmlNodeOrder.Unknown;
1405                 }
1406                 else
1407                 {
1408                     Debug.Assert(node1 != node2);
1409                     return Compare(node1, node2);
1410                 }
1411             }
1412 
1413             int depth1 = GetDepth(node1);
1414             int depth2 = GetDepth(node2);
1415             if (depth2 > depth1)
1416             {
1417                 while (node2 != null
1418                        && depth2 > depth1)
1419                 {
1420                     node2 = OwnerNode(node2);
1421                     depth2--;
1422                 }
1423                 if (node1 == node2)
1424                 {
1425                     return XmlNodeOrder.Before;
1426                 }
1427                 parent2 = OwnerNode(node2);
1428             }
1429             else if (depth1 > depth2)
1430             {
1431                 while (node1 != null
1432                        && depth1 > depth2)
1433                 {
1434                     node1 = OwnerNode(node1);
1435                     depth1--;
1436                 }
1437                 if (node1 == node2)
1438                 {
1439                     return XmlNodeOrder.After;
1440                 }
1441                 parent1 = OwnerNode(node1);
1442             }
1443 
1444             while (parent1 != null
1445                    && parent2 != null)
1446             {
1447                 if (parent1 == parent2)
1448                 {
1449                     Debug.Assert(node1 != node2);
1450                     return Compare(node1, node2);
1451                 }
1452                 node1 = parent1;
1453                 node2 = parent2;
1454                 parent1 = OwnerNode(node1);
1455                 parent2 = OwnerNode(node2);
1456             }
1457             return XmlNodeOrder.Unknown;
1458         }
1459 
1460         //the function just for XPathNodeList to enumerate current Node.
IHasXmlNode.GetNode()1461         XmlNode IHasXmlNode.GetNode() { return _source; }
1462 
SelectDescendants(string localName, string namespaceURI, bool matchSelf)1463         public override XPathNodeIterator SelectDescendants(string localName, string namespaceURI, bool matchSelf)
1464         {
1465             string nsAtom = _document.NameTable.Get(namespaceURI);
1466             if (nsAtom == null || _source.NodeType == XmlNodeType.Attribute)
1467                 return new DocumentXPathNodeIterator_Empty(this);
1468 
1469             Debug.Assert(this.NodeType != XPathNodeType.Attribute && this.NodeType != XPathNodeType.Namespace && this.NodeType != XPathNodeType.All);
1470 
1471             string localNameAtom = _document.NameTable.Get(localName);
1472             if (localNameAtom == null)
1473                 return new DocumentXPathNodeIterator_Empty(this);
1474 
1475             if (localNameAtom.Length == 0)
1476             {
1477                 if (matchSelf)
1478                     return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName(this, nsAtom);
1479                 return new DocumentXPathNodeIterator_ElemChildren_NoLocalName(this, nsAtom);
1480             }
1481 
1482             if (matchSelf)
1483                 return new DocumentXPathNodeIterator_ElemChildren_AndSelf(this, localNameAtom, nsAtom);
1484             return new DocumentXPathNodeIterator_ElemChildren(this, localNameAtom, nsAtom);
1485         }
1486 
SelectDescendants(XPathNodeType nt, bool includeSelf)1487         public override XPathNodeIterator SelectDescendants(XPathNodeType nt, bool includeSelf)
1488         {
1489             if (nt == XPathNodeType.Element)
1490             {
1491                 XmlNodeType curNT = _source.NodeType;
1492                 if (curNT != XmlNodeType.Document && curNT != XmlNodeType.Element)
1493                 {
1494                     //only Document, Entity, Element node can have Element node as children ( descendant )
1495                     //entity nodes should be invisible to XPath data model
1496                     return new DocumentXPathNodeIterator_Empty(this);
1497                 }
1498                 if (includeSelf)
1499                     return new DocumentXPathNodeIterator_AllElemChildren_AndSelf(this);
1500                 return new DocumentXPathNodeIterator_AllElemChildren(this);
1501             }
1502             return base.SelectDescendants(nt, includeSelf);
1503         }
1504 
1505         public override bool CanEdit
1506         {
1507             get
1508             {
1509                 return true;
1510             }
1511         }
1512 
PrependChild()1513         public override XmlWriter PrependChild()
1514         {
1515             switch (_source.NodeType)
1516             {
1517                 case XmlNodeType.Element:
1518                 case XmlNodeType.Document:
1519                 case XmlNodeType.DocumentFragment:
1520                     break;
1521                 default:
1522                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1523             }
1524 
1525             DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.PrependChild, _source, _document);
1526             writer.NamespaceManager = GetNamespaceManager(_source, _document);
1527             return new XmlWellFormedWriter(writer, writer.Settings);
1528         }
1529 
AppendChild()1530         public override XmlWriter AppendChild()
1531         {
1532             switch (_source.NodeType)
1533             {
1534                 case XmlNodeType.Element:
1535                 case XmlNodeType.Document:
1536                 case XmlNodeType.DocumentFragment:
1537                     break;
1538                 default:
1539                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1540             }
1541 
1542             DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendChild, _source, _document);
1543             writer.NamespaceManager = GetNamespaceManager(_source, _document);
1544             return new XmlWellFormedWriter(writer, writer.Settings);
1545         }
1546 
InsertAfter()1547         public override XmlWriter InsertAfter()
1548         {
1549             XmlNode node = _source;
1550 
1551             switch (node.NodeType)
1552             {
1553                 case XmlNodeType.Attribute:
1554                 case XmlNodeType.Document:
1555                 case XmlNodeType.DocumentFragment:
1556                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1557                 case XmlNodeType.Text:
1558                 case XmlNodeType.CDATA:
1559                 case XmlNodeType.SignificantWhitespace:
1560                 case XmlNodeType.Whitespace:
1561                     node = TextEnd(node);
1562                     break;
1563                 default:
1564                     break;
1565             }
1566 
1567             DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingAfter, node, _document);
1568             writer.NamespaceManager = GetNamespaceManager(node.ParentNode, _document);
1569             return new XmlWellFormedWriter(writer, writer.Settings);
1570         }
1571 
InsertBefore()1572         public override XmlWriter InsertBefore()
1573         {
1574             switch (_source.NodeType)
1575             {
1576                 case XmlNodeType.Attribute:
1577                 case XmlNodeType.Document:
1578                 case XmlNodeType.DocumentFragment:
1579                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1580                 case XmlNodeType.Text:
1581                 case XmlNodeType.CDATA:
1582                 case XmlNodeType.SignificantWhitespace:
1583                 case XmlNodeType.Whitespace:
1584                     CalibrateText();
1585 
1586                     break;
1587                 default:
1588                     break;
1589             }
1590 
1591             DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingBefore, _source, _document);
1592             writer.NamespaceManager = GetNamespaceManager(_source.ParentNode, _document);
1593             return new XmlWellFormedWriter(writer, writer.Settings);
1594         }
1595 
CreateAttributes()1596         public override XmlWriter CreateAttributes()
1597         {
1598             if (_source.NodeType != XmlNodeType.Element)
1599             {
1600                 throw new InvalidOperationException(SR.Xpn_BadPosition);
1601             }
1602 
1603             DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendAttribute, _source, _document);
1604             writer.NamespaceManager = GetNamespaceManager(_source, _document);
1605             return new XmlWellFormedWriter(writer, writer.Settings);
1606         }
1607 
ReplaceRange(XPathNavigator lastSiblingToReplace)1608         public override XmlWriter ReplaceRange(XPathNavigator lastSiblingToReplace)
1609         {
1610             DocumentXPathNavigator that = lastSiblingToReplace as DocumentXPathNavigator;
1611             if (that == null)
1612             {
1613                 if (lastSiblingToReplace == null)
1614                 {
1615                     throw new ArgumentNullException(nameof(lastSiblingToReplace));
1616                 }
1617                 else
1618                 {
1619                     throw new NotSupportedException();
1620                 }
1621             }
1622 
1623             this.CalibrateText();
1624             that.CalibrateText();
1625 
1626             XmlNode node = _source;
1627             XmlNode end = that._source;
1628 
1629             if (node == end)
1630             {
1631                 switch (node.NodeType)
1632                 {
1633                     case XmlNodeType.Attribute:
1634                     case XmlNodeType.Document:
1635                     case XmlNodeType.DocumentFragment:
1636                         throw new InvalidOperationException(SR.Xpn_BadPosition);
1637                     case XmlNodeType.Text:
1638                     case XmlNodeType.CDATA:
1639                     case XmlNodeType.SignificantWhitespace:
1640                     case XmlNodeType.Whitespace:
1641                         end = that.TextEnd(end);
1642                         break;
1643                     default:
1644                         break;
1645                 }
1646             }
1647             else
1648             {
1649                 if (end.IsText)
1650                 {
1651                     end = that.TextEnd(end);
1652                 }
1653                 if (!IsFollowingSibling(node, end))
1654                 {
1655                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1656                 }
1657             }
1658 
1659             DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.ReplaceToFollowingSibling, node, _document);
1660             writer.NamespaceManager = GetNamespaceManager(node.ParentNode, _document);
1661             writer.Navigator = this;
1662             writer.EndNode = end;
1663             return new XmlWellFormedWriter(writer, writer.Settings);
1664         }
1665 
DeleteRange(XPathNavigator lastSiblingToDelete)1666         public override void DeleteRange(XPathNavigator lastSiblingToDelete)
1667         {
1668             DocumentXPathNavigator that = lastSiblingToDelete as DocumentXPathNavigator;
1669             if (that == null)
1670             {
1671                 if (lastSiblingToDelete == null)
1672                 {
1673                     throw new ArgumentNullException(nameof(lastSiblingToDelete));
1674                 }
1675                 else
1676                 {
1677                     throw new NotSupportedException();
1678                 }
1679             }
1680 
1681             this.CalibrateText();
1682             that.CalibrateText();
1683 
1684             XmlNode node = _source;
1685             XmlNode end = that._source;
1686 
1687             if (node == end)
1688             {
1689                 switch (node.NodeType)
1690                 {
1691                     case XmlNodeType.Attribute:
1692                         XmlAttribute attribute = (XmlAttribute)node;
1693                         if (attribute.IsNamespace)
1694                         {
1695                             goto default;
1696                         }
1697                         XmlNode parent = OwnerNode(attribute);
1698                         DeleteAttribute(attribute, _attributeIndex);
1699                         if (parent != null)
1700                         {
1701                             ResetPosition(parent);
1702                         }
1703                         break;
1704                     case XmlNodeType.Text:
1705                     case XmlNodeType.CDATA:
1706                     case XmlNodeType.SignificantWhitespace:
1707                     case XmlNodeType.Whitespace:
1708                         end = that.TextEnd(end);
1709                         goto case XmlNodeType.Element;
1710                     case XmlNodeType.Element:
1711                     case XmlNodeType.ProcessingInstruction:
1712                     case XmlNodeType.Comment:
1713                         parent = OwnerNode(node);
1714                         DeleteToFollowingSibling(node, end);
1715                         if (parent != null)
1716                         {
1717                             ResetPosition(parent);
1718                         }
1719                         break;
1720                     default:
1721                         throw new InvalidOperationException(SR.Xpn_BadPosition);
1722                 }
1723             }
1724             else
1725             {
1726                 if (end.IsText)
1727                 {
1728                     end = that.TextEnd(end);
1729                 }
1730                 if (!IsFollowingSibling(node, end))
1731                 {
1732                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1733                 }
1734                 XmlNode parent = OwnerNode(node);
1735                 DeleteToFollowingSibling(node, end);
1736                 if (parent != null)
1737                 {
1738                     ResetPosition(parent);
1739                 }
1740             }
1741         }
1742 
DeleteSelf()1743         public override void DeleteSelf()
1744         {
1745             XmlNode node = _source;
1746             XmlNode end = node;
1747 
1748             switch (node.NodeType)
1749             {
1750                 case XmlNodeType.Attribute:
1751                     XmlAttribute attribute = (XmlAttribute)node;
1752                     if (attribute.IsNamespace)
1753                     {
1754                         goto default;
1755                     }
1756                     XmlNode parent = OwnerNode(attribute);
1757                     DeleteAttribute(attribute, _attributeIndex);
1758                     if (parent != null)
1759                     {
1760                         ResetPosition(parent);
1761                     }
1762                     break;
1763                 case XmlNodeType.Text:
1764                 case XmlNodeType.CDATA:
1765                 case XmlNodeType.SignificantWhitespace:
1766                 case XmlNodeType.Whitespace:
1767                     CalibrateText();
1768 
1769                     node = _source;
1770                     end = TextEnd(node);
1771                     goto case XmlNodeType.Element;
1772                 case XmlNodeType.Element:
1773                 case XmlNodeType.ProcessingInstruction:
1774                 case XmlNodeType.Comment:
1775                     parent = OwnerNode(node);
1776                     DeleteToFollowingSibling(node, end);
1777                     if (parent != null)
1778                     {
1779                         ResetPosition(parent);
1780                     }
1781                     break;
1782                 default:
1783                     throw new InvalidOperationException(SR.Xpn_BadPosition);
1784             }
1785         }
1786 
DeleteAttribute(XmlAttribute attribute, int index)1787         private static void DeleteAttribute(XmlAttribute attribute, int index)
1788         {
1789             XmlAttributeCollection attributes;
1790 
1791             if (!CheckAttributePosition(attribute, out attributes, index)
1792                 && !ResetAttributePosition(attribute, attributes, out index))
1793             {
1794                 throw new InvalidOperationException(SR.Xpn_MissingParent);
1795             }
1796             if (attribute.IsReadOnly)
1797             {
1798                 throw new InvalidOperationException(SR.Xdom_Node_Modify_ReadOnly);
1799             }
1800             attributes.RemoveAt(index);
1801         }
1802 
DeleteToFollowingSibling(XmlNode node, XmlNode end)1803         internal static void DeleteToFollowingSibling(XmlNode node, XmlNode end)
1804         {
1805             XmlNode parent = node.ParentNode;
1806 
1807             if (parent == null)
1808             {
1809                 throw new InvalidOperationException(SR.Xpn_MissingParent);
1810             }
1811             if (node.IsReadOnly
1812                 || end.IsReadOnly)
1813             {
1814                 throw new InvalidOperationException(SR.Xdom_Node_Modify_ReadOnly);
1815             }
1816             while (node != end)
1817             {
1818                 XmlNode temp = node;
1819                 node = node.NextSibling;
1820                 parent.RemoveChild(temp);
1821             }
1822             parent.RemoveChild(node);
1823         }
1824 
GetNamespaceManager(XmlNode node, XmlDocument document)1825         private static XmlNamespaceManager GetNamespaceManager(XmlNode node, XmlDocument document)
1826         {
1827             XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
1828             List<XmlElement> elements = new List<XmlElement>();
1829 
1830             while (node != null)
1831             {
1832                 XmlElement element = node as XmlElement;
1833                 if (element != null
1834                     && element.HasAttributes)
1835                 {
1836                     elements.Add(element);
1837                 }
1838                 node = node.ParentNode;
1839             }
1840             for (int i = elements.Count - 1; i >= 0; i--)
1841             {
1842                 namespaceManager.PushScope();
1843                 XmlAttributeCollection attributes = elements[i].Attributes;
1844                 for (int j = 0; j < attributes.Count; j++)
1845                 {
1846                     XmlAttribute attribute = attributes[j];
1847                     if (attribute.IsNamespace)
1848                     {
1849                         string prefix = attribute.Prefix.Length == 0 ? string.Empty : attribute.LocalName;
1850                         namespaceManager.AddNamespace(prefix, attribute.Value);
1851                     }
1852                 }
1853             }
1854             return namespaceManager;
1855         }
1856 
ResetPosition(XmlNode node)1857         internal void ResetPosition(XmlNode node)
1858         {
1859             Debug.Assert(node != null, "Undefined navigator position");
1860             Debug.Assert(node == _document || node.OwnerDocument == _document, "Navigator switched documents");
1861             _source = node;
1862             XmlAttribute attribute = node as XmlAttribute;
1863             if (attribute != null)
1864             {
1865                 XmlElement element = attribute.OwnerElement;
1866                 if (element != null)
1867                 {
1868                     ResetAttributePosition(attribute, element.Attributes, out _attributeIndex);
1869                     if (attribute.IsNamespace)
1870                     {
1871                         _namespaceParent = element;
1872                     }
1873                 }
1874             }
1875         }
1876 
ResetAttributePosition(XmlAttribute attribute, XmlAttributeCollection attributes, out int index)1877         private static bool ResetAttributePosition(XmlAttribute attribute, XmlAttributeCollection attributes, out int index)
1878         {
1879             if (attributes != null)
1880             {
1881                 for (int i = 0; i < attributes.Count; i++)
1882                 {
1883                     if (attribute == attributes[i])
1884                     {
1885                         index = i;
1886                         return true;
1887                     }
1888                 }
1889             }
1890             index = 0;
1891             return false;
1892         }
1893 
CheckAttributePosition(XmlAttribute attribute, out XmlAttributeCollection attributes, int index)1894         private static bool CheckAttributePosition(XmlAttribute attribute, out XmlAttributeCollection attributes, int index)
1895         {
1896             XmlElement element = attribute.OwnerElement;
1897             if (element != null)
1898             {
1899                 attributes = element.Attributes;
1900                 if (index >= 0
1901                     && index < attributes.Count
1902                     && attribute == attributes[index])
1903                 {
1904                     return true;
1905                 }
1906             }
1907             else
1908             {
1909                 attributes = null;
1910             }
1911             return false;
1912         }
1913 
CalibrateText()1914         private void CalibrateText()
1915         {
1916             XmlNode text = PreviousText(_source);
1917             while (text != null)
1918             {
1919                 ResetPosition(text);
1920                 text = PreviousText(text);
1921             }
1922         }
1923 
ParentNode(XmlNode node)1924         private XmlNode ParentNode(XmlNode node)
1925         {
1926             XmlNode parent = node.ParentNode;
1927 
1928             if (!_document.HasEntityReferences)
1929             {
1930                 return parent;
1931             }
1932             return ParentNodeTail(parent);
1933         }
1934 
ParentNodeTail(XmlNode parent)1935         private XmlNode ParentNodeTail(XmlNode parent)
1936         {
1937             while (parent != null
1938                    && parent.NodeType == XmlNodeType.EntityReference)
1939             {
1940                 parent = parent.ParentNode;
1941             }
1942             return parent;
1943         }
1944 
FirstChild(XmlNode node)1945         private XmlNode FirstChild(XmlNode node)
1946         {
1947             XmlNode child = node.FirstChild;
1948 
1949             if (!_document.HasEntityReferences)
1950             {
1951                 return child;
1952             }
1953             return FirstChildTail(child);
1954         }
1955 
FirstChildTail(XmlNode child)1956         private XmlNode FirstChildTail(XmlNode child)
1957         {
1958             while (child != null
1959                    && child.NodeType == XmlNodeType.EntityReference)
1960             {
1961                 child = child.FirstChild;
1962             }
1963             return child;
1964         }
1965 
NextSibling(XmlNode node)1966         private XmlNode NextSibling(XmlNode node)
1967         {
1968             XmlNode sibling = node.NextSibling;
1969 
1970             if (!_document.HasEntityReferences)
1971             {
1972                 return sibling;
1973             }
1974             return NextSiblingTail(node, sibling);
1975         }
1976 
NextSiblingTail(XmlNode node, XmlNode sibling)1977         private XmlNode NextSiblingTail(XmlNode node, XmlNode sibling)
1978         {
1979             while (sibling == null)
1980             {
1981                 node = node.ParentNode;
1982                 if (node == null
1983                     || node.NodeType != XmlNodeType.EntityReference)
1984                 {
1985                     return null;
1986                 }
1987                 sibling = node.NextSibling;
1988             }
1989             while (sibling != null
1990                    && sibling.NodeType == XmlNodeType.EntityReference)
1991             {
1992                 sibling = sibling.FirstChild;
1993             }
1994             return sibling;
1995         }
1996 
PreviousSibling(XmlNode node)1997         private XmlNode PreviousSibling(XmlNode node)
1998         {
1999             XmlNode sibling = node.PreviousSibling;
2000 
2001             if (!_document.HasEntityReferences)
2002             {
2003                 return sibling;
2004             }
2005             return PreviousSiblingTail(node, sibling);
2006         }
2007 
PreviousSiblingTail(XmlNode node, XmlNode sibling)2008         private XmlNode PreviousSiblingTail(XmlNode node, XmlNode sibling)
2009         {
2010             while (sibling == null)
2011             {
2012                 node = node.ParentNode;
2013                 if (node == null
2014                     || node.NodeType != XmlNodeType.EntityReference)
2015                 {
2016                     return null;
2017                 }
2018                 sibling = node.PreviousSibling;
2019             }
2020             while (sibling != null
2021                    && sibling.NodeType == XmlNodeType.EntityReference)
2022             {
2023                 sibling = sibling.LastChild;
2024             }
2025             return sibling;
2026         }
2027 
PreviousText(XmlNode node)2028         private XmlNode PreviousText(XmlNode node)
2029         {
2030             XmlNode text = node.PreviousText;
2031 
2032             if (!_document.HasEntityReferences)
2033             {
2034                 return text;
2035             }
2036             return PreviousTextTail(node, text);
2037         }
2038 
PreviousTextTail(XmlNode node, XmlNode text)2039         private XmlNode PreviousTextTail(XmlNode node, XmlNode text)
2040         {
2041             if (text != null)
2042             {
2043                 return text;
2044             }
2045             if (!node.IsText)
2046             {
2047                 return null;
2048             }
2049             XmlNode sibling = node.PreviousSibling;
2050             while (sibling == null)
2051             {
2052                 node = node.ParentNode;
2053                 if (node == null
2054                     || node.NodeType != XmlNodeType.EntityReference)
2055                 {
2056                     return null;
2057                 }
2058                 sibling = node.PreviousSibling;
2059             }
2060             while (sibling != null)
2061             {
2062                 switch (sibling.NodeType)
2063                 {
2064                     case XmlNodeType.EntityReference:
2065                         sibling = sibling.LastChild;
2066                         break;
2067                     case XmlNodeType.Text:
2068                     case XmlNodeType.CDATA:
2069                     case XmlNodeType.Whitespace:
2070                     case XmlNodeType.SignificantWhitespace:
2071                         return sibling;
2072                     default:
2073                         return null;
2074                 }
2075             }
2076             return null;
2077         }
2078 
IsFollowingSibling(XmlNode left, XmlNode right)2079         internal static bool IsFollowingSibling(XmlNode left, XmlNode right)
2080         {
2081             for (;;)
2082             {
2083                 left = left.NextSibling;
2084                 if (left == null)
2085                 {
2086                     break;
2087                 }
2088                 if (left == right)
2089                 {
2090                     return true;
2091                 }
2092             }
2093             return false;
2094         }
2095 
IsDescendant(XmlNode top, XmlNode bottom)2096         private static bool IsDescendant(XmlNode top, XmlNode bottom)
2097         {
2098             for (;;)
2099             {
2100                 XmlNode parent = bottom.ParentNode;
2101                 if (parent == null)
2102                 {
2103                     XmlAttribute attribute = bottom as XmlAttribute;
2104                     if (attribute == null)
2105                     {
2106                         break;
2107                     }
2108                     parent = attribute.OwnerElement;
2109                     if (parent == null)
2110                     {
2111                         break;
2112                     }
2113                 }
2114                 bottom = parent;
2115                 if (top == bottom)
2116                 {
2117                     return true;
2118                 }
2119             }
2120             return false;
2121         }
2122 
IsValidChild(XmlNode parent, XmlNode child)2123         private static bool IsValidChild(XmlNode parent, XmlNode child)
2124         {
2125             switch (parent.NodeType)
2126             {
2127                 case XmlNodeType.Element:
2128                     return true;
2129                 case XmlNodeType.DocumentFragment:
2130                     switch (child.NodeType)
2131                     {
2132                         case XmlNodeType.Element:
2133                         case XmlNodeType.Text:
2134                         case XmlNodeType.CDATA:
2135                         case XmlNodeType.ProcessingInstruction:
2136                         case XmlNodeType.Comment:
2137                         case XmlNodeType.Whitespace:
2138                         case XmlNodeType.SignificantWhitespace:
2139                             return true;
2140                     }
2141                     break;
2142                 case XmlNodeType.Document:
2143                     switch (child.NodeType)
2144                     {
2145                         case XmlNodeType.Element:
2146                         case XmlNodeType.ProcessingInstruction:
2147                         case XmlNodeType.Comment:
2148                             return true;
2149                     }
2150                     break;
2151                 default:
2152                     break;
2153             }
2154             return false;
2155         }
2156 
TextStart(XmlNode node)2157         private XmlNode TextStart(XmlNode node)
2158         {
2159             XmlNode start;
2160 
2161             do
2162             {
2163                 start = node;
2164                 node = PreviousSibling(node);
2165             }
2166             while (node != null
2167                    && node.IsText);
2168             return start;
2169         }
2170 
TextEnd(XmlNode node)2171         private XmlNode TextEnd(XmlNode node)
2172         {
2173             XmlNode end;
2174 
2175             do
2176             {
2177                 end = node;
2178                 node = NextSibling(node);
2179             }
2180             while (node != null
2181                    && node.IsText);
2182             return end;
2183         }
2184     }
2185 
2186     // An iterator that matches no nodes
2187     internal sealed class DocumentXPathNodeIterator_Empty : XPathNodeIterator
2188     {
2189         private XPathNavigator _nav;
2190 
DocumentXPathNodeIterator_Empty(DocumentXPathNavigator nav)2191         internal DocumentXPathNodeIterator_Empty(DocumentXPathNavigator nav) { _nav = nav.Clone(); }
DocumentXPathNodeIterator_Empty(DocumentXPathNodeIterator_Empty other)2192         internal DocumentXPathNodeIterator_Empty(DocumentXPathNodeIterator_Empty other) { _nav = other._nav.Clone(); }
Clone()2193         public override XPathNodeIterator Clone() { return new DocumentXPathNodeIterator_Empty(this); }
MoveNext()2194         public override bool MoveNext() { return false; }
2195         public override XPathNavigator Current { get { return _nav; } }
2196         public override int CurrentPosition { get { return 0; } }
2197         public override int Count { get { return 0; } }
2198     }
2199 
2200     // An iterator that can match any child elements that match the Match condition (overridden in the derived class)
2201     internal abstract class DocumentXPathNodeIterator_ElemDescendants : XPathNodeIterator
2202     {
2203         private DocumentXPathNavigator _nav;
2204         private int _level;
2205         private int _position;
2206 
DocumentXPathNodeIterator_ElemDescendants(DocumentXPathNavigator nav)2207         internal DocumentXPathNodeIterator_ElemDescendants(DocumentXPathNavigator nav)
2208         {
2209             _nav = (DocumentXPathNavigator)(nav.Clone());
2210             _level = 0;
2211             _position = 0;
2212         }
DocumentXPathNodeIterator_ElemDescendants(DocumentXPathNodeIterator_ElemDescendants other)2213         internal DocumentXPathNodeIterator_ElemDescendants(DocumentXPathNodeIterator_ElemDescendants other)
2214         {
2215             _nav = (DocumentXPathNavigator)(other._nav.Clone());
2216             _level = other._level;
2217             _position = other._position;
2218         }
2219 
Match(XmlNode node)2220         protected abstract bool Match(XmlNode node);
2221 
2222         public override XPathNavigator Current
2223         {
2224             get { return _nav; }
2225         }
2226 
2227         public override int CurrentPosition
2228         {
2229             get { return _position; }
2230         }
2231 
SetPosition(int pos)2232         protected void SetPosition(int pos)
2233         {
2234             _position = pos;
2235         }
2236 
MoveNext()2237         public override bool MoveNext()
2238         {
2239             for (;;)
2240             {
2241                 if (_nav.MoveToFirstChild())
2242                 {
2243                     _level++;
2244                 }
2245                 else
2246                 {
2247                     if (_level == 0)
2248                     {
2249                         return false;
2250                     }
2251                     while (!_nav.MoveToNext())
2252                     {
2253                         _level--;
2254                         if (_level == 0)
2255                         {
2256                             return false;
2257                         }
2258                         if (!_nav.MoveToParent())
2259                         {
2260                             return false;
2261                         }
2262                     }
2263                 }
2264                 XmlNode node = (XmlNode)_nav.UnderlyingObject;
2265                 if (node.NodeType == XmlNodeType.Element && Match(node))
2266                 {
2267                     _position++;
2268                     return true;
2269                 }
2270             }
2271         }
2272     }
2273 
2274     // Iterate over all element children irrespective of the localName and namespace
2275     internal class DocumentXPathNodeIterator_AllElemChildren : DocumentXPathNodeIterator_ElemDescendants
2276     {
DocumentXPathNodeIterator_AllElemChildren(DocumentXPathNavigator nav)2277         internal DocumentXPathNodeIterator_AllElemChildren(DocumentXPathNavigator nav) : base(nav)
2278         {
2279             Debug.Assert(((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute);
2280         }
DocumentXPathNodeIterator_AllElemChildren(DocumentXPathNodeIterator_AllElemChildren other)2281         internal DocumentXPathNodeIterator_AllElemChildren(DocumentXPathNodeIterator_AllElemChildren other) : base(other)
2282         {
2283         }
2284 
Clone()2285         public override XPathNodeIterator Clone()
2286         {
2287             return new DocumentXPathNodeIterator_AllElemChildren(this);
2288         }
2289 
Match(XmlNode node)2290         protected override bool Match(XmlNode node)
2291         {
2292             Debug.Assert(node != null);
2293             return (node.NodeType == XmlNodeType.Element);
2294         }
2295     }
2296     // Iterate over all element children irrespective of the localName and namespace, include the self node when testing for localName/ns
2297     internal sealed class DocumentXPathNodeIterator_AllElemChildren_AndSelf : DocumentXPathNodeIterator_AllElemChildren
2298     {
DocumentXPathNodeIterator_AllElemChildren_AndSelf(DocumentXPathNavigator nav)2299         internal DocumentXPathNodeIterator_AllElemChildren_AndSelf(DocumentXPathNavigator nav) : base(nav)
2300         {
2301         }
DocumentXPathNodeIterator_AllElemChildren_AndSelf(DocumentXPathNodeIterator_AllElemChildren_AndSelf other)2302         internal DocumentXPathNodeIterator_AllElemChildren_AndSelf(DocumentXPathNodeIterator_AllElemChildren_AndSelf other) : base(other)
2303         {
2304         }
2305 
Clone()2306         public override XPathNodeIterator Clone()
2307         {
2308             return new DocumentXPathNodeIterator_AllElemChildren_AndSelf(this);
2309         }
2310 
MoveNext()2311         public override bool MoveNext()
2312         {
2313             if (CurrentPosition == 0)
2314             {
2315                 DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
2316                 XmlNode node = (XmlNode)nav.UnderlyingObject;
2317                 if (node.NodeType == XmlNodeType.Element && Match(node))
2318                 {
2319                     SetPosition(1);
2320                     return true;
2321                 }
2322             }
2323             return base.MoveNext();
2324         }
2325     }
2326     // Iterate over all element children that have a given namespace but irrespective of the localName
2327     internal class DocumentXPathNodeIterator_ElemChildren_NoLocalName : DocumentXPathNodeIterator_ElemDescendants
2328     {
2329         private string _nsAtom;
2330 
DocumentXPathNodeIterator_ElemChildren_NoLocalName(DocumentXPathNavigator nav, string nsAtom)2331         internal DocumentXPathNodeIterator_ElemChildren_NoLocalName(DocumentXPathNavigator nav, string nsAtom) : base(nav)
2332         {
2333             Debug.Assert(((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute);
2334             Debug.Assert(Ref.Equal(nav.NameTable.Get(nsAtom), nsAtom));
2335             _nsAtom = nsAtom;
2336         }
DocumentXPathNodeIterator_ElemChildren_NoLocalName(DocumentXPathNodeIterator_ElemChildren_NoLocalName other)2337         internal DocumentXPathNodeIterator_ElemChildren_NoLocalName(DocumentXPathNodeIterator_ElemChildren_NoLocalName other) : base(other)
2338         {
2339             _nsAtom = other._nsAtom;
2340         }
Clone()2341         public override XPathNodeIterator Clone()
2342         {
2343             return new DocumentXPathNodeIterator_ElemChildren_NoLocalName(this);
2344         }
2345 
Match(XmlNode node)2346         protected override bool Match(XmlNode node)
2347         {
2348             Debug.Assert(node != null);
2349             Debug.Assert(node.NodeType == XmlNodeType.Element);
2350             return Ref.Equal(node.NamespaceURI, _nsAtom);
2351         }
2352     }
2353     // Iterate over all element children that have a given namespace but irrespective of the localName, include self node when checking for ns
2354     internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName : DocumentXPathNodeIterator_ElemChildren_NoLocalName
2355     {
DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName(DocumentXPathNavigator nav, string nsAtom)2356         internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName(DocumentXPathNavigator nav, string nsAtom) : base(nav, nsAtom)
2357         {
2358         }
DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName(DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName other)2359         internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName(DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName other) : base(other)
2360         {
2361         }
2362 
Clone()2363         public override XPathNodeIterator Clone()
2364         {
2365             return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName(this);
2366         }
2367 
MoveNext()2368         public override bool MoveNext()
2369         {
2370             if (CurrentPosition == 0)
2371             {
2372                 DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
2373                 XmlNode node = (XmlNode)nav.UnderlyingObject;
2374                 if (node.NodeType == XmlNodeType.Element && Match(node))
2375                 {
2376                     SetPosition(1);
2377                     return true;
2378                 }
2379             }
2380             return base.MoveNext();
2381         }
2382     }
2383     // Iterate over all element children that have a given name and namespace
2384     internal class DocumentXPathNodeIterator_ElemChildren : DocumentXPathNodeIterator_ElemDescendants
2385     {
2386         protected string localNameAtom;
2387         protected string nsAtom;
2388 
DocumentXPathNodeIterator_ElemChildren(DocumentXPathNavigator nav, string localNameAtom, string nsAtom)2389         internal DocumentXPathNodeIterator_ElemChildren(DocumentXPathNavigator nav, string localNameAtom, string nsAtom) : base(nav)
2390         {
2391             Debug.Assert(((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute);
2392             Debug.Assert(Ref.Equal(nav.NameTable.Get(localNameAtom), localNameAtom));
2393             Debug.Assert(Ref.Equal(nav.NameTable.Get(nsAtom), nsAtom));
2394             Debug.Assert(localNameAtom.Length > 0);   // Use DocumentXPathNodeIterator_ElemChildren_NoLocalName class for special magic value of localNameAtom
2395 
2396             this.localNameAtom = localNameAtom;
2397             this.nsAtom = nsAtom;
2398         }
2399 
DocumentXPathNodeIterator_ElemChildren(DocumentXPathNodeIterator_ElemChildren other)2400         internal DocumentXPathNodeIterator_ElemChildren(DocumentXPathNodeIterator_ElemChildren other) : base(other)
2401         {
2402             this.localNameAtom = other.localNameAtom;
2403             this.nsAtom = other.nsAtom;
2404         }
2405 
Clone()2406         public override XPathNodeIterator Clone()
2407         {
2408             return new DocumentXPathNodeIterator_ElemChildren(this);
2409         }
2410 
Match(XmlNode node)2411         protected override bool Match(XmlNode node)
2412         {
2413             Debug.Assert(node != null);
2414             Debug.Assert(node.NodeType == XmlNodeType.Element);
2415             return Ref.Equal(node.LocalName, localNameAtom) && Ref.Equal(node.NamespaceURI, nsAtom);
2416         }
2417     }
2418     // Iterate over all elem children and itself and check for the given localName (including the magic value "") and namespace
2419     internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf : DocumentXPathNodeIterator_ElemChildren
2420     {
DocumentXPathNodeIterator_ElemChildren_AndSelf(DocumentXPathNavigator nav, string localNameAtom, string nsAtom)2421         internal DocumentXPathNodeIterator_ElemChildren_AndSelf(DocumentXPathNavigator nav, string localNameAtom, string nsAtom)
2422             : base(nav, localNameAtom, nsAtom)
2423         {
2424             Debug.Assert(localNameAtom.Length > 0);   // Use DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName if localName == String.Empty
2425         }
DocumentXPathNodeIterator_ElemChildren_AndSelf(DocumentXPathNodeIterator_ElemChildren_AndSelf other)2426         internal DocumentXPathNodeIterator_ElemChildren_AndSelf(DocumentXPathNodeIterator_ElemChildren_AndSelf other) : base(other)
2427         {
2428         }
2429 
Clone()2430         public override XPathNodeIterator Clone()
2431         {
2432             return new DocumentXPathNodeIterator_ElemChildren_AndSelf(this);
2433         }
2434 
MoveNext()2435         public override bool MoveNext()
2436         {
2437             if (CurrentPosition == 0)
2438             {
2439                 DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
2440                 XmlNode node = (XmlNode)nav.UnderlyingObject;
2441                 if (node.NodeType == XmlNodeType.Element && Match(node))
2442                 {
2443                     SetPosition(1);
2444                     return true;
2445                 }
2446             }
2447             return base.MoveNext();
2448         }
2449     }
2450 }
2451