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