|
//------------------------------------------------------------------------------
// <copyright file="XPathNavigator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System.ComponentModel;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Schema;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
using System.Text;
using System.Xml;
using MS.Internal.Xml.Cache;
using MS.Internal.Xml.XPath;
namespace System.Xml.XPath {
// Provides a navigation interface API using XPath data model.
[DebuggerDisplay("{debuggerDisplayProxy}")]
#if CONTRACTS_FULL
[ContractClass(typeof(XPathNavigatorContract))]
#endif
public abstract class XPathNavigator : XPathItem, ICloneable, IXPathNavigable, IXmlNamespaceResolver {
internal static readonly XPathNavigatorKeyComparer comparer = new XPathNavigatorKeyComparer();
//-----------------------------------------------
// Object
//-----------------------------------------------
public override string ToString() {
return Value;
}
//-----------------------------------------------
// XPathItem
//-----------------------------------------------
public override sealed bool IsNode {
get { return true; }
}
public override XmlSchemaType XmlType {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
XmlSchemaType memberType = schemaInfo.MemberType;
if (memberType != null) {
return memberType;
}
return schemaInfo.SchemaType;
}
}
return null;
}
}
public virtual void SetValue(string value) {
throw new NotSupportedException();
}
public override object TypedValue {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ChangeType(Value, datatype.ValueType, this);
}
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ChangeType(datatype.ParseValue(Value, NameTable, this), datatype.ValueType, this);
}
}
}
}
return Value;
}
}
public virtual void SetTypedValue(object typedValue) {
if (typedValue == null) {
throw new ArgumentNullException("typedValue");
}
switch (NodeType) {
case XPathNodeType.Element:
case XPathNodeType.Attribute:
break;
default:
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
string value = null;
IXmlSchemaInfo schemaInfo = SchemaInfo;
if (schemaInfo != null) {
XmlSchemaType schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
value = schemaType.ValueConverter.ToString(typedValue, this);
XmlSchemaDatatype datatype = schemaType.Datatype;
if (datatype != null) {
datatype.ParseValue(value, NameTable, this);
}
}
}
if (value == null) {
value = XmlUntypedConverter.Untyped.ToString(typedValue, this);
}
SetValue(value);
}
public override Type ValueType {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return datatype.ValueType;
}
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return datatype.ValueType;
}
}
}
}
return typeof(string);
}
}
public override bool ValueAsBoolean {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
return schemaType.ValueConverter.ToBoolean(Value);
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ToBoolean(datatype.ParseValue(Value, NameTable, this));
}
}
}
}
return XmlUntypedConverter.Untyped.ToBoolean(Value);
}
}
public override DateTime ValueAsDateTime {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
return schemaType.ValueConverter.ToDateTime(Value);
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ToDateTime(datatype.ParseValue(Value, NameTable, this));
}
}
}
}
return XmlUntypedConverter.Untyped.ToDateTime(Value);
}
}
public override double ValueAsDouble {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
return schemaType.ValueConverter.ToDouble(Value);
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ToDouble(datatype.ParseValue(Value, NameTable, this));
}
}
}
}
return XmlUntypedConverter.Untyped.ToDouble(Value);
}
}
public override int ValueAsInt {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
return schemaType.ValueConverter.ToInt32(Value);
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ToInt32(datatype.ParseValue(Value, NameTable, this));
}
}
}
}
return XmlUntypedConverter.Untyped.ToInt32(Value);
}
}
public override long ValueAsLong {
get {
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
return schemaType.ValueConverter.ToInt64(Value);
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ToInt64(datatype.ParseValue(Value, NameTable, this));
}
}
}
}
return XmlUntypedConverter.Untyped.ToInt64(Value);
}
}
public override object ValueAs(Type returnType, IXmlNamespaceResolver nsResolver) {
if (nsResolver == null) {
nsResolver = this;
}
IXmlSchemaInfo schemaInfo = SchemaInfo;
XmlSchemaType schemaType;
XmlSchemaDatatype datatype;
if (schemaInfo != null) {
if (schemaInfo.Validity == XmlSchemaValidity.Valid) {
schemaType = schemaInfo.MemberType;
if (schemaType == null) {
schemaType = schemaInfo.SchemaType;
}
if (schemaType != null) {
return schemaType.ValueConverter.ChangeType(Value, returnType, nsResolver);
}
}
else {
schemaType = schemaInfo.SchemaType;
if (schemaType != null) {
datatype = schemaType.Datatype;
if (datatype != null) {
return schemaType.ValueConverter.ChangeType(datatype.ParseValue(Value, NameTable, nsResolver), returnType, nsResolver);
}
}
}
}
return XmlUntypedConverter.Untyped.ChangeType(Value, returnType, nsResolver);
}
//-----------------------------------------------
// ICloneable
//-----------------------------------------------
object ICloneable.Clone() {
return Clone();
}
//-----------------------------------------------
// IXPathNavigable
//-----------------------------------------------
public virtual XPathNavigator CreateNavigator() {
return Clone();
}
//-----------------------------------------------
// IXmlNamespaceResolver
//-----------------------------------------------
public abstract XmlNameTable NameTable { get; }
public virtual string LookupNamespace(string prefix) {
if (prefix == null)
return null;
if (NodeType != XPathNodeType.Element) {
XPathNavigator navSave = Clone();
// If current item is not an element, then try parent
if (navSave.MoveToParent())
return navSave.LookupNamespace(prefix);
}
else if (MoveToNamespace(prefix)) {
string namespaceURI = Value;
MoveToParent();
return namespaceURI;
}
// Check for "", "xml", and "xmlns" prefixes
if (prefix.Length == 0)
return string.Empty;
else if (prefix == "xml")
return XmlReservedNs.NsXml;
else if (prefix == "xmlns")
return XmlReservedNs.NsXmlNs;
return null;
}
public virtual string LookupPrefix(string namespaceURI) {
if (namespaceURI == null)
return null;
XPathNavigator navClone = Clone();
if (NodeType != XPathNodeType.Element) {
// If current item is not an element, then try parent
if (navClone.MoveToParent())
return navClone.LookupPrefix(namespaceURI);
}
else {
if (navClone.MoveToFirstNamespace(XPathNamespaceScope.All)) {
// Loop until a matching namespace is found
do {
if (namespaceURI == navClone.Value)
return navClone.LocalName;
}
while (navClone.MoveToNextNamespace(XPathNamespaceScope.All));
}
}
// Check for default, "xml", and "xmlns" namespaces
if (namespaceURI == LookupNamespace(string.Empty))
return string.Empty;
else if (namespaceURI == XmlReservedNs.NsXml)
return "xml";
else if (namespaceURI == XmlReservedNs.NsXmlNs)
return "xmlns";
return null;
}
// This pragma disables a warning that the return type is not CLS-compliant, but generics are part of CLS in Whidbey.
#pragma warning disable 3002
public virtual IDictionary<string,string> GetNamespacesInScope(XmlNamespaceScope scope) {
#pragma warning restore 3002
XPathNodeType nt = NodeType;
if ((nt != XPathNodeType.Element && scope != XmlNamespaceScope.Local) || nt == XPathNodeType.Attribute || nt == XPathNodeType.Namespace) {
XPathNavigator navSave = Clone();
// If current item is not an element, then try parent
if (navSave.MoveToParent())
return navSave.GetNamespacesInScope(scope);
}
Dictionary<string,string> dict = new Dictionary<string,string>();
// "xml" prefix always in scope
if (scope == XmlNamespaceScope.All)
dict["xml"] = XmlReservedNs.NsXml;
// Now add all in-scope namespaces
if (MoveToFirstNamespace((XPathNamespaceScope) scope)) {
do {
string prefix = LocalName;
string ns = Value;
// Exclude xmlns="" declarations unless scope = Local
if (prefix.Length != 0 || ns.Length != 0 || scope == XmlNamespaceScope.Local)
dict[prefix] = ns;
}
while (MoveToNextNamespace((XPathNamespaceScope) scope));
MoveToParent();
}
return dict;
}
//-----------------------------------------------
// XPathNavigator
//-----------------------------------------------
// Returns an object of type IKeyComparer. Using this the navigators can be hashed
// on the basis of actual position it represents rather than the clr reference of
// the navigator object.
public static IEqualityComparer NavigatorComparer {
get { return comparer; }
}
public abstract XPathNavigator Clone();
public abstract XPathNodeType NodeType { get; }
public abstract string LocalName { get; }
public abstract string Name { get; }
public abstract string NamespaceURI { get; }
public abstract string Prefix { get; }
public abstract string BaseURI { get; }
public abstract bool IsEmptyElement { get; }
public virtual string XmlLang {
get {
XPathNavigator navClone = Clone();
do {
if (navClone.MoveToAttribute("lang", XmlReservedNs.NsXml))
return navClone.Value;
}
while (navClone.MoveToParent());
return string.Empty;
}
}
public virtual XmlReader ReadSubtree() {
switch (NodeType) {
case XPathNodeType.Root:
case XPathNodeType.Element:
break;
default:
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
return CreateReader();
}
public virtual void WriteSubtree(XmlWriter writer) {
if (null == writer)
throw new ArgumentNullException("writer");
writer.WriteNode(this, true);
}
public virtual object UnderlyingObject {
get { return null; }
}
public virtual bool HasAttributes {
get {
if (!MoveToFirstAttribute())
return false;
MoveToParent();
return true;
}
}
public virtual string GetAttribute(string localName, string namespaceURI) {
string value;
if (!MoveToAttribute(localName, namespaceURI))
return "";
value = Value;
MoveToParent();
return value;
}
public virtual bool MoveToAttribute(string localName, string namespaceURI) {
if (MoveToFirstAttribute()) {
do {
if (localName == LocalName && namespaceURI == NamespaceURI)
return true;
}
while (MoveToNextAttribute());
MoveToParent();
}
return false;
}
public abstract bool MoveToFirstAttribute();
public abstract bool MoveToNextAttribute();
public virtual string GetNamespace(string name) {
string value;
if (!MoveToNamespace(name)) {
if (name == "xml")
return XmlReservedNs.NsXml;
if (name == "xmlns")
return XmlReservedNs.NsXmlNs;
return string.Empty;
}
value = Value;
MoveToParent();
return value;
}
public virtual bool MoveToNamespace(string name) {
if (MoveToFirstNamespace(XPathNamespaceScope.All)) {
do {
if (name == LocalName)
return true;
}
while (MoveToNextNamespace(XPathNamespaceScope.All));
MoveToParent();
}
return false;
}
public abstract bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope);
public abstract bool MoveToNextNamespace(XPathNamespaceScope namespaceScope);
public bool MoveToFirstNamespace() { return MoveToFirstNamespace(XPathNamespaceScope.All); }
public bool MoveToNextNamespace() { return MoveToNextNamespace(XPathNamespaceScope.All); }
public abstract bool MoveToNext();
public abstract bool MoveToPrevious();
public virtual bool MoveToFirst() {
switch (NodeType) {
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
// MoveToFirst should only succeed for content-typed nodes
return false;
}
if (!MoveToParent())
return false;
return MoveToFirstChild();
}
public abstract bool MoveToFirstChild();
public abstract bool MoveToParent();
public virtual void MoveToRoot() {
while (MoveToParent())
;
}
public abstract bool MoveTo(XPathNavigator other);
public abstract bool MoveToId(string id);
public virtual bool MoveToChild(string localName, string namespaceURI) {
if (MoveToFirstChild()) {
do {
if (NodeType == XPathNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
return true;
}
while (MoveToNext());
MoveToParent();
}
return false;
}
public virtual bool MoveToChild(XPathNodeType type) {
if (MoveToFirstChild()) {
int mask = GetContentKindMask(type);
do {
if (((1 << (int) NodeType) & mask) != 0)
return true;
}
while (MoveToNext());
MoveToParent();
}
return false;
}
public virtual bool MoveToFollowing(string localName, string namespaceURI) {
return MoveToFollowing(localName, namespaceURI, null);
}
public virtual bool MoveToFollowing(string localName, string namespaceURI, XPathNavigator end) {
XPathNavigator navSave = Clone();
if (end != null) {
switch (end.NodeType) {
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
// Scan until we come to the next content-typed node
// after the attribute or namespace node
end = end.Clone();
end.MoveToNonDescendant();
break;
}
}
switch (NodeType) {
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
if (!MoveToParent()) {
// Restore previous position and return false
// MoveTo(navSave);
return false;
}
break;
}
do {
if (!MoveToFirstChild()) {
// Look for next sibling
while (true) {
if (MoveToNext())
break;
if (!MoveToParent()) {
// Restore previous position and return false
MoveTo(navSave);
return false;
}
}
}
// Have we reached the end of the scan?
if (end != null && IsSamePosition(end)) {
// Restore previous position and return false
MoveTo(navSave);
return false;
}
}
while (NodeType != XPathNodeType.Element
|| localName != LocalName
|| namespaceURI != NamespaceURI);
return true;
}
public virtual bool MoveToFollowing(XPathNodeType type) {
return MoveToFollowing(type, null);
}
public virtual bool MoveToFollowing(XPathNodeType type, XPathNavigator end) {
XPathNavigator navSave = Clone();
int mask = GetContentKindMask(type);
if (end != null) {
switch (end.NodeType) {
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
// Scan until we come to the next content-typed node
// after the attribute or namespace node
end = end.Clone();
end.MoveToNonDescendant();
break;
}
}
switch (NodeType) {
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
if (!MoveToParent()) {
// Restore previous position and return false
// MoveTo(navSave);
return false;
}
break;
}
do {
if (!MoveToFirstChild()) {
// Look for next sibling
while (true) {
if (MoveToNext())
break;
if (!MoveToParent()) {
// Restore previous position and return false
MoveTo(navSave);
return false;
}
}
}
// Have we reached the end of the scan?
if (end != null && IsSamePosition(end)) {
// Restore previous position and return false
MoveTo(navSave);
return false;
}
}
while (((1 << (int) NodeType) & mask) == 0);
return true;
}
public virtual bool MoveToNext(string localName, string namespaceURI) {
XPathNavigator navClone = Clone();
while (MoveToNext()) {
if (NodeType == XPathNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
return true;
}
MoveTo(navClone);
return false;
}
public virtual bool MoveToNext(XPathNodeType type) {
XPathNavigator navClone = Clone();
int mask = GetContentKindMask(type);
while (MoveToNext()) {
if (((1 << (int) NodeType) & mask) != 0)
return true;
}
MoveTo(navClone);
return false;
}
public virtual bool HasChildren {
get {
if (MoveToFirstChild()) {
MoveToParent();
return true;
}
return false;
}
}
public abstract bool IsSamePosition(XPathNavigator other);
public virtual bool IsDescendant(XPathNavigator nav) {
if (nav != null){
nav = nav.Clone();
while ( nav.MoveToParent() )
if (nav.IsSamePosition(this))
return true;
}
return false;
}
public virtual XmlNodeOrder ComparePosition( XPathNavigator nav ) {
if (nav == null) {
return XmlNodeOrder.Unknown;
}
if( IsSamePosition( nav ) )
return XmlNodeOrder.Same;
XPathNavigator n1 = this.Clone();
XPathNavigator n2 = nav.Clone();
int depth1 = GetDepth( n1.Clone() );
int depth2 = GetDepth( n2.Clone() );
if( depth1 > depth2 ) {
while( depth1 > depth2 ) {
n1.MoveToParent();
depth1--;
}
if( n1.IsSamePosition(n2) )
return XmlNodeOrder.After;
}
if( depth2 > depth1 ) {
while( depth2 > depth1 ) {
n2.MoveToParent();
depth2 --;
}
if( n1.IsSamePosition(n2) )
return XmlNodeOrder.Before;
}
XPathNavigator parent1 = n1.Clone();
XPathNavigator parent2 = n2.Clone();
while( true ) {
if( !parent1.MoveToParent() || !parent2.MoveToParent() )
return XmlNodeOrder.Unknown;
if( parent1.IsSamePosition( parent2 ) ) {
if (n1.GetType().ToString() != "Microsoft.VisualStudio.Modeling.StoreNavigator") {
Debug.Assert( CompareSiblings(n1.Clone(), n2.Clone()) != CompareSiblings(n2.Clone(), n1.Clone()), "IsSamePosition() on custom navigator returns incosistent results" );
}
return CompareSiblings(n1, n2);
}
n1.MoveToParent();
n2.MoveToParent();
}
}
public virtual IXmlSchemaInfo SchemaInfo {
get { return this as IXmlSchemaInfo; }
}
public virtual bool CheckValidity(XmlSchemaSet schemas, ValidationEventHandler validationEventHandler) {
IXmlSchemaInfo schemaInfo;
XmlSchemaType schemaType = null;
XmlSchemaElement schemaElement = null;
XmlSchemaAttribute schemaAttribute = null;
switch (NodeType) {
case XPathNodeType.Root:
if (schemas == null) {
throw new InvalidOperationException(Res.GetString(Res.XPathDocument_MissingSchemas));
}
schemaType = null;
break;
case XPathNodeType.Element:
if (schemas == null) {
throw new InvalidOperationException(Res.GetString(Res.XPathDocument_MissingSchemas));
}
schemaInfo = SchemaInfo;
if (schemaInfo != null) {
schemaType = schemaInfo.SchemaType;
schemaElement = schemaInfo.SchemaElement;
}
if (schemaType == null
&& schemaElement == null) {
throw new InvalidOperationException(Res.GetString(Res.XPathDocument_NotEnoughSchemaInfo, null));
}
break;
case XPathNodeType.Attribute:
if (schemas == null) {
throw new InvalidOperationException(Res.GetString(Res.XPathDocument_MissingSchemas));
}
schemaInfo = SchemaInfo;
if (schemaInfo != null) {
schemaType = schemaInfo.SchemaType;
schemaAttribute = schemaInfo.SchemaAttribute;
}
if (schemaType == null
&& schemaAttribute == null) {
throw new InvalidOperationException(Res.GetString(Res.XPathDocument_NotEnoughSchemaInfo, null));
}
break;
default:
throw new InvalidOperationException(Res.GetString(Res.XPathDocument_ValidateInvalidNodeType, null));
}
Debug.Assert( schemaType != null || this.NodeType == XPathNodeType.Root, "schemaType != null || this.NodeType == XPathNodeType.Root" );
XmlReader reader = CreateReader();
CheckValidityHelper validityTracker = new CheckValidityHelper( validationEventHandler, reader as XPathNavigatorReader );
validationEventHandler = new ValidationEventHandler( validityTracker.ValidationCallback );
XmlReader validatingReader = GetValidatingReader( reader, schemas, validationEventHandler, schemaType, schemaElement, schemaAttribute );
while( validatingReader.Read() )
;
return validityTracker.IsValid;
}
private XmlReader GetValidatingReader( XmlReader reader, XmlSchemaSet schemas, ValidationEventHandler validationEvent, XmlSchemaType schemaType, XmlSchemaElement schemaElement, XmlSchemaAttribute schemaAttribute ) {
if (schemaAttribute != null) {
return schemaAttribute.Validate(reader, null, schemas, validationEvent);
}
else if (schemaElement != null) {
return schemaElement.Validate(reader, null, schemas, validationEvent);
}
else if (schemaType != null) {
return schemaType.Validate(reader, null, schemas, validationEvent);
}
Debug.Assert( schemas != null, "schemas != null" );
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ConformanceLevel = ConformanceLevel.Auto;
readerSettings.ValidationType = ValidationType.Schema;
readerSettings.Schemas = schemas;
readerSettings.ValidationEventHandler += validationEvent;
return XmlReader.Create( reader, readerSettings );
}
class CheckValidityHelper {
bool isValid;
ValidationEventHandler nextEventHandler;
XPathNavigatorReader reader;
internal CheckValidityHelper( ValidationEventHandler nextEventHandler, XPathNavigatorReader reader ) {
this.isValid = true;
this.nextEventHandler = nextEventHandler;
this.reader = reader;
}
internal void ValidationCallback( object sender, ValidationEventArgs args ) {
Debug.Assert( args != null );
if ( args.Severity == XmlSeverityType.Error )
this.isValid = false;
XmlSchemaValidationException exception = args.Exception as XmlSchemaValidationException;
if (exception != null && reader != null)
exception.SetSourceObject(reader.UnderlyingObject);
if (this.nextEventHandler != null) {
this.nextEventHandler( sender, args );
}
else if (exception != null && args.Severity == XmlSeverityType.Error) {
throw exception;
}
}
internal bool IsValid {
get { return this.isValid; }
}
}
public virtual XPathExpression Compile(string xpath) {
return XPathExpression.Compile(xpath);
}
public virtual XPathNavigator SelectSingleNode(string xpath) {
return SelectSingleNode(XPathExpression.Compile(xpath));
}
public virtual XPathNavigator SelectSingleNode(string xpath, IXmlNamespaceResolver resolver) {
return SelectSingleNode(XPathExpression.Compile(xpath, resolver));
}
public virtual XPathNavigator SelectSingleNode(XPathExpression expression) {
//
XPathNodeIterator iter = this.Select(expression);
if (iter.MoveNext()) {
return iter.Current;
}
return null;
}
public virtual XPathNodeIterator Select(string xpath) {
Contract.Ensures(Contract.Result<XPathNodeIterator>() != null);
return this.Select(XPathExpression.Compile(xpath));
}
public virtual XPathNodeIterator Select(string xpath, IXmlNamespaceResolver resolver) {
Contract.Ensures(Contract.Result<XPathNodeIterator>() != null);
return this.Select(XPathExpression.Compile(xpath, resolver));
}
public virtual XPathNodeIterator Select(XPathExpression expr) {
Contract.Ensures(Contract.Result<XPathNodeIterator>() != null);
XPathNodeIterator result = Evaluate(expr) as XPathNodeIterator;
if (result == null) {
throw XPathException.Create(Res.Xp_NodeSetExpected);
}
return result;
}
public virtual object Evaluate(string xpath) {
return Evaluate(XPathExpression.Compile(xpath), null);
}
public virtual object Evaluate(string xpath, IXmlNamespaceResolver resolver) {
return this.Evaluate(XPathExpression.Compile(xpath, resolver));
}
public virtual object Evaluate(XPathExpression expr) {
return Evaluate(expr, null);
}
public virtual object Evaluate(XPathExpression expr, XPathNodeIterator context) {
CompiledXpathExpr cexpr = expr as CompiledXpathExpr;
if (cexpr == null) {
throw XPathException.Create(Res.Xp_BadQueryObject);
}
Query query = Query.Clone(cexpr.QueryTree);
query.Reset();
if (context == null) {
context = new XPathSingletonIterator(this.Clone(), /*moved:*/true);
}
object result = query.Evaluate(context);
if (result is XPathNodeIterator) {
return new XPathSelectionIterator(context.Current, query);
}
return result;
}
public virtual bool Matches( XPathExpression expr ) {
CompiledXpathExpr cexpr = expr as CompiledXpathExpr;
if( cexpr == null )
throw XPathException.Create(Res.Xp_BadQueryObject);
// We should clone query because some Query.MatchNode() alter expression state and this may brake
// SelectionIterators that are runing using this Query
// Excample of MatchNode() that alret the state is FilterQuery.MatchNode()
Query query = Query.Clone(cexpr.QueryTree);
try {
return query.MatchNode(this) != null;
}
catch(XPathException) {
throw XPathException.Create(Res.Xp_InvalidPattern, cexpr.Expression);
}
}
public virtual bool Matches(string xpath) {
return Matches(CompileMatchPattern(xpath));
}
public virtual XPathNodeIterator SelectChildren( XPathNodeType type ) {
return new XPathChildIterator( this.Clone(), type );
}
public virtual XPathNodeIterator SelectChildren( string name, string namespaceURI ) {
return new XPathChildIterator( this.Clone(), name, namespaceURI );
}
public virtual XPathNodeIterator SelectAncestors( XPathNodeType type, bool matchSelf ) {
return new XPathAncestorIterator( this.Clone(), type, matchSelf );
}
public virtual XPathNodeIterator SelectAncestors( string name, string namespaceURI, bool matchSelf ) {
return new XPathAncestorIterator( this.Clone(), name, namespaceURI, matchSelf );
}
public virtual XPathNodeIterator SelectDescendants( XPathNodeType type, bool matchSelf ) {
return new XPathDescendantIterator( this.Clone(), type, matchSelf );
}
public virtual XPathNodeIterator SelectDescendants( string name, string namespaceURI, bool matchSelf ) {
return new XPathDescendantIterator( this.Clone(), name, namespaceURI, matchSelf );
}
public virtual bool CanEdit {
get {
return false;
}
}
public virtual XmlWriter PrependChild() {
throw new NotSupportedException();
}
public virtual XmlWriter AppendChild() {
throw new NotSupportedException();
}
public virtual XmlWriter InsertAfter() {
throw new NotSupportedException();
}
public virtual XmlWriter InsertBefore() {
throw new NotSupportedException();
}
public virtual XmlWriter CreateAttributes() {
throw new NotSupportedException();
}
public virtual XmlWriter ReplaceRange(XPathNavigator lastSiblingToReplace) {
throw new NotSupportedException();
}
public virtual void ReplaceSelf(string newNode) {
XmlReader reader = CreateContextReader(newNode, false);
ReplaceSelf(reader);
}
public virtual void ReplaceSelf(XmlReader newNode) {
if (newNode == null) {
throw new ArgumentNullException("newNode");
}
XPathNodeType type = NodeType;
if (type == XPathNodeType.Root
|| type == XPathNodeType.Attribute
|| type == XPathNodeType.Namespace) {
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
XmlWriter writer = ReplaceRange(this);
BuildSubtree(newNode, writer);
writer.Close();
}
public virtual void ReplaceSelf(XPathNavigator newNode) {
if (newNode == null) {
throw new ArgumentNullException("newNode");
}
XmlReader reader = newNode.CreateReader();
ReplaceSelf(reader);
}
// Returns the markup representing the current node and all of its children.
public virtual string OuterXml {
get {
StringWriter stringWriter;
XmlWriterSettings writerSettings;
XmlWriter xmlWriter;
// Attributes and namespaces are not allowed at the top-level by the well-formed writer
if (NodeType == XPathNodeType.Attribute) {
return string.Concat(Name, "=\"", Value, "\"");
}
else if (NodeType == XPathNodeType.Namespace) {
if (LocalName.Length == 0)
return string.Concat("xmlns=\"", Value, "\"");
else
return string.Concat("xmlns:", LocalName, "=\"", Value, "\"");
}
stringWriter = new StringWriter(CultureInfo.InvariantCulture);
writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
writerSettings.OmitXmlDeclaration = true;
writerSettings.ConformanceLevel = ConformanceLevel.Auto;
xmlWriter = XmlWriter.Create(stringWriter, writerSettings);
try {
xmlWriter.WriteNode(this, true);
}
finally {
xmlWriter.Close();
}
return stringWriter.ToString();
}
set {
ReplaceSelf(value);
}
}
// Returns the markup representing just the children of the current node.
public virtual string InnerXml {
get {
switch (NodeType) {
case XPathNodeType.Root:
case XPathNodeType.Element:
StringWriter stringWriter;
XmlWriterSettings writerSettings;
XmlWriter xmlWriter;
stringWriter = new StringWriter(CultureInfo.InvariantCulture);
writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
writerSettings.OmitXmlDeclaration = true;
writerSettings.ConformanceLevel = ConformanceLevel.Auto;
xmlWriter = XmlWriter.Create(stringWriter, writerSettings);
try {
if (MoveToFirstChild()) {
do {
xmlWriter.WriteNode(this, true);
}
while (MoveToNext());
// Restore position
MoveToParent();
}
}
finally {
xmlWriter.Close();
}
return stringWriter.ToString();
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
return Value;
default:
return string.Empty;
}
}
set {
if (value == null) {
throw new ArgumentNullException("value");
}
switch (NodeType) {
case XPathNodeType.Root:
case XPathNodeType.Element:
XPathNavigator edit = CreateNavigator();
while (edit.MoveToFirstChild()) {
edit.DeleteSelf();
}
if (value.Length != 0) {
edit.AppendChild(value);
}
break;
case XPathNodeType.Attribute:
SetValue(value);
break;
default:
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
}
}
public virtual void AppendChild(string newChild) {
XmlReader reader = CreateContextReader(newChild, true);
AppendChild(reader);
}
public virtual void AppendChild(XmlReader newChild) {
if (newChild == null) {
throw new ArgumentNullException("newChild");
}
XmlWriter writer = AppendChild();
BuildSubtree(newChild, writer);
writer.Close();
}
public virtual void AppendChild(XPathNavigator newChild) {
if (newChild == null) {
throw new ArgumentNullException("newChild");
}
if (!IsValidChildType(newChild.NodeType)) {
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
XmlReader reader = newChild.CreateReader();
AppendChild(reader);
}
public virtual void PrependChild(string newChild) {
XmlReader reader = CreateContextReader(newChild, true);
PrependChild(reader);
}
public virtual void PrependChild(XmlReader newChild) {
if (newChild == null) {
throw new ArgumentNullException("newChild");
}
XmlWriter writer = PrependChild();
BuildSubtree(newChild, writer);
writer.Close();
}
public virtual void PrependChild(XPathNavigator newChild) {
if (newChild == null) {
throw new ArgumentNullException("newChild");
}
if (!IsValidChildType(newChild.NodeType)) {
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
XmlReader reader = newChild.CreateReader();
PrependChild(reader);
}
public virtual void InsertBefore(string newSibling) {
XmlReader reader = CreateContextReader(newSibling, false);
InsertBefore(reader);
}
public virtual void InsertBefore(XmlReader newSibling) {
if (newSibling == null) {
throw new ArgumentNullException("newSibling");
}
XmlWriter writer = InsertBefore();
BuildSubtree(newSibling, writer);
writer.Close();
}
public virtual void InsertBefore(XPathNavigator newSibling) {
if (newSibling == null) {
throw new ArgumentNullException("newSibling");
}
if (!IsValidSiblingType(newSibling.NodeType)) {
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
XmlReader reader = newSibling.CreateReader();
InsertBefore(reader);
}
public virtual void InsertAfter(string newSibling) {
XmlReader reader = CreateContextReader(newSibling, false);
InsertAfter(reader);
}
public virtual void InsertAfter(XmlReader newSibling) {
if (newSibling == null) {
throw new ArgumentNullException("newSibling");
}
XmlWriter writer = InsertAfter();
BuildSubtree(newSibling, writer);
writer.Close();
}
public virtual void InsertAfter(XPathNavigator newSibling) {
if (newSibling == null) {
throw new ArgumentNullException("newSibling");
}
if (!IsValidSiblingType(newSibling.NodeType)) {
throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
}
XmlReader reader = newSibling.CreateReader();
InsertAfter(reader);
}
public virtual void DeleteRange(XPathNavigator lastSiblingToDelete) {
throw new NotSupportedException();
}
public virtual void DeleteSelf() {
DeleteRange(this);
}
public virtual void PrependChildElement(string prefix, string localName, string namespaceURI, string value) {
XmlWriter writer = PrependChild();
writer.WriteStartElement(prefix, localName, namespaceURI);
if (value != null) {
writer.WriteString(value);
}
writer.WriteEndElement();
writer.Close();
}
public virtual void AppendChildElement(string prefix, string localName, string namespaceURI, string value) {
XmlWriter writer = AppendChild();
writer.WriteStartElement(prefix, localName, namespaceURI);
if (value != null) {
writer.WriteString(value);
}
writer.WriteEndElement();
writer.Close();
}
public virtual void InsertElementBefore(string prefix, string localName, string namespaceURI, string value) {
XmlWriter writer = InsertBefore();
writer.WriteStartElement(prefix, localName, namespaceURI);
if (value != null) {
writer.WriteString(value);
}
writer.WriteEndElement();
writer.Close();
}
public virtual void InsertElementAfter(string prefix, string localName, string namespaceURI, string value) {
XmlWriter writer = InsertAfter();
writer.WriteStartElement(prefix, localName, namespaceURI);
if (value != null) {
writer.WriteString(value);
}
writer.WriteEndElement();
writer.Close();
}
public virtual void CreateAttribute(string prefix, string localName, string namespaceURI, string value) {
XmlWriter writer = CreateAttributes();
writer.WriteStartAttribute(prefix, localName, namespaceURI);
if (value != null) {
writer.WriteString(value);
}
writer.WriteEndAttribute();
writer.Close();
}
//-----------------------------------------------
// Internal
//-----------------------------------------------
internal bool MoveToPrevious(string localName, string namespaceURI) {
XPathNavigator navClone = Clone();
localName = (localName != null) ? NameTable.Get(localName) : null;
while (MoveToPrevious()) {
if (NodeType == XPathNodeType.Element && (object) localName == (object) LocalName && namespaceURI == NamespaceURI)
return true;
}
MoveTo(navClone);
return false;
}
internal bool MoveToPrevious(XPathNodeType type) {
XPathNavigator navClone = Clone();
int mask = GetContentKindMask(type);
while (MoveToPrevious()) {
if (((1 << (int) NodeType) & mask) != 0)
return true;
}
MoveTo(navClone);
return false;
}
internal bool MoveToNonDescendant() {
// If current node is document, there is no next non-descendant
if (NodeType == XPathNodeType.Root)
return false;
// If sibling exists, it is the next non-descendant
if (MoveToNext())
return true;
// The current node is either an attribute, namespace, or last child node
XPathNavigator navSave = Clone();
if (!MoveToParent())
return false;
switch (navSave.NodeType) {
case XPathNodeType.Attribute:
case XPathNodeType.Namespace:
// Next node in document order is first content-child of parent
if (MoveToFirstChild())
return true;
break;
}
while (!MoveToNext()) {
if (!MoveToParent()) {
// Restore original position and return false
MoveTo(navSave);
return false;
}
}
return true;
}
/// <summary>
/// Returns ordinal number of attribute, namespace or child node within its parent.
/// Order is reversed for attributes and child nodes to avoid O(N**2) running time.
/// This property is useful for debugging, and also used in UniqueId implementation.
/// </summary>
internal uint IndexInParent {
get {
XPathNavigator nav = this.Clone();
uint idx = 0;
switch (NodeType) {
case XPathNodeType.Attribute:
while (nav.MoveToNextAttribute()) {
idx ++;
}
break;
case XPathNodeType.Namespace:
while (nav.MoveToNextNamespace()) {
idx ++;
}
break;
default:
while (nav.MoveToNext()) {
idx ++;
}
break;
}
return idx;
}
}
internal static readonly char[] NodeTypeLetter = new char[] {
'R', // Root
'E', // Element
'A', // Attribute
'N', // Namespace
'T', // Text
'S', // SignificantWhitespace
'W', // Whitespace
'P', // ProcessingInstruction
'C', // Comment
'X', // All
};
internal static readonly char[] UniqueIdTbl = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4',
'5', '6'
};
// Requirements for id:
// 1. must consist of alphanumeric characters only
// 2. must begin with an alphabetic character
// 3. same id is generated for the same node
// 4. ids are unique
//
// id = node type letter + reverse path to root in terms of encoded IndexInParent integers from node to root seperated by 0's if needed
internal virtual string UniqueId {
get {
XPathNavigator nav = this.Clone();
StringBuilder sb = new StringBuilder();
// Ensure distinguishing attributes, namespaces and child nodes
sb.Append(NodeTypeLetter[(int)NodeType]);
while (true) {
uint idx = nav.IndexInParent;
if (!nav.MoveToParent()) {
break;
}
if (idx <= 0x1f) {
sb.Append(UniqueIdTbl[idx]);
} else {
sb.Append('0');
do {
sb.Append(UniqueIdTbl[idx & 0x1f]);
idx >>= 5;
} while (idx != 0);
sb.Append('0');
}
}
return sb.ToString();
}
}
private static XPathExpression CompileMatchPattern(string xpath) {
bool hasPrefix;
Query query = new QueryBuilder().BuildPatternQuery(xpath, out hasPrefix);
return new CompiledXpathExpr(query, xpath, hasPrefix);
}
private static int GetDepth(XPathNavigator nav) {
int depth = 0;
while (nav.MoveToParent()) {
depth++;
}
return depth;
}
// XPath based comparison for namespaces, attributes and other
// items with the same parent element.
//
// n2
// namespace(0) attribute(-1) other(-2)
// n1
// namespace(0) ?(0) before(-1) before(-2)
// attribute(1) after(1) ?(0) before(-1)
// other (2) after(2) after(1) ?(0)
private XmlNodeOrder CompareSiblings(XPathNavigator n1, XPathNavigator n2) {
int cmp = 0;
#if DEBUG
Debug.Assert(!n1.IsSamePosition(n2));
XPathNavigator p1 = n1.Clone(), p2 = n2.Clone();
Debug.Assert(p1.MoveToParent() && p2.MoveToParent() && p1.IsSamePosition(p2));
#endif
switch (n1.NodeType) {
case XPathNodeType.Namespace:
break;
case XPathNodeType.Attribute:
cmp += 1;
break;
default:
cmp += 2;
break;
}
switch (n2.NodeType) {
case XPathNodeType.Namespace:
if (cmp == 0) {
while (n1.MoveToNextNamespace()) {
if (n1.IsSamePosition(n2)) {
return XmlNodeOrder.Before;
}
}
}
break;
case XPathNodeType.Attribute:
cmp -= 1;
if (cmp == 0) {
while (n1.MoveToNextAttribute()) {
if (n1.IsSamePosition(n2)) {
return XmlNodeOrder.Before;
}
}
}
break;
default:
cmp -= 2;
if (cmp == 0) {
while (n1.MoveToNext()) {
if (n1.IsSamePosition(n2)) {
return XmlNodeOrder.Before;
}
}
}
break;
}
return cmp < 0 ? XmlNodeOrder.Before : XmlNodeOrder.After;
}
internal static XmlNamespaceManager GetNamespaces( IXmlNamespaceResolver resolver ) {
XmlNamespaceManager mngr = new XmlNamespaceManager(new NameTable());
IDictionary<string,string> dictionary = resolver.GetNamespacesInScope( XmlNamespaceScope.All );
foreach ( KeyValuePair<string,string> pair in dictionary ) {
//"xmlns " is always in the namespace manager so adding it would throw an exception
if( pair.Key != "xmlns" )
mngr.AddNamespace( pair.Key, pair.Value );
}
return mngr;
}
// Get mask that will allow XPathNodeType content matching to be performed using only a shift and an and operation
internal const int AllMask = 0x7FFFFFFF;
internal const int NoAttrNmspMask = AllMask & ~(1 << (int) XPathNodeType.Attribute) & ~(1 << (int) XPathNodeType.Namespace);
internal const int TextMask = (1 << (int) XPathNodeType.Text) | (1 << (int) XPathNodeType.SignificantWhitespace) | (1 << (int) XPathNodeType.Whitespace);
internal static readonly int[] ContentKindMasks = {
(1 << (int) XPathNodeType.Root), // Root
(1 << (int) XPathNodeType.Element), // Element
0, // Attribute (not content)
0, // Namespace (not content)
TextMask, // Text
(1 << (int) XPathNodeType.SignificantWhitespace), // SignificantWhitespace
(1 << (int) XPathNodeType.Whitespace), // Whitespace
(1 << (int) XPathNodeType.ProcessingInstruction), // ProcessingInstruction
(1 << (int) XPathNodeType.Comment), // Comment
NoAttrNmspMask, // All
};
internal static int GetContentKindMask(XPathNodeType type) {
return ContentKindMasks[(int) type];
}
internal static int GetKindMask(XPathNodeType type) {
if (type == XPathNodeType.All)
return AllMask;
else if (type == XPathNodeType.Text)
return TextMask;
return (1 << (int) type);
}
internal static bool IsText(XPathNodeType type) {
//return ((1 << (int) type) & TextMask) != 0;
return (uint)(type - XPathNodeType.Text) <= (XPathNodeType.Whitespace - XPathNodeType.Text);
}
// Lax check for potential child item.
private bool IsValidChildType(XPathNodeType type) {
switch (NodeType) {
case XPathNodeType.Root:
switch (type) {
case XPathNodeType.Element:
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.Whitespace:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
return true;
}
break;
case XPathNodeType.Element:
switch (type) {
case XPathNodeType.Element:
case XPathNodeType.Text:
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.Whitespace:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
return true;
}
break;
}
return false;
}
// Lax check for potential sibling item.
private bool IsValidSiblingType(XPathNodeType type) {
switch (NodeType) {
case XPathNodeType.Element:
case XPathNodeType.Text:
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.Whitespace:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
switch (type) {
case XPathNodeType.Element:
case XPathNodeType.Text:
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.Whitespace:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
return true;
}
break;
}
return false;
}
private XmlReader CreateReader() {
return XPathNavigatorReader.Create(this);
}
private XmlReader CreateContextReader(string xml, bool fromCurrentNode) {
if (xml == null) {
throw new ArgumentNullException("xml");
}
// We have to set the namespace context for the reader.
XPathNavigator editor = CreateNavigator();
// scope starts from parent.
XmlNamespaceManager mgr = new XmlNamespaceManager( NameTable );
if (!fromCurrentNode) {
editor.MoveToParent(); // should always succeed.
}
if (editor.MoveToFirstNamespace(XPathNamespaceScope.All)) {
do {
mgr.AddNamespace(editor.LocalName, editor.Value);
}
while (editor.MoveToNextNamespace(XPathNamespaceScope.All));
}
//
XmlParserContext context = new XmlParserContext(NameTable, mgr, null, XmlSpace.Default);
XmlTextReader reader = new XmlTextReader(xml, XmlNodeType.Element, context);
//
reader.WhitespaceHandling = WhitespaceHandling.Significant;
return reader;
}
internal void BuildSubtree(XmlReader reader, XmlWriter writer) {
// important (perf) string literal...
string xmlnsUri = XmlReservedNs.NsXmlNs; // http://www.w3.org/2000/xmlns/
ReadState readState = reader.ReadState;
if (readState != ReadState.Initial
&& readState != ReadState.Interactive) {
throw new ArgumentException(Res.GetString(Res.Xml_InvalidOperation), "reader");
}
int level = 0;
if ( readState == ReadState.Initial ) {
if( !reader.Read() )
return;
level++; // if start in initial, read everything (not just first)
}
do {
switch (reader.NodeType) {
case XmlNodeType.Element:
writer.WriteStartElement( reader.Prefix, reader.LocalName, reader.NamespaceURI );
bool isEmptyElement = reader.IsEmptyElement;
while (reader.MoveToNextAttribute()) {
if ((object) reader.NamespaceURI == (object) xmlnsUri) {
if (reader.Prefix.Length == 0) {
// Default namespace declaration "xmlns"
Debug.Assert(reader.LocalName == "xmlns");
writer.WriteAttributeString( "", "xmlns", xmlnsUri, reader.Value );
}
else {
Debug.Assert(reader.Prefix == "xmlns");
writer.WriteAttributeString( "xmlns", reader.LocalName, xmlnsUri, reader.Value );
}
}
else {
writer.WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteString(reader.Value);
writer.WriteEndAttribute();
}
}
reader.MoveToElement();
if (isEmptyElement) {
// there might still be a value, if there is a default value specified in the schema
writer.WriteEndElement();
}
else {
level++;
}
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
//should not read beyond the level of the reader's original position.
level--;
break;
case XmlNodeType.Text:
case XmlNodeType.CDATA:
writer.WriteString( reader.Value );
break;
case XmlNodeType.SignificantWhitespace:
case XmlNodeType.Whitespace:
//
writer.WriteString( reader.Value );
break;
case XmlNodeType.Comment:
writer.WriteComment( reader.Value );
break;
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction( reader.LocalName , reader.Value);
break;
case XmlNodeType.EntityReference:
reader.ResolveEntity(); //
break;
case XmlNodeType.EndEntity:
case XmlNodeType.None:
case XmlNodeType.DocumentType:
case XmlNodeType.XmlDeclaration:
break;
case XmlNodeType.Attribute:
if ((object) reader.NamespaceURI == (object) xmlnsUri) {
if (reader.Prefix.Length == 0) {
// Default namespace declaration "xmlns"
Debug.Assert(reader.LocalName == "xmlns");
writer.WriteAttributeString( "", "xmlns", xmlnsUri, reader.Value );
}
else {
Debug.Assert(reader.Prefix == "xmlns");
writer.WriteAttributeString( "xmlns", reader.LocalName, xmlnsUri, reader.Value );
}
}
else {
writer.WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteString(reader.Value);
writer.WriteEndAttribute();
}
break;
}
}
while( reader.Read() && ( level > 0 ) );
}
private object debuggerDisplayProxy { get { return new DebuggerDisplayProxy(this); } }
[DebuggerDisplay("{ToString()}")]
internal struct DebuggerDisplayProxy {
XPathNavigator nav;
public DebuggerDisplayProxy(XPathNavigator nav) {
this.nav = nav;
}
public override string ToString() {
string result = nav.NodeType.ToString();
switch (nav.NodeType) {
case XPathNodeType.Element :
result += ", Name=\"" + nav.Name + '"';
break;
case XPathNodeType.Attribute:
case XPathNodeType.Namespace :
case XPathNodeType.ProcessingInstruction:
result += ", Name=\"" + nav.Name + '"';
result += ", Value=\"" + XmlConvert.EscapeValueForDebuggerDisplay(nav.Value) + '"';
break;
case XPathNodeType.Text :
case XPathNodeType.Whitespace :
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.Comment :
result += ", Value=\"" + XmlConvert.EscapeValueForDebuggerDisplay(nav.Value) + '"';
break;
}
return result;
}
}
}
#if CONTRACTS_FULL
[ContractClassFor(typeof(XPathNavigator))]
internal abstract class XPathNavigatorContract : XPathNavigator
{
public override XPathNavigator Clone()
{
Contract.Ensures(Contract.Result<XPathNavigator>() != null);
return default(XPathNavigator);
}
public override XmlNameTable NameTable {
get {
Contract.Ensures(Contract.Result<XmlNameTable>() != null);
return default(XmlNameTable);
}
}
}
#endif
}
|