2016 lines
75 KiB
C#
2016 lines
75 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="DocumentXPathNavigator.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
// <owner current="true" primary="true">[....]</owner>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Text;
|
||
|
using System.Xml.Schema;
|
||
|
using System.Xml.XPath;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
namespace System.Xml {
|
||
|
internal sealed class DocumentXPathNavigator : XPathNavigator, IHasXmlNode {
|
||
|
private XmlDocument document; // owner document
|
||
|
private XmlNode source; // navigator position
|
||
|
private int attributeIndex; // index in attribute collection for attribute
|
||
|
private XmlElement namespaceParent; // parent for namespace
|
||
|
|
||
|
public DocumentXPathNavigator(XmlDocument document, XmlNode node) {
|
||
|
this.document = document;
|
||
|
ResetPosition(node);
|
||
|
}
|
||
|
|
||
|
public DocumentXPathNavigator(DocumentXPathNavigator other) {
|
||
|
document = other.document;
|
||
|
source = other.source;
|
||
|
attributeIndex = other.attributeIndex;
|
||
|
namespaceParent = other.namespaceParent;
|
||
|
}
|
||
|
|
||
|
public override XPathNavigator Clone() {
|
||
|
return new DocumentXPathNavigator(this);
|
||
|
}
|
||
|
|
||
|
public override void SetValue(string value) {
|
||
|
if (value == null) {
|
||
|
throw new ArgumentNullException("value");
|
||
|
}
|
||
|
|
||
|
XmlNode node = source;
|
||
|
XmlNode end;
|
||
|
|
||
|
switch (node.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
if (((XmlAttribute)node).IsNamespace) {
|
||
|
goto default;
|
||
|
}
|
||
|
node.InnerText = value;
|
||
|
break;
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
CalibrateText();
|
||
|
|
||
|
node = source;
|
||
|
end = TextEnd(node);
|
||
|
if (node != end) {
|
||
|
if (node.IsReadOnly) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
|
||
|
}
|
||
|
DeleteToFollowingSibling(node.NextSibling, end);
|
||
|
}
|
||
|
goto case XmlNodeType.Element;
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.ProcessingInstruction:
|
||
|
case XmlNodeType.Comment:
|
||
|
node.InnerText = value;
|
||
|
break;
|
||
|
default:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override XmlNameTable NameTable {
|
||
|
get {
|
||
|
return document.NameTable;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override XPathNodeType NodeType {
|
||
|
get {
|
||
|
CalibrateText();
|
||
|
|
||
|
return (XPathNodeType)source.XPNodeType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string LocalName {
|
||
|
get {
|
||
|
return source.XPLocalName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string NamespaceURI {
|
||
|
get {
|
||
|
XmlAttribute attribute = source as XmlAttribute;
|
||
|
if (attribute != null
|
||
|
&& attribute.IsNamespace) {
|
||
|
return string.Empty;
|
||
|
}
|
||
|
return source.NamespaceURI;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string Name {
|
||
|
get {
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.ProcessingInstruction:
|
||
|
return source.Name;
|
||
|
case XmlNodeType.Attribute:
|
||
|
if (((XmlAttribute)source).IsNamespace) {
|
||
|
string localName = source.LocalName;
|
||
|
if (Ref.Equal(localName, document.strXmlns)) {
|
||
|
return string.Empty; // xmlns declaration
|
||
|
}
|
||
|
return localName; // xmlns:name declaration
|
||
|
}
|
||
|
return source.Name; // attribute
|
||
|
default:
|
||
|
return string.Empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string Prefix {
|
||
|
get {
|
||
|
XmlAttribute attribute = source as XmlAttribute;
|
||
|
if (attribute != null
|
||
|
&& attribute.IsNamespace) {
|
||
|
return string.Empty;
|
||
|
}
|
||
|
return source.Prefix;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string Value {
|
||
|
get {
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
return source.InnerText;
|
||
|
case XmlNodeType.Document:
|
||
|
return ValueDocument;
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
return ValueText;
|
||
|
default:
|
||
|
return source.Value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private string ValueDocument {
|
||
|
get {
|
||
|
XmlElement element = document.DocumentElement;
|
||
|
if (element != null) {
|
||
|
return element.InnerText;
|
||
|
}
|
||
|
return string.Empty;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private string ValueText {
|
||
|
get {
|
||
|
CalibrateText();
|
||
|
|
||
|
string value = source.Value;
|
||
|
XmlNode nextSibling = NextSibling(source);
|
||
|
if (nextSibling != null
|
||
|
&& nextSibling.IsText) {
|
||
|
StringBuilder builder = new StringBuilder(value);
|
||
|
do {
|
||
|
builder.Append(nextSibling.Value);
|
||
|
nextSibling = NextSibling(nextSibling);
|
||
|
}
|
||
|
while (nextSibling != null
|
||
|
&& nextSibling.IsText);
|
||
|
value = builder.ToString();
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string BaseURI {
|
||
|
get {
|
||
|
return source.BaseURI;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool IsEmptyElement {
|
||
|
get {
|
||
|
XmlElement element = source as XmlElement;
|
||
|
if (element != null) {
|
||
|
return element.IsEmpty;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string XmlLang {
|
||
|
get {
|
||
|
return source.XmlLang;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override object UnderlyingObject {
|
||
|
get {
|
||
|
CalibrateText();
|
||
|
|
||
|
return source;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool HasAttributes {
|
||
|
get {
|
||
|
XmlElement element = source as XmlElement;
|
||
|
if (element != null
|
||
|
&& element.HasAttributes) {
|
||
|
XmlAttributeCollection attributes = element.Attributes;
|
||
|
for (int i = 0; i < attributes.Count; i++) {
|
||
|
XmlAttribute attribute = attributes[i];
|
||
|
if (!attribute.IsNamespace) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string GetAttribute(string localName, string namespaceURI) {
|
||
|
return source.GetXPAttribute(localName, namespaceURI);
|
||
|
}
|
||
|
|
||
|
public override bool MoveToAttribute(string localName, string namespaceURI) {
|
||
|
XmlElement element = source as XmlElement;
|
||
|
if (element != null
|
||
|
&& element.HasAttributes) {
|
||
|
XmlAttributeCollection attributes = element.Attributes;
|
||
|
for (int i = 0; i < attributes.Count; i++) {
|
||
|
XmlAttribute attribute = attributes[i];
|
||
|
if (attribute.LocalName == localName
|
||
|
&& attribute.NamespaceURI == namespaceURI) {
|
||
|
if (!attribute.IsNamespace) {
|
||
|
source = attribute;
|
||
|
attributeIndex = i;
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToFirstAttribute() {
|
||
|
XmlElement element = source as XmlElement;
|
||
|
if (element != null
|
||
|
&& element.HasAttributes) {
|
||
|
XmlAttributeCollection attributes = element.Attributes;
|
||
|
for (int i = 0; i < attributes.Count; i++) {
|
||
|
XmlAttribute attribute = attributes[i];
|
||
|
if (!attribute.IsNamespace) {
|
||
|
source = attribute;
|
||
|
attributeIndex = i;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToNextAttribute() {
|
||
|
XmlAttribute attribute = source as XmlAttribute;
|
||
|
if (attribute == null
|
||
|
|| attribute.IsNamespace) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlAttributeCollection attributes;
|
||
|
if (!CheckAttributePosition(attribute, out attributes, attributeIndex)
|
||
|
&& !ResetAttributePosition(attribute, attributes, out attributeIndex)) {
|
||
|
return false;
|
||
|
}
|
||
|
for (int i = attributeIndex + 1; i < attributes.Count; i++) {
|
||
|
attribute = attributes[i];
|
||
|
if (!attribute.IsNamespace) {
|
||
|
source = attribute;
|
||
|
attributeIndex = i;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override string GetNamespace(string name) {
|
||
|
XmlNode node = source;
|
||
|
while (node != null
|
||
|
&& node.NodeType != XmlNodeType.Element) {
|
||
|
XmlAttribute attribute = node as XmlAttribute;
|
||
|
if (attribute != null) {
|
||
|
node = attribute.OwnerElement;
|
||
|
}
|
||
|
else {
|
||
|
node = node.ParentNode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
XmlElement element = node as XmlElement;
|
||
|
if (element != null) {
|
||
|
string localName;
|
||
|
if (name != null
|
||
|
&& name.Length != 0) {
|
||
|
localName = name;
|
||
|
}
|
||
|
else {
|
||
|
localName = document.strXmlns;
|
||
|
}
|
||
|
string namespaceUri = document.strReservedXmlns;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri);
|
||
|
if (attribute != null) {
|
||
|
return attribute.Value;
|
||
|
}
|
||
|
element = element.ParentNode as XmlElement;
|
||
|
}
|
||
|
while (element != null);
|
||
|
}
|
||
|
|
||
|
if (name == document.strXml) {
|
||
|
return document.strReservedXml;
|
||
|
}
|
||
|
else if (name == document.strXmlns) {
|
||
|
return document.strReservedXmlns;
|
||
|
}
|
||
|
return string.Empty;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToNamespace(string name) {
|
||
|
if (name == document.strXmlns) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlElement element = source as XmlElement;
|
||
|
if (element != null) {
|
||
|
string localName;
|
||
|
if (name != null
|
||
|
&& name.Length != 0) {
|
||
|
localName = name;
|
||
|
}
|
||
|
else {
|
||
|
localName = document.strXmlns;
|
||
|
}
|
||
|
string namespaceUri = document.strReservedXmlns;
|
||
|
|
||
|
do {
|
||
|
XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri);
|
||
|
if (attribute != null) {
|
||
|
namespaceParent = (XmlElement)source;
|
||
|
source = attribute;
|
||
|
return true;
|
||
|
}
|
||
|
element = element.ParentNode as XmlElement;
|
||
|
}
|
||
|
while (element != null);
|
||
|
|
||
|
if (name == document.strXml) {
|
||
|
namespaceParent = (XmlElement)source;
|
||
|
source = document.NamespaceXml;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToFirstNamespace(XPathNamespaceScope scope) {
|
||
|
XmlElement element = source as XmlElement;
|
||
|
if (element == null) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlAttributeCollection attributes;
|
||
|
int index = Int32.MaxValue;
|
||
|
switch (scope) {
|
||
|
case XPathNamespaceScope.Local:
|
||
|
if (!element.HasAttributes) {
|
||
|
return false;
|
||
|
}
|
||
|
attributes = element.Attributes;
|
||
|
if (!MoveToFirstNamespaceLocal(attributes, ref index)) {
|
||
|
return false;
|
||
|
}
|
||
|
source = attributes[index];
|
||
|
attributeIndex = index;
|
||
|
namespaceParent = element;
|
||
|
break;
|
||
|
case XPathNamespaceScope.ExcludeXml:
|
||
|
attributes = element.Attributes;
|
||
|
if (!MoveToFirstNamespaceGlobal(ref attributes, ref index)) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlAttribute attribute = attributes[index];
|
||
|
while (Ref.Equal(attribute.LocalName, document.strXml)) {
|
||
|
if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) {
|
||
|
return false;
|
||
|
}
|
||
|
attribute = attributes[index];
|
||
|
}
|
||
|
source = attribute;
|
||
|
attributeIndex = index;
|
||
|
namespaceParent = element;
|
||
|
break;
|
||
|
case XPathNamespaceScope.All:
|
||
|
attributes = element.Attributes;
|
||
|
if (!MoveToFirstNamespaceGlobal(ref attributes, ref index)) {
|
||
|
source = document.NamespaceXml;
|
||
|
// attributeIndex = 0;
|
||
|
}
|
||
|
else {
|
||
|
source = attributes[index];
|
||
|
attributeIndex = index;
|
||
|
}
|
||
|
namespaceParent = element;
|
||
|
break;
|
||
|
default:
|
||
|
Debug.Assert(false);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private static bool MoveToFirstNamespaceLocal(XmlAttributeCollection attributes, ref int index) {
|
||
|
Debug.Assert(attributes != null);
|
||
|
for (int i = attributes.Count - 1; i >= 0; i--) {
|
||
|
XmlAttribute attribute = attributes[i];
|
||
|
if (attribute.IsNamespace) {
|
||
|
index = i;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private static bool MoveToFirstNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index) {
|
||
|
if (MoveToFirstNamespaceLocal(attributes, ref index)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Debug.Assert(attributes != null && attributes.parent != null);
|
||
|
XmlElement element = attributes.parent.ParentNode as XmlElement;
|
||
|
while (element != null) {
|
||
|
if (element.HasAttributes) {
|
||
|
attributes = element.Attributes;
|
||
|
if (MoveToFirstNamespaceLocal(attributes, ref index)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
element = element.ParentNode as XmlElement;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
|
||
|
XmlAttribute attribute = source as XmlAttribute;
|
||
|
if (attribute == null
|
||
|
|| !attribute.IsNamespace) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlAttributeCollection attributes;
|
||
|
int index = attributeIndex;
|
||
|
if (!CheckAttributePosition(attribute, out attributes, index)
|
||
|
&& !ResetAttributePosition(attribute, attributes, out index)) {
|
||
|
return false;
|
||
|
}
|
||
|
Debug.Assert(namespaceParent != null);
|
||
|
switch (scope) {
|
||
|
case XPathNamespaceScope.Local:
|
||
|
if (attribute.OwnerElement != namespaceParent) {
|
||
|
return false;
|
||
|
}
|
||
|
if (!MoveToNextNamespaceLocal(attributes, ref index)) {
|
||
|
return false;
|
||
|
}
|
||
|
source = attributes[index];
|
||
|
attributeIndex = index;
|
||
|
break;
|
||
|
case XPathNamespaceScope.ExcludeXml:
|
||
|
string localName;
|
||
|
do {
|
||
|
if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) {
|
||
|
return false;
|
||
|
}
|
||
|
attribute = attributes[index];
|
||
|
localName = attribute.LocalName;
|
||
|
}
|
||
|
while (PathHasDuplicateNamespace(attribute.OwnerElement, namespaceParent, localName)
|
||
|
|| Ref.Equal(localName, document.strXml));
|
||
|
source = attribute;
|
||
|
attributeIndex = index;
|
||
|
break;
|
||
|
case XPathNamespaceScope.All:
|
||
|
do {
|
||
|
if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) {
|
||
|
if (PathHasDuplicateNamespace(null, namespaceParent, document.strXml)) {
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
source = document.NamespaceXml;
|
||
|
// attributeIndex = 0;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
attribute = attributes[index];
|
||
|
}
|
||
|
while (PathHasDuplicateNamespace(attribute.OwnerElement, namespaceParent, attribute.LocalName));
|
||
|
source = attribute;
|
||
|
attributeIndex = index;
|
||
|
break;
|
||
|
default:
|
||
|
Debug.Assert(false);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private static bool MoveToNextNamespaceLocal(XmlAttributeCollection attributes, ref int index) {
|
||
|
Debug.Assert(attributes != null);
|
||
|
Debug.Assert(0 <= index && index < attributes.Count);
|
||
|
for (int i = index - 1; i >= 0; i--) {
|
||
|
XmlAttribute attribute = attributes[i];
|
||
|
if (attribute.IsNamespace) {
|
||
|
index = i;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private static bool MoveToNextNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index) {
|
||
|
if (MoveToNextNamespaceLocal(attributes, ref index)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Debug.Assert(attributes != null && attributes.parent != null);
|
||
|
XmlElement element = attributes.parent.ParentNode as XmlElement;
|
||
|
while (element != null) {
|
||
|
if (element.HasAttributes) {
|
||
|
attributes = element.Attributes;
|
||
|
if (MoveToFirstNamespaceLocal(attributes, ref index)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
element = element.ParentNode as XmlElement;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private bool PathHasDuplicateNamespace(XmlElement top, XmlElement bottom, string localName) {
|
||
|
string namespaceUri = document.strReservedXmlns;
|
||
|
while (bottom != null
|
||
|
&& bottom != top) {
|
||
|
XmlAttribute attribute = bottom.GetAttributeNode(localName, namespaceUri);
|
||
|
if (attribute != null) {
|
||
|
return true;
|
||
|
}
|
||
|
bottom = bottom.ParentNode as XmlElement;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override string LookupNamespace(string prefix) {
|
||
|
string ns = base.LookupNamespace(prefix);
|
||
|
if (ns != null) {
|
||
|
ns = this.NameTable.Add(ns);
|
||
|
}
|
||
|
return ns;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToNext() {
|
||
|
XmlNode sibling = NextSibling(source);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
if (sibling.IsText) {
|
||
|
if (source.IsText) {
|
||
|
sibling = NextSibling(TextEnd(sibling));
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
XmlNode parent = ParentNode(sibling);
|
||
|
Debug.Assert(parent != null);
|
||
|
while (!IsValidChild(parent, sibling)) {
|
||
|
sibling = NextSibling(sibling);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
source = sibling;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToPrevious() {
|
||
|
XmlNode sibling = PreviousSibling(source);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
if (sibling.IsText) {
|
||
|
if (source.IsText) {
|
||
|
sibling = PreviousSibling(TextStart(sibling));
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
sibling = TextStart(sibling);
|
||
|
}
|
||
|
}
|
||
|
XmlNode parent = ParentNode(sibling);
|
||
|
Debug.Assert(parent != null);
|
||
|
while (!IsValidChild(parent, sibling)) {
|
||
|
sibling = PreviousSibling(sibling);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
// if (sibling.IsText) {
|
||
|
// sibling = TextStart(sibling);
|
||
|
// }
|
||
|
}
|
||
|
source = sibling;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToFirst() {
|
||
|
if (source.NodeType == XmlNodeType.Attribute) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlNode parent = ParentNode(source);
|
||
|
if (parent == null) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlNode sibling = FirstChild(parent);
|
||
|
Debug.Assert(sibling != null);
|
||
|
while (!IsValidChild(parent, sibling)) {
|
||
|
sibling = NextSibling(sibling);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
source = sibling;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToFirstChild() {
|
||
|
XmlNode child;
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
child = FirstChild(source);
|
||
|
if (child == null) {
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
case XmlNodeType.Document:
|
||
|
child = FirstChild(source);
|
||
|
if (child == null) {
|
||
|
return false;
|
||
|
}
|
||
|
while (!IsValidChild(source, child)) {
|
||
|
child = NextSibling(child);
|
||
|
if (child == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return false;
|
||
|
|
||
|
}
|
||
|
source = child;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToParent() {
|
||
|
XmlNode parent = ParentNode(source);
|
||
|
if (parent != null) {
|
||
|
source = parent;
|
||
|
return true;
|
||
|
}
|
||
|
XmlAttribute attribute = source as XmlAttribute;
|
||
|
if (attribute != null) {
|
||
|
parent = attribute.IsNamespace ? namespaceParent : attribute.OwnerElement;
|
||
|
if (parent != null) {
|
||
|
source = parent;
|
||
|
namespaceParent = null;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override void MoveToRoot() {
|
||
|
for (;;) {
|
||
|
XmlNode parent = source.ParentNode;
|
||
|
if (parent == null) {
|
||
|
XmlAttribute attribute = source as XmlAttribute;
|
||
|
if (attribute == null) {
|
||
|
break;
|
||
|
}
|
||
|
parent = attribute.IsNamespace ? namespaceParent : attribute.OwnerElement;
|
||
|
if (parent == null) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
source = parent;
|
||
|
}
|
||
|
namespaceParent = null;
|
||
|
}
|
||
|
|
||
|
public override bool MoveTo(XPathNavigator other) {
|
||
|
DocumentXPathNavigator that = other as DocumentXPathNavigator;
|
||
|
if (that != null
|
||
|
&& document == that.document) {
|
||
|
source = that.source;
|
||
|
attributeIndex = that.attributeIndex;
|
||
|
namespaceParent = that.namespaceParent;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToId(string id) {
|
||
|
XmlElement element = document.GetElementById(id);
|
||
|
if (element != null) {
|
||
|
source = element;
|
||
|
namespaceParent = null;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToChild(string localName, string namespaceUri) {
|
||
|
if (source.NodeType == XmlNodeType.Attribute) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
XmlNode child = FirstChild(source);
|
||
|
if (child != null) {
|
||
|
do {
|
||
|
if (child.NodeType == XmlNodeType.Element
|
||
|
&& child.LocalName == localName
|
||
|
&& child.NamespaceURI == namespaceUri) {
|
||
|
source = child;
|
||
|
return true;
|
||
|
}
|
||
|
child = NextSibling(child);
|
||
|
}
|
||
|
while (child != null);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToChild(XPathNodeType type) {
|
||
|
if (source.NodeType == XmlNodeType.Attribute) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
XmlNode child = FirstChild(source);
|
||
|
if (child != null) {
|
||
|
int mask = GetContentKindMask(type);
|
||
|
if (mask == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
do {
|
||
|
if (((1 << (int)child.XPNodeType) & mask) != 0) {
|
||
|
source = child;
|
||
|
return true;
|
||
|
}
|
||
|
child = NextSibling(child);
|
||
|
}
|
||
|
while (child != null);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToFollowing(string localName, string namespaceUri, XPathNavigator end) {
|
||
|
XmlNode pastFollowing = null;
|
||
|
DocumentXPathNavigator that = end as DocumentXPathNavigator;
|
||
|
if (that != null) {
|
||
|
if (document != that.document) {
|
||
|
return false;
|
||
|
}
|
||
|
switch (that.source.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
that = (DocumentXPathNavigator)that.Clone();
|
||
|
if (!that.MoveToNonDescendant()) {
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
pastFollowing = that.source;
|
||
|
}
|
||
|
|
||
|
XmlNode following = source;
|
||
|
if (following.NodeType == XmlNodeType.Attribute) {
|
||
|
following = ((XmlAttribute)following).OwnerElement;
|
||
|
if (following == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
do {
|
||
|
XmlNode firstChild = following.FirstChild;
|
||
|
if (firstChild != null) {
|
||
|
following = firstChild;
|
||
|
}
|
||
|
else {
|
||
|
for (;;) {
|
||
|
XmlNode nextSibling = following.NextSibling;
|
||
|
if (nextSibling != null) {
|
||
|
following = nextSibling;
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
XmlNode parent = following.ParentNode;
|
||
|
if (parent != null) {
|
||
|
following = parent;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (following == pastFollowing) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
while (following.NodeType != XmlNodeType.Element
|
||
|
|| following.LocalName != localName
|
||
|
|| following.NamespaceURI != namespaceUri);
|
||
|
|
||
|
source = following;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToFollowing(XPathNodeType type, XPathNavigator end) {
|
||
|
XmlNode pastFollowing = null;
|
||
|
DocumentXPathNavigator that = end as DocumentXPathNavigator;
|
||
|
if (that != null) {
|
||
|
if (document != that.document) {
|
||
|
return false;
|
||
|
}
|
||
|
switch (that.source.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
that = (DocumentXPathNavigator)that.Clone();
|
||
|
if (!that.MoveToNonDescendant()) {
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
pastFollowing = that.source;
|
||
|
}
|
||
|
|
||
|
int mask = GetContentKindMask(type);
|
||
|
if (mask == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
XmlNode following = source;
|
||
|
switch (following.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
following = ((XmlAttribute)following).OwnerElement;
|
||
|
if (following == null) {
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
following = TextEnd(following);
|
||
|
break;
|
||
|
}
|
||
|
do {
|
||
|
XmlNode firstChild = following.FirstChild;
|
||
|
if (firstChild != null) {
|
||
|
following = firstChild;
|
||
|
}
|
||
|
else {
|
||
|
for (;;) {
|
||
|
XmlNode nextSibling = following.NextSibling;
|
||
|
if (nextSibling != null) {
|
||
|
following = nextSibling;
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
XmlNode parent = following.ParentNode;
|
||
|
if (parent != null) {
|
||
|
following = parent;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (following == pastFollowing) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
while (((1 << (int)following.XPNodeType) & mask) == 0);
|
||
|
|
||
|
source = following;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToNext(string localName, string namespaceUri) {
|
||
|
XmlNode sibling = NextSibling(source);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
do {
|
||
|
if (sibling.NodeType == XmlNodeType.Element
|
||
|
&& sibling.LocalName == localName
|
||
|
&& sibling.NamespaceURI == namespaceUri) {
|
||
|
source = sibling;
|
||
|
return true;
|
||
|
}
|
||
|
sibling = NextSibling(sibling);
|
||
|
}
|
||
|
while (sibling != null);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool MoveToNext(XPathNodeType type) {
|
||
|
XmlNode sibling = NextSibling(source);
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
if (sibling.IsText
|
||
|
&& source.IsText) {
|
||
|
sibling = NextSibling(TextEnd(sibling));
|
||
|
if (sibling == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int mask = GetContentKindMask(type);
|
||
|
if (mask == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
do {
|
||
|
if (((1 << (int)sibling.XPNodeType) & mask) != 0) {
|
||
|
source = sibling;
|
||
|
return true;
|
||
|
}
|
||
|
sibling = NextSibling(sibling);
|
||
|
}
|
||
|
while (sibling != null);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool HasChildren {
|
||
|
get {
|
||
|
XmlNode child;
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
child = FirstChild(source);
|
||
|
if (child == null) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
case XmlNodeType.Document:
|
||
|
child = FirstChild(source);
|
||
|
if (child == null) {
|
||
|
return false;
|
||
|
}
|
||
|
while (!IsValidChild(source, child)) {
|
||
|
child = NextSibling(child);
|
||
|
if (child == null) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool IsSamePosition(XPathNavigator other) {
|
||
|
DocumentXPathNavigator that = other as DocumentXPathNavigator;
|
||
|
if (that != null) {
|
||
|
this.CalibrateText();
|
||
|
that.CalibrateText();
|
||
|
|
||
|
return this.source == that.source
|
||
|
&& this.namespaceParent == that.namespaceParent;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override bool IsDescendant(XPathNavigator other) {
|
||
|
DocumentXPathNavigator that = other as DocumentXPathNavigator;
|
||
|
if (that != null) {
|
||
|
return IsDescendant(this.source, that.source);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override IXmlSchemaInfo SchemaInfo {
|
||
|
get {
|
||
|
return source.SchemaInfo;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool CheckValidity(XmlSchemaSet schemas, ValidationEventHandler validationEventHandler) {
|
||
|
XmlDocument ownerDocument;
|
||
|
|
||
|
if (source.NodeType == XmlNodeType.Document) {
|
||
|
ownerDocument = (XmlDocument)source;
|
||
|
}
|
||
|
else {
|
||
|
ownerDocument = source.OwnerDocument;
|
||
|
|
||
|
if (schemas != null) {
|
||
|
throw new ArgumentException(Res.GetString(Res.XPathDocument_SchemaSetNotAllowed, null));
|
||
|
}
|
||
|
}
|
||
|
if (schemas == null && ownerDocument != null) {
|
||
|
schemas = ownerDocument.Schemas;
|
||
|
}
|
||
|
|
||
|
if (schemas == null || schemas.Count == 0) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.XmlDocument_NoSchemaInfo));
|
||
|
}
|
||
|
|
||
|
DocumentSchemaValidator validator = new DocumentSchemaValidator(ownerDocument, schemas, validationEventHandler);
|
||
|
validator.PsviAugmentation = false;
|
||
|
return validator.Validate(source);
|
||
|
}
|
||
|
|
||
|
private static XmlNode OwnerNode(XmlNode node) {
|
||
|
XmlNode parent = node.ParentNode;
|
||
|
if (parent != null) {
|
||
|
return parent;
|
||
|
}
|
||
|
XmlAttribute attribute = node as XmlAttribute;
|
||
|
if (attribute != null) {
|
||
|
return attribute.OwnerElement;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
private static int GetDepth(XmlNode node) {
|
||
|
int depth = 0;
|
||
|
XmlNode owner = OwnerNode(node);
|
||
|
while (owner != null) {
|
||
|
depth++;
|
||
|
owner = OwnerNode(owner);
|
||
|
}
|
||
|
return depth;
|
||
|
}
|
||
|
|
||
|
//Assuming that node1 and node2 are in the same level; Except when they are namespace nodes, they should have the same parent node
|
||
|
//the returned value is node2's position corresponding to node1
|
||
|
private XmlNodeOrder Compare( XmlNode node1, XmlNode node2 ) {
|
||
|
Debug.Assert( node1 != null );
|
||
|
Debug.Assert( node2 != null );
|
||
|
Debug.Assert( node1 != node2, "Should be handled by ComparePosition()" );
|
||
|
//Attribute nodes come before other children nodes except namespace nodes
|
||
|
Debug.Assert( OwnerNode(node1) == OwnerNode(node2) );
|
||
|
if (node1.XPNodeType == XPathNodeType.Attribute) {
|
||
|
if (node2.XPNodeType == XPathNodeType.Attribute) {
|
||
|
XmlElement element = ((XmlAttribute)node1).OwnerElement;
|
||
|
if (element.HasAttributes) {
|
||
|
XmlAttributeCollection attributes = element.Attributes;
|
||
|
for (int i = 0; i < attributes.Count; i++) {
|
||
|
XmlAttribute attribute = attributes[i];
|
||
|
if (attribute == node1) {
|
||
|
return XmlNodeOrder.Before;
|
||
|
}
|
||
|
else if (attribute == node2) {
|
||
|
return XmlNodeOrder.After;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return XmlNodeOrder.Unknown;
|
||
|
}
|
||
|
else {
|
||
|
return XmlNodeOrder.Before;
|
||
|
}
|
||
|
}
|
||
|
if (node2.XPNodeType == XPathNodeType.Attribute) {
|
||
|
return XmlNodeOrder.After;
|
||
|
}
|
||
|
|
||
|
//neither of the node is Namespace node or Attribute node
|
||
|
XmlNode nextNode = node1.NextSibling;
|
||
|
while ( nextNode != null && nextNode != node2 )
|
||
|
nextNode = nextNode.NextSibling;
|
||
|
if ( nextNode == null )
|
||
|
//didn't meet node2 in the path to the end, thus it has to be in the front of node1
|
||
|
return XmlNodeOrder.After;
|
||
|
else
|
||
|
//met node2 in the path to the end, so node1 is at front
|
||
|
return XmlNodeOrder.Before;
|
||
|
}
|
||
|
|
||
|
public override XmlNodeOrder ComparePosition(XPathNavigator other) {
|
||
|
DocumentXPathNavigator that = other as DocumentXPathNavigator;
|
||
|
if (that == null) {
|
||
|
return XmlNodeOrder.Unknown;
|
||
|
}
|
||
|
|
||
|
this.CalibrateText();
|
||
|
that.CalibrateText();
|
||
|
|
||
|
if (this.source == that.source
|
||
|
&& this.namespaceParent == that.namespaceParent) {
|
||
|
return XmlNodeOrder.Same;
|
||
|
}
|
||
|
|
||
|
if (this.namespaceParent != null
|
||
|
|| that.namespaceParent != null) {
|
||
|
return base.ComparePosition(other);
|
||
|
}
|
||
|
|
||
|
XmlNode node1 = this.source;
|
||
|
XmlNode node2 = that.source;
|
||
|
|
||
|
XmlNode parent1 = OwnerNode(node1);
|
||
|
XmlNode parent2 = OwnerNode(node2);
|
||
|
if (parent1 == parent2) {
|
||
|
if (parent1 == null) {
|
||
|
return XmlNodeOrder.Unknown;
|
||
|
}
|
||
|
else {
|
||
|
Debug.Assert(node1 != node2);
|
||
|
return Compare(node1, node2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int depth1 = GetDepth(node1);
|
||
|
int depth2 = GetDepth(node2);
|
||
|
if (depth2 > depth1) {
|
||
|
while (node2 != null
|
||
|
&& depth2 > depth1) {
|
||
|
node2 = OwnerNode(node2);
|
||
|
depth2--;
|
||
|
}
|
||
|
if (node1 == node2) {
|
||
|
return XmlNodeOrder.Before;
|
||
|
}
|
||
|
parent2 = OwnerNode(node2);
|
||
|
}
|
||
|
else if (depth1 > depth2) {
|
||
|
while (node1 != null
|
||
|
&& depth1 > depth2) {
|
||
|
node1 = OwnerNode(node1);
|
||
|
depth1--;
|
||
|
}
|
||
|
if (node1 == node2) {
|
||
|
return XmlNodeOrder.After;
|
||
|
}
|
||
|
parent1 = OwnerNode(node1);
|
||
|
}
|
||
|
|
||
|
while (parent1 != null
|
||
|
&& parent2 != null) {
|
||
|
if (parent1 == parent2) {
|
||
|
Debug.Assert(node1 != node2);
|
||
|
return Compare(node1, node2);
|
||
|
}
|
||
|
node1 = parent1;
|
||
|
node2 = parent2;
|
||
|
parent1 = OwnerNode(node1);
|
||
|
parent2 = OwnerNode(node2);
|
||
|
}
|
||
|
return XmlNodeOrder.Unknown;
|
||
|
}
|
||
|
|
||
|
//the function just for XPathNodeList to enumerate current Node.
|
||
|
XmlNode IHasXmlNode.GetNode() { return source; }
|
||
|
|
||
|
public override XPathNodeIterator SelectDescendants( string localName, string namespaceURI, bool matchSelf ) {
|
||
|
string nsAtom = document.NameTable.Get( namespaceURI );
|
||
|
if ( nsAtom == null || this.source.NodeType == XmlNodeType.Attribute )
|
||
|
return new DocumentXPathNodeIterator_Empty( this );
|
||
|
|
||
|
Debug.Assert( this.NodeType != XPathNodeType.Attribute && this.NodeType != XPathNodeType.Namespace && this.NodeType != XPathNodeType.All );
|
||
|
|
||
|
string localNameAtom = document.NameTable.Get( localName );
|
||
|
if ( localNameAtom == null )
|
||
|
return new DocumentXPathNodeIterator_Empty( this );
|
||
|
|
||
|
if ( localNameAtom.Length == 0 ) {
|
||
|
if ( matchSelf )
|
||
|
return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( this, nsAtom );
|
||
|
return new DocumentXPathNodeIterator_ElemChildren_NoLocalName( this, nsAtom );
|
||
|
}
|
||
|
|
||
|
if ( matchSelf )
|
||
|
return new DocumentXPathNodeIterator_ElemChildren_AndSelf( this, localNameAtom, nsAtom );
|
||
|
return new DocumentXPathNodeIterator_ElemChildren( this, localNameAtom, nsAtom );
|
||
|
}
|
||
|
|
||
|
public override XPathNodeIterator SelectDescendants( XPathNodeType nt, bool includeSelf ) {
|
||
|
if ( nt == XPathNodeType.Element ) {
|
||
|
XmlNodeType curNT = source.NodeType;
|
||
|
if ( curNT != XmlNodeType.Document && curNT != XmlNodeType.Element ) {
|
||
|
//only Document, Entity, Element node can have Element node as children ( descendant )
|
||
|
//entity nodes should be invisible to XPath data model
|
||
|
return new DocumentXPathNodeIterator_Empty( this );
|
||
|
}
|
||
|
if ( includeSelf )
|
||
|
return new DocumentXPathNodeIterator_AllElemChildren_AndSelf( this );
|
||
|
return new DocumentXPathNodeIterator_AllElemChildren( this );
|
||
|
}
|
||
|
return base.SelectDescendants( nt, includeSelf );
|
||
|
}
|
||
|
|
||
|
public override bool CanEdit {
|
||
|
get {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override XmlWriter PrependChild() {
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.Document:
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
break;
|
||
|
default:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
|
||
|
DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.PrependChild, source, document);
|
||
|
writer.NamespaceManager = GetNamespaceManager(source, document);
|
||
|
return new XmlWellFormedWriter(writer, writer.Settings);
|
||
|
}
|
||
|
|
||
|
public override XmlWriter AppendChild() {
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.Document:
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
break;
|
||
|
default:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
|
||
|
DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendChild, source, document);
|
||
|
writer.NamespaceManager = GetNamespaceManager(source, document);
|
||
|
return new XmlWellFormedWriter(writer, writer.Settings);
|
||
|
}
|
||
|
|
||
|
public override XmlWriter InsertAfter() {
|
||
|
XmlNode node = source;
|
||
|
|
||
|
switch (node.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
case XmlNodeType.Document:
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
node = TextEnd(node);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingAfter, node, document);
|
||
|
writer.NamespaceManager = GetNamespaceManager(node.ParentNode, document);
|
||
|
return new XmlWellFormedWriter(writer, writer.Settings);
|
||
|
}
|
||
|
|
||
|
public override XmlWriter InsertBefore() {
|
||
|
switch (source.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
case XmlNodeType.Document:
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
CalibrateText();
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingBefore, source, document);
|
||
|
writer.NamespaceManager = GetNamespaceManager(source.ParentNode, document);
|
||
|
return new XmlWellFormedWriter(writer, writer.Settings);
|
||
|
}
|
||
|
|
||
|
public override XmlWriter CreateAttributes() {
|
||
|
if (source.NodeType != XmlNodeType.Element) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
|
||
|
DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendAttribute, source, document);
|
||
|
writer.NamespaceManager = GetNamespaceManager(source, document);
|
||
|
return new XmlWellFormedWriter(writer, writer.Settings);
|
||
|
}
|
||
|
|
||
|
public override XmlWriter ReplaceRange(XPathNavigator lastSiblingToReplace) {
|
||
|
DocumentXPathNavigator that = lastSiblingToReplace as DocumentXPathNavigator;
|
||
|
if (that == null) {
|
||
|
if (lastSiblingToReplace == null) {
|
||
|
throw new ArgumentNullException("lastSiblingToReplace");
|
||
|
}
|
||
|
else {
|
||
|
throw new NotSupportedException();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.CalibrateText();
|
||
|
that.CalibrateText();
|
||
|
|
||
|
XmlNode node = this.source;
|
||
|
XmlNode end = that.source;
|
||
|
|
||
|
if (node == end) {
|
||
|
switch (node.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
case XmlNodeType.Document:
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
end = that.TextEnd(end);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (end.IsText) {
|
||
|
end = that.TextEnd(end);
|
||
|
}
|
||
|
if (!IsFollowingSibling(node, end)) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.ReplaceToFollowingSibling, node, document);
|
||
|
writer.NamespaceManager = GetNamespaceManager(node.ParentNode, document);
|
||
|
writer.Navigator = this;
|
||
|
writer.EndNode = end;
|
||
|
return new XmlWellFormedWriter(writer, writer.Settings);
|
||
|
}
|
||
|
|
||
|
public override void DeleteRange(XPathNavigator lastSiblingToDelete) {
|
||
|
DocumentXPathNavigator that = lastSiblingToDelete as DocumentXPathNavigator;
|
||
|
if (that == null) {
|
||
|
if (lastSiblingToDelete == null) {
|
||
|
throw new ArgumentNullException("lastSiblingToDelete");
|
||
|
}
|
||
|
else {
|
||
|
throw new NotSupportedException();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.CalibrateText();
|
||
|
that.CalibrateText();
|
||
|
|
||
|
XmlNode node = this.source;
|
||
|
XmlNode end = that.source;
|
||
|
|
||
|
if (node == end) {
|
||
|
switch (node.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
XmlAttribute attribute = (XmlAttribute)node;
|
||
|
if (attribute.IsNamespace) {
|
||
|
goto default;
|
||
|
}
|
||
|
XmlNode parent = OwnerNode(attribute);
|
||
|
DeleteAttribute(attribute, attributeIndex);
|
||
|
if (parent != null) {
|
||
|
ResetPosition(parent);
|
||
|
}
|
||
|
break;
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
end = that.TextEnd(end);
|
||
|
goto case XmlNodeType.Element;
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.ProcessingInstruction:
|
||
|
case XmlNodeType.Comment:
|
||
|
parent = OwnerNode(node);
|
||
|
DeleteToFollowingSibling(node, end);
|
||
|
if (parent != null) {
|
||
|
ResetPosition(parent);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (end.IsText) {
|
||
|
end = that.TextEnd(end);
|
||
|
}
|
||
|
if (!IsFollowingSibling(node, end)) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
XmlNode parent = OwnerNode(node);
|
||
|
DeleteToFollowingSibling(node, end);
|
||
|
if (parent != null) {
|
||
|
ResetPosition(parent);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void DeleteSelf() {
|
||
|
XmlNode node = source;
|
||
|
XmlNode end = node;
|
||
|
|
||
|
switch (node.NodeType) {
|
||
|
case XmlNodeType.Attribute:
|
||
|
XmlAttribute attribute = (XmlAttribute)node;
|
||
|
if (attribute.IsNamespace) {
|
||
|
goto default;
|
||
|
}
|
||
|
XmlNode parent = OwnerNode(attribute);
|
||
|
DeleteAttribute(attribute, attributeIndex);
|
||
|
if (parent != null) {
|
||
|
ResetPosition(parent);
|
||
|
}
|
||
|
break;
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
CalibrateText();
|
||
|
|
||
|
node = source;
|
||
|
end = TextEnd(node);
|
||
|
goto case XmlNodeType.Element;
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.ProcessingInstruction:
|
||
|
case XmlNodeType.Comment:
|
||
|
parent = OwnerNode(node);
|
||
|
DeleteToFollowingSibling(node, end);
|
||
|
if (parent != null) {
|
||
|
ResetPosition(parent);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeleteAttribute(XmlAttribute attribute, int index) {
|
||
|
XmlAttributeCollection attributes;
|
||
|
|
||
|
if (!CheckAttributePosition(attribute, out attributes, index)
|
||
|
&& !ResetAttributePosition(attribute, attributes, out index)) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_MissingParent));
|
||
|
}
|
||
|
if (attribute.IsReadOnly) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
|
||
|
}
|
||
|
attributes.RemoveAt(index);
|
||
|
}
|
||
|
|
||
|
internal static void DeleteToFollowingSibling(XmlNode node, XmlNode end) {
|
||
|
XmlNode parent = node.ParentNode;
|
||
|
|
||
|
if (parent == null) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xpn_MissingParent));
|
||
|
}
|
||
|
if (node.IsReadOnly
|
||
|
|| end.IsReadOnly) {
|
||
|
throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
|
||
|
}
|
||
|
while (node != end) {
|
||
|
XmlNode temp = node;
|
||
|
node = node.NextSibling;
|
||
|
parent.RemoveChild(temp);
|
||
|
}
|
||
|
parent.RemoveChild(node);
|
||
|
}
|
||
|
|
||
|
private static XmlNamespaceManager GetNamespaceManager(XmlNode node, XmlDocument document) {
|
||
|
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
|
||
|
List<XmlElement> elements = new List<XmlElement>();
|
||
|
|
||
|
while (node != null) {
|
||
|
XmlElement element = node as XmlElement;
|
||
|
if (element != null
|
||
|
&& element.HasAttributes) {
|
||
|
elements.Add(element);
|
||
|
}
|
||
|
node = node.ParentNode;
|
||
|
}
|
||
|
for (int i = elements.Count - 1; i >= 0; i--) {
|
||
|
namespaceManager.PushScope();
|
||
|
XmlAttributeCollection attributes = elements[i].Attributes;
|
||
|
for (int j = 0; j < attributes.Count; j++) {
|
||
|
XmlAttribute attribute = attributes[j];
|
||
|
if (attribute.IsNamespace) {
|
||
|
string prefix = attribute.Prefix.Length == 0 ? string.Empty : attribute.LocalName;
|
||
|
namespaceManager.AddNamespace(prefix, attribute.Value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return namespaceManager;
|
||
|
}
|
||
|
|
||
|
internal void ResetPosition(XmlNode node) {
|
||
|
Debug.Assert(node != null, "Undefined navigator position");
|
||
|
Debug.Assert(node == document || node.OwnerDocument == document, "Navigator switched documents");
|
||
|
source = node;
|
||
|
XmlAttribute attribute = node as XmlAttribute;
|
||
|
if (attribute != null) {
|
||
|
XmlElement element = attribute.OwnerElement;
|
||
|
if (element != null) {
|
||
|
ResetAttributePosition(attribute, element.Attributes, out attributeIndex);
|
||
|
if (attribute.IsNamespace) {
|
||
|
namespaceParent = element;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static bool ResetAttributePosition(XmlAttribute attribute, XmlAttributeCollection attributes, out int index) {
|
||
|
if (attributes != null) {
|
||
|
for (int i = 0; i < attributes.Count; i++) {
|
||
|
if (attribute == attributes[i]) {
|
||
|
index = i;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
index = 0;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private static bool CheckAttributePosition(XmlAttribute attribute, out XmlAttributeCollection attributes, int index) {
|
||
|
XmlElement element = attribute.OwnerElement;
|
||
|
if (element != null) {
|
||
|
attributes = element.Attributes;
|
||
|
if (index >= 0
|
||
|
&& index < attributes.Count
|
||
|
&& attribute == attributes[index]) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
attributes = null;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private void CalibrateText() {
|
||
|
XmlNode text = PreviousText(source);
|
||
|
while (text != null) {
|
||
|
ResetPosition(text);
|
||
|
text = PreviousText(text);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private XmlNode ParentNode(XmlNode node) {
|
||
|
XmlNode parent = node.ParentNode;
|
||
|
|
||
|
if (!document.HasEntityReferences) {
|
||
|
return parent;
|
||
|
}
|
||
|
return ParentNodeTail(parent);
|
||
|
}
|
||
|
|
||
|
private XmlNode ParentNodeTail(XmlNode parent) {
|
||
|
while (parent != null
|
||
|
&& parent.NodeType == XmlNodeType.EntityReference) {
|
||
|
parent = parent.ParentNode;
|
||
|
}
|
||
|
return parent;
|
||
|
}
|
||
|
|
||
|
private XmlNode FirstChild(XmlNode node) {
|
||
|
XmlNode child = node.FirstChild;
|
||
|
|
||
|
if (!document.HasEntityReferences) {
|
||
|
return child;
|
||
|
}
|
||
|
return FirstChildTail(child);
|
||
|
}
|
||
|
|
||
|
private XmlNode FirstChildTail(XmlNode child) {
|
||
|
while (child != null
|
||
|
&& child.NodeType == XmlNodeType.EntityReference) {
|
||
|
child = child.FirstChild;
|
||
|
}
|
||
|
return child;
|
||
|
}
|
||
|
|
||
|
private XmlNode NextSibling(XmlNode node) {
|
||
|
XmlNode sibling = node.NextSibling;
|
||
|
|
||
|
if (!document.HasEntityReferences) {
|
||
|
return sibling;
|
||
|
}
|
||
|
return NextSiblingTail(node, sibling);
|
||
|
}
|
||
|
|
||
|
private XmlNode NextSiblingTail(XmlNode node, XmlNode sibling) {
|
||
|
while (sibling == null) {
|
||
|
node = node.ParentNode;
|
||
|
if (node == null
|
||
|
|| node.NodeType != XmlNodeType.EntityReference) {
|
||
|
return null;
|
||
|
}
|
||
|
sibling = node.NextSibling;
|
||
|
}
|
||
|
while (sibling != null
|
||
|
&& sibling.NodeType == XmlNodeType.EntityReference) {
|
||
|
sibling = sibling.FirstChild;
|
||
|
}
|
||
|
return sibling;
|
||
|
}
|
||
|
|
||
|
private XmlNode PreviousSibling(XmlNode node) {
|
||
|
XmlNode sibling = node.PreviousSibling;
|
||
|
|
||
|
if (!document.HasEntityReferences) {
|
||
|
return sibling;
|
||
|
}
|
||
|
return PreviousSiblingTail(node, sibling);
|
||
|
}
|
||
|
|
||
|
private XmlNode PreviousSiblingTail(XmlNode node, XmlNode sibling) {
|
||
|
while (sibling == null) {
|
||
|
node = node.ParentNode;
|
||
|
if (node == null
|
||
|
|| node.NodeType != XmlNodeType.EntityReference) {
|
||
|
return null;
|
||
|
}
|
||
|
sibling = node.PreviousSibling;
|
||
|
}
|
||
|
while (sibling != null
|
||
|
&& sibling.NodeType == XmlNodeType.EntityReference) {
|
||
|
sibling = sibling.LastChild;
|
||
|
}
|
||
|
return sibling;
|
||
|
}
|
||
|
|
||
|
private XmlNode PreviousText(XmlNode node) {
|
||
|
XmlNode text = node.PreviousText;
|
||
|
|
||
|
if (!document.HasEntityReferences) {
|
||
|
return text;
|
||
|
}
|
||
|
return PreviousTextTail(node, text);
|
||
|
}
|
||
|
|
||
|
private XmlNode PreviousTextTail(XmlNode node, XmlNode text) {
|
||
|
if (text != null) {
|
||
|
return text;
|
||
|
}
|
||
|
if (!node.IsText) {
|
||
|
return null;
|
||
|
}
|
||
|
XmlNode sibling = node.PreviousSibling;
|
||
|
while (sibling == null) {
|
||
|
node = node.ParentNode;
|
||
|
if (node == null
|
||
|
|| node.NodeType != XmlNodeType.EntityReference) {
|
||
|
return null;
|
||
|
}
|
||
|
sibling = node.PreviousSibling;
|
||
|
}
|
||
|
while (sibling != null) {
|
||
|
switch (sibling.NodeType) {
|
||
|
case XmlNodeType.EntityReference:
|
||
|
sibling = sibling.LastChild;
|
||
|
break;
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
return sibling;
|
||
|
default:
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
internal static bool IsFollowingSibling(XmlNode left, XmlNode right) {
|
||
|
for (;;) {
|
||
|
left = left.NextSibling;
|
||
|
if (left == null) {
|
||
|
break;
|
||
|
}
|
||
|
if (left == right) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private static bool IsDescendant(XmlNode top, XmlNode bottom) {
|
||
|
for (;;) {
|
||
|
XmlNode parent = bottom.ParentNode;
|
||
|
if (parent == null) {
|
||
|
XmlAttribute attribute = bottom as XmlAttribute;
|
||
|
if (attribute == null) {
|
||
|
break;
|
||
|
}
|
||
|
parent = attribute.OwnerElement;
|
||
|
if (parent == null) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
bottom = parent;
|
||
|
if (top == bottom) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private static bool IsValidChild(XmlNode parent, XmlNode child) {
|
||
|
switch (parent.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
return true;
|
||
|
case XmlNodeType.DocumentFragment:
|
||
|
switch (child.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.Text:
|
||
|
case XmlNodeType.CDATA:
|
||
|
case XmlNodeType.ProcessingInstruction:
|
||
|
case XmlNodeType.Comment:
|
||
|
case XmlNodeType.Whitespace:
|
||
|
case XmlNodeType.SignificantWhitespace:
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
case XmlNodeType.Document:
|
||
|
switch (child.NodeType) {
|
||
|
case XmlNodeType.Element:
|
||
|
case XmlNodeType.ProcessingInstruction:
|
||
|
case XmlNodeType.Comment:
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private XmlNode TextStart(XmlNode node) {
|
||
|
XmlNode start;
|
||
|
|
||
|
do {
|
||
|
start = node;
|
||
|
node = PreviousSibling(node);
|
||
|
}
|
||
|
while (node != null
|
||
|
&& node.IsText);
|
||
|
return start;
|
||
|
}
|
||
|
|
||
|
private XmlNode TextEnd(XmlNode node) {
|
||
|
XmlNode end;
|
||
|
|
||
|
do {
|
||
|
end = node;
|
||
|
node = NextSibling(node);
|
||
|
}
|
||
|
while (node != null
|
||
|
&& node.IsText);
|
||
|
return end;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// An iterator that matches no nodes
|
||
|
internal sealed class DocumentXPathNodeIterator_Empty : XPathNodeIterator {
|
||
|
private XPathNavigator nav;
|
||
|
|
||
|
internal DocumentXPathNodeIterator_Empty( DocumentXPathNavigator nav ) { this.nav = nav.Clone(); }
|
||
|
internal DocumentXPathNodeIterator_Empty( DocumentXPathNodeIterator_Empty other ) { this.nav = other.nav.Clone(); }
|
||
|
public override XPathNodeIterator Clone() { return new DocumentXPathNodeIterator_Empty( this ); }
|
||
|
public override bool MoveNext() { return false; }
|
||
|
public override XPathNavigator Current { get { return nav; } }
|
||
|
public override int CurrentPosition { get { return 0; } }
|
||
|
public override int Count { get { return 0; } }
|
||
|
}
|
||
|
|
||
|
// An iterator that can match any child elements that match the Match condition (overrided in the derived class)
|
||
|
internal abstract class DocumentXPathNodeIterator_ElemDescendants : XPathNodeIterator {
|
||
|
private DocumentXPathNavigator nav;
|
||
|
private int level;
|
||
|
private int position;
|
||
|
|
||
|
internal DocumentXPathNodeIterator_ElemDescendants( DocumentXPathNavigator nav ) {
|
||
|
this.nav = (DocumentXPathNavigator)(nav.Clone());
|
||
|
this.level = 0;
|
||
|
this.position = 0;
|
||
|
}
|
||
|
internal DocumentXPathNodeIterator_ElemDescendants( DocumentXPathNodeIterator_ElemDescendants other ) {
|
||
|
this.nav = (DocumentXPathNavigator)(other.nav.Clone());
|
||
|
this.level = other.level;
|
||
|
this.position = other.position;
|
||
|
}
|
||
|
|
||
|
protected abstract bool Match( XmlNode node );
|
||
|
|
||
|
public override XPathNavigator Current {
|
||
|
get { return nav; }
|
||
|
}
|
||
|
|
||
|
public override int CurrentPosition {
|
||
|
get { return position; }
|
||
|
}
|
||
|
|
||
|
protected void SetPosition( int pos ) {
|
||
|
position = pos;
|
||
|
}
|
||
|
|
||
|
public override bool MoveNext() {
|
||
|
for (;;) {
|
||
|
if (nav.MoveToFirstChild()) {
|
||
|
level++;
|
||
|
}
|
||
|
else {
|
||
|
if (level == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
while (!nav.MoveToNext()) {
|
||
|
level--;
|
||
|
if (level == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
if (!nav.MoveToParent()) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
XmlNode node = (XmlNode)nav.UnderlyingObject;
|
||
|
if (node.NodeType == XmlNodeType.Element && Match(node)) {
|
||
|
position++;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Iterate over all element children irrespective of the localName and namespace
|
||
|
internal class DocumentXPathNodeIterator_AllElemChildren : DocumentXPathNodeIterator_ElemDescendants {
|
||
|
internal DocumentXPathNodeIterator_AllElemChildren( DocumentXPathNavigator nav ) : base( nav ) {
|
||
|
Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
|
||
|
}
|
||
|
internal DocumentXPathNodeIterator_AllElemChildren( DocumentXPathNodeIterator_AllElemChildren other ) : base( other ) {
|
||
|
}
|
||
|
|
||
|
public override XPathNodeIterator Clone() {
|
||
|
return new DocumentXPathNodeIterator_AllElemChildren( this );
|
||
|
}
|
||
|
|
||
|
protected override bool Match( XmlNode node ) {
|
||
|
Debug.Assert( node != null );
|
||
|
return ( node.NodeType == XmlNodeType.Element );
|
||
|
}
|
||
|
}
|
||
|
// Iterate over all element children irrespective of the localName and namespace, include the self node when testing for localName/ns
|
||
|
internal sealed class DocumentXPathNodeIterator_AllElemChildren_AndSelf : DocumentXPathNodeIterator_AllElemChildren {
|
||
|
internal DocumentXPathNodeIterator_AllElemChildren_AndSelf( DocumentXPathNavigator nav ) : base( nav ) {
|
||
|
}
|
||
|
internal DocumentXPathNodeIterator_AllElemChildren_AndSelf( DocumentXPathNodeIterator_AllElemChildren_AndSelf other ) : base( other ) {
|
||
|
}
|
||
|
|
||
|
public override XPathNodeIterator Clone() {
|
||
|
return new DocumentXPathNodeIterator_AllElemChildren_AndSelf( this );
|
||
|
}
|
||
|
|
||
|
public override bool MoveNext() {
|
||
|
if( CurrentPosition == 0 ) {
|
||
|
DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
|
||
|
XmlNode node = (XmlNode)nav.UnderlyingObject;
|
||
|
if ( node.NodeType == XmlNodeType.Element && Match( node ) ) {
|
||
|
SetPosition( 1 );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return base.MoveNext();
|
||
|
}
|
||
|
}
|
||
|
// Iterate over all element children that have a given namespace but irrespective of the localName
|
||
|
internal class DocumentXPathNodeIterator_ElemChildren_NoLocalName : DocumentXPathNodeIterator_ElemDescendants {
|
||
|
private string nsAtom;
|
||
|
|
||
|
internal DocumentXPathNodeIterator_ElemChildren_NoLocalName( DocumentXPathNavigator nav, string nsAtom ) : base( nav ) {
|
||
|
Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
|
||
|
Debug.Assert( Ref.Equal(nav.NameTable.Get( nsAtom ), nsAtom) );
|
||
|
this.nsAtom = nsAtom;
|
||
|
}
|
||
|
internal DocumentXPathNodeIterator_ElemChildren_NoLocalName( DocumentXPathNodeIterator_ElemChildren_NoLocalName other ) : base( other ) {
|
||
|
this.nsAtom = other.nsAtom;
|
||
|
}
|
||
|
public override XPathNodeIterator Clone() {
|
||
|
return new DocumentXPathNodeIterator_ElemChildren_NoLocalName( this );
|
||
|
}
|
||
|
|
||
|
protected override bool Match( XmlNode node ) {
|
||
|
Debug.Assert( node != null );
|
||
|
Debug.Assert( node.NodeType == XmlNodeType.Element );
|
||
|
return Ref.Equal(node.NamespaceURI, nsAtom);
|
||
|
}
|
||
|
}
|
||
|
// Iterate over all element children that have a given namespace but irrespective of the localName, include self node when checking for ns
|
||
|
internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName : DocumentXPathNodeIterator_ElemChildren_NoLocalName {
|
||
|
|
||
|
internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( DocumentXPathNavigator nav, string nsAtom ) : base( nav, nsAtom ) {
|
||
|
}
|
||
|
internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName other ) : base( other ) {
|
||
|
}
|
||
|
|
||
|
public override XPathNodeIterator Clone() {
|
||
|
return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( this );
|
||
|
}
|
||
|
|
||
|
public override bool MoveNext() {
|
||
|
if( CurrentPosition == 0 ) {
|
||
|
DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
|
||
|
XmlNode node = (XmlNode)nav.UnderlyingObject;
|
||
|
if ( node.NodeType == XmlNodeType.Element && Match( node ) ) {
|
||
|
SetPosition( 1 );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return base.MoveNext();
|
||
|
}
|
||
|
}
|
||
|
// Iterate over all element children that have a given name and namespace
|
||
|
internal class DocumentXPathNodeIterator_ElemChildren : DocumentXPathNodeIterator_ElemDescendants {
|
||
|
protected string localNameAtom;
|
||
|
protected string nsAtom;
|
||
|
|
||
|
internal DocumentXPathNodeIterator_ElemChildren( DocumentXPathNavigator nav, string localNameAtom, string nsAtom ) : base( nav ) {
|
||
|
Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
|
||
|
Debug.Assert( Ref.Equal(nav.NameTable.Get( localNameAtom ), localNameAtom) );
|
||
|
Debug.Assert( Ref.Equal(nav.NameTable.Get( nsAtom ), nsAtom) );
|
||
|
Debug.Assert( localNameAtom.Length > 0 ); // Use DocumentXPathNodeIterator_ElemChildren_NoLocalName class for special magic value of localNameAtom
|
||
|
|
||
|
this.localNameAtom = localNameAtom;
|
||
|
this.nsAtom = nsAtom;
|
||
|
}
|
||
|
|
||
|
internal DocumentXPathNodeIterator_ElemChildren( DocumentXPathNodeIterator_ElemChildren other ) : base( other ) {
|
||
|
this.localNameAtom = other.localNameAtom;
|
||
|
this.nsAtom = other.nsAtom;
|
||
|
}
|
||
|
|
||
|
public override XPathNodeIterator Clone() {
|
||
|
return new DocumentXPathNodeIterator_ElemChildren( this );
|
||
|
}
|
||
|
|
||
|
protected override bool Match( XmlNode node ) {
|
||
|
Debug.Assert( node != null );
|
||
|
Debug.Assert( node.NodeType == XmlNodeType.Element );
|
||
|
return Ref.Equal(node.LocalName, localNameAtom) && Ref.Equal(node.NamespaceURI, nsAtom);
|
||
|
}
|
||
|
}
|
||
|
// Iterate over all elem children and itself and check for the given localName (including the magic value "") and namespace
|
||
|
internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf : DocumentXPathNodeIterator_ElemChildren {
|
||
|
|
||
|
internal DocumentXPathNodeIterator_ElemChildren_AndSelf( DocumentXPathNavigator nav, string localNameAtom, string nsAtom )
|
||
|
: base( nav, localNameAtom, nsAtom ) {
|
||
|
Debug.Assert( localNameAtom.Length > 0 ); // Use DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName if localName == String.Empty
|
||
|
}
|
||
|
internal DocumentXPathNodeIterator_ElemChildren_AndSelf( DocumentXPathNodeIterator_ElemChildren_AndSelf other ) : base( other ) {
|
||
|
}
|
||
|
|
||
|
public override XPathNodeIterator Clone() {
|
||
|
return new DocumentXPathNodeIterator_ElemChildren_AndSelf( this );
|
||
|
}
|
||
|
|
||
|
public override bool MoveNext() {
|
||
|
if( CurrentPosition == 0 ) {
|
||
|
DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
|
||
|
XmlNode node = (XmlNode)nav.UnderlyingObject;
|
||
|
if ( node.NodeType == XmlNodeType.Element && Match( node ) ) {
|
||
|
SetPosition( 1 );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return base.MoveNext();
|
||
|
}
|
||
|
}
|
||
|
}
|