e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1642 lines
64 KiB
C#
1642 lines
64 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="XmlNodeReader.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <owner current="true" primary="true">[....]</owner>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Xml
|
|
{
|
|
using System;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Xml.Schema;
|
|
using System.Globalization;
|
|
|
|
internal class XmlNodeReaderNavigator {
|
|
XmlNode curNode;
|
|
XmlNode elemNode;
|
|
XmlNode logNode;
|
|
int attrIndex;
|
|
int logAttrIndex;
|
|
|
|
//presave these 2 variables since they shouldn't change.
|
|
XmlNameTable nameTable;
|
|
XmlDocument doc;
|
|
|
|
int nAttrInd; //used to identify virtual attributes of DocumentType node and XmlDeclaration node
|
|
|
|
const String strPublicID = "PUBLIC";
|
|
const String strSystemID = "SYSTEM";
|
|
const String strVersion = "version";
|
|
const String strStandalone = "standalone";
|
|
const String strEncoding = "encoding";
|
|
|
|
|
|
//caching variables for perf reasons
|
|
int nDeclarationAttrCount;
|
|
int nDocTypeAttrCount;
|
|
|
|
//variables for roll back the moves
|
|
int nLogLevel;
|
|
int nLogAttrInd;
|
|
bool bLogOnAttrVal;
|
|
bool bCreatedOnAttribute;
|
|
|
|
internal struct VirtualAttribute {
|
|
internal String name;
|
|
internal String value;
|
|
|
|
internal VirtualAttribute(String name, String value) {
|
|
this.name = name;
|
|
this.value = value;
|
|
}
|
|
};
|
|
|
|
internal VirtualAttribute [] decNodeAttributes = {
|
|
new VirtualAttribute( null, null ),
|
|
new VirtualAttribute( null, null ),
|
|
new VirtualAttribute( null, null )
|
|
};
|
|
|
|
internal VirtualAttribute [] docTypeNodeAttributes = {
|
|
new VirtualAttribute( null, null ),
|
|
new VirtualAttribute( null, null )
|
|
};
|
|
|
|
bool bOnAttrVal;
|
|
|
|
public XmlNodeReaderNavigator( XmlNode node ) {
|
|
curNode = node;
|
|
logNode = node;
|
|
XmlNodeType nt = curNode.NodeType;
|
|
if ( nt == XmlNodeType.Attribute ) {
|
|
elemNode = null;
|
|
attrIndex = -1;
|
|
bCreatedOnAttribute = true;
|
|
}
|
|
else {
|
|
elemNode = node;
|
|
attrIndex = -1;
|
|
bCreatedOnAttribute = false;
|
|
}
|
|
//presave this for pref reason since it shouldn't change.
|
|
if ( nt == XmlNodeType.Document )
|
|
this.doc = (XmlDocument)curNode;
|
|
else
|
|
this.doc = node.OwnerDocument;
|
|
this.nameTable = doc.NameTable;
|
|
this.nAttrInd = -1;
|
|
//initialize the caching variables
|
|
this.nDeclarationAttrCount = -1;
|
|
this.nDocTypeAttrCount = -1;
|
|
this.bOnAttrVal = false;
|
|
this.bLogOnAttrVal = false;
|
|
}
|
|
|
|
public XmlNodeType NodeType {
|
|
get {
|
|
XmlNodeType nt = curNode.NodeType;
|
|
if ( nAttrInd != -1 ) {
|
|
Debug.Assert( nt == XmlNodeType.XmlDeclaration || nt == XmlNodeType.DocumentType );
|
|
if ( this.bOnAttrVal )
|
|
return XmlNodeType.Text;
|
|
else
|
|
return XmlNodeType.Attribute;
|
|
}
|
|
return nt;
|
|
}
|
|
}
|
|
|
|
public String NamespaceURI {
|
|
get { return curNode.NamespaceURI; }
|
|
}
|
|
|
|
public String Name {
|
|
get {
|
|
if ( nAttrInd != -1 ) {
|
|
Debug.Assert( curNode.NodeType == XmlNodeType.XmlDeclaration || curNode.NodeType == XmlNodeType.DocumentType );
|
|
if ( this.bOnAttrVal )
|
|
return String.Empty; //Text node's name is String.Empty
|
|
else {
|
|
Debug.Assert( nAttrInd >= 0 && nAttrInd < AttributeCount );
|
|
if ( curNode.NodeType == XmlNodeType.XmlDeclaration )
|
|
return decNodeAttributes[nAttrInd].name;
|
|
else
|
|
return docTypeNodeAttributes[nAttrInd].name;
|
|
}
|
|
}
|
|
if ( IsLocalNameEmpty ( curNode.NodeType ) )
|
|
return String.Empty;
|
|
return curNode.Name;
|
|
}
|
|
}
|
|
|
|
public String LocalName {
|
|
get {
|
|
if ( nAttrInd != -1 )
|
|
//for the nodes in this case, their LocalName should be the same as their name
|
|
return Name;
|
|
if ( IsLocalNameEmpty( curNode.NodeType ))
|
|
return String.Empty;
|
|
return curNode.LocalName;
|
|
}
|
|
}
|
|
|
|
internal bool IsOnAttrVal {
|
|
get {
|
|
return this.bOnAttrVal;
|
|
}
|
|
}
|
|
|
|
internal XmlNode OwnerElementNode {
|
|
get {
|
|
if( this.bCreatedOnAttribute )
|
|
return null;
|
|
return this.elemNode;
|
|
}
|
|
}
|
|
|
|
internal bool CreatedOnAttribute {
|
|
get {
|
|
return this.bCreatedOnAttribute;
|
|
}
|
|
}
|
|
|
|
private bool IsLocalNameEmpty ( XmlNodeType nt) {
|
|
switch ( nt ) {
|
|
case XmlNodeType.None :
|
|
case XmlNodeType.Text :
|
|
case XmlNodeType.CDATA :
|
|
case XmlNodeType.Comment :
|
|
case XmlNodeType.Document :
|
|
case XmlNodeType.DocumentFragment :
|
|
case XmlNodeType.Whitespace :
|
|
case XmlNodeType.SignificantWhitespace :
|
|
case XmlNodeType.EndElement :
|
|
case XmlNodeType.EndEntity :
|
|
return true;
|
|
case XmlNodeType.Element :
|
|
case XmlNodeType.Attribute :
|
|
case XmlNodeType.EntityReference :
|
|
case XmlNodeType.Entity :
|
|
case XmlNodeType.ProcessingInstruction :
|
|
case XmlNodeType.DocumentType :
|
|
case XmlNodeType.Notation :
|
|
case XmlNodeType.XmlDeclaration :
|
|
return false;
|
|
default :
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public String Prefix {
|
|
get { return curNode.Prefix; }
|
|
}
|
|
|
|
public bool HasValue {
|
|
//In DOM, DocumentType node and XmlDeclaration node doesn't value
|
|
//In XPathNavigator, XmlDeclaration node's value is its InnerText; DocumentType doesn't have value
|
|
//In XmlReader, DocumentType node's value is its InternalSubset which is never null ( at least String.Empty )
|
|
get {
|
|
if ( nAttrInd != -1 ) {
|
|
//Pointing at the one of virtual attributes of Declaration or DocumentType nodes
|
|
Debug.Assert( curNode.NodeType == XmlNodeType.XmlDeclaration || curNode.NodeType == XmlNodeType.DocumentType );
|
|
Debug.Assert( nAttrInd >= 0 && nAttrInd < AttributeCount );
|
|
return true;
|
|
}
|
|
if ( curNode.Value != null || curNode.NodeType == XmlNodeType.DocumentType )
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public String Value {
|
|
//See comments in HasValue
|
|
get {
|
|
String retValue = null;
|
|
XmlNodeType nt = curNode.NodeType;
|
|
if ( nAttrInd != -1 ) {
|
|
//Pointing at the one of virtual attributes of Declaration or DocumentType nodes
|
|
Debug.Assert( nt == XmlNodeType.XmlDeclaration || nt == XmlNodeType.DocumentType );
|
|
Debug.Assert( nAttrInd >= 0 && nAttrInd < AttributeCount );
|
|
if ( curNode.NodeType == XmlNodeType.XmlDeclaration )
|
|
return decNodeAttributes[nAttrInd].value;
|
|
else
|
|
return docTypeNodeAttributes[nAttrInd].value;
|
|
}
|
|
if ( nt == XmlNodeType.DocumentType )
|
|
retValue = ((XmlDocumentType)curNode).InternalSubset; //in this case nav.Value will be null
|
|
else if ( nt == XmlNodeType.XmlDeclaration ) {
|
|
StringBuilder strb = new StringBuilder(String.Empty);
|
|
if ( nDeclarationAttrCount == -1 )
|
|
InitDecAttr();
|
|
for ( int i = 0; i < nDeclarationAttrCount; i++ ) {
|
|
strb.Append(decNodeAttributes[i].name + "=\"" +decNodeAttributes[i].value + "\"");
|
|
if( i != ( nDeclarationAttrCount-1 ) )
|
|
strb.Append( " " );
|
|
}
|
|
retValue = strb.ToString();
|
|
} else
|
|
retValue = curNode.Value;
|
|
return ( retValue == null )? String.Empty : retValue;
|
|
}
|
|
}
|
|
|
|
public String BaseURI {
|
|
get { return curNode.BaseURI; }
|
|
}
|
|
|
|
public XmlSpace XmlSpace {
|
|
get { return curNode.XmlSpace; }
|
|
}
|
|
|
|
public String XmlLang {
|
|
get { return curNode.XmlLang; }
|
|
}
|
|
|
|
public bool IsEmptyElement {
|
|
get {
|
|
if (curNode.NodeType == XmlNodeType.Element) {
|
|
return((XmlElement)curNode).IsEmpty;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool IsDefault {
|
|
get {
|
|
if (curNode.NodeType == XmlNodeType.Attribute) {
|
|
return !((XmlAttribute)curNode).Specified;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public IXmlSchemaInfo SchemaInfo {
|
|
get {
|
|
return curNode.SchemaInfo;
|
|
}
|
|
}
|
|
|
|
public XmlNameTable NameTable {
|
|
get { return nameTable; }
|
|
}
|
|
|
|
public int AttributeCount {
|
|
get {
|
|
if( this.bCreatedOnAttribute )
|
|
return 0;
|
|
XmlNodeType nt = curNode.NodeType;
|
|
if ( nt == XmlNodeType.Element )
|
|
return ((XmlElement)curNode).Attributes.Count;
|
|
else if ( nt == XmlNodeType.Attribute
|
|
|| ( this.bOnAttrVal && nt != XmlNodeType.XmlDeclaration && nt != XmlNodeType.DocumentType ) )
|
|
return elemNode.Attributes.Count;
|
|
else if ( nt == XmlNodeType.XmlDeclaration ) {
|
|
if ( nDeclarationAttrCount != -1 )
|
|
return nDeclarationAttrCount;
|
|
InitDecAttr();
|
|
return nDeclarationAttrCount;
|
|
} else if ( nt == XmlNodeType.DocumentType ) {
|
|
if ( nDocTypeAttrCount != -1 )
|
|
return nDocTypeAttrCount;
|
|
InitDocTypeAttr();
|
|
return nDocTypeAttrCount;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private void CheckIndexCondition(int attributeIndex) {
|
|
if (attributeIndex < 0 || attributeIndex >= AttributeCount) {
|
|
throw new ArgumentOutOfRangeException( "attributeIndex" );
|
|
}
|
|
}
|
|
|
|
//8 functions below are the helper functions to deal with virtual attributes of XmlDeclaration nodes and DocumentType nodes.
|
|
private void InitDecAttr() {
|
|
int i = 0;
|
|
String strTemp = doc.Version;
|
|
if ( strTemp != null && strTemp.Length != 0 ) {
|
|
decNodeAttributes[i].name = strVersion;
|
|
decNodeAttributes[i].value = strTemp;
|
|
i++;
|
|
}
|
|
strTemp = doc.Encoding;
|
|
if ( strTemp != null && strTemp.Length != 0 ) {
|
|
decNodeAttributes[i].name = strEncoding;
|
|
decNodeAttributes[i].value = strTemp;
|
|
i++;
|
|
}
|
|
strTemp = doc.Standalone;
|
|
if ( strTemp != null && strTemp.Length != 0 ) {
|
|
decNodeAttributes[i].name = strStandalone;
|
|
decNodeAttributes[i].value = strTemp;
|
|
i++;
|
|
}
|
|
nDeclarationAttrCount = i;
|
|
}
|
|
|
|
public String GetDeclarationAttr( XmlDeclaration decl, String name ) {
|
|
//PreCondition: curNode is pointing at Declaration node or one of its virtual attributes
|
|
if ( name == strVersion )
|
|
return decl.Version;
|
|
if ( name == strEncoding )
|
|
return decl.Encoding;
|
|
if ( name == strStandalone )
|
|
return decl.Standalone;
|
|
return null;
|
|
}
|
|
|
|
public String GetDeclarationAttr( int i ) {
|
|
if ( nDeclarationAttrCount == -1 )
|
|
InitDecAttr();
|
|
return decNodeAttributes[i].value;
|
|
}
|
|
|
|
public int GetDecAttrInd( String name ) {
|
|
if ( nDeclarationAttrCount == -1 )
|
|
InitDecAttr();
|
|
for ( int i = 0 ; i < nDeclarationAttrCount; i++ ) {
|
|
if ( decNodeAttributes[i].name == name )
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private void InitDocTypeAttr() {
|
|
int i = 0;
|
|
XmlDocumentType docType = doc.DocumentType;
|
|
if ( docType == null ) {
|
|
nDocTypeAttrCount = 0;
|
|
return;
|
|
}
|
|
String strTemp = docType.PublicId;
|
|
if ( strTemp != null ) {
|
|
docTypeNodeAttributes[i].name = strPublicID;
|
|
docTypeNodeAttributes[i].value = strTemp;
|
|
i++;
|
|
}
|
|
strTemp = docType.SystemId;
|
|
if ( strTemp != null ) {
|
|
docTypeNodeAttributes[i].name = strSystemID;
|
|
docTypeNodeAttributes[i].value = strTemp;
|
|
i++;
|
|
}
|
|
nDocTypeAttrCount = i;
|
|
}
|
|
|
|
public String GetDocumentTypeAttr ( XmlDocumentType docType, String name ) {
|
|
//PreCondition: nav is pointing at DocumentType node or one of its virtual attributes
|
|
if ( name == strPublicID )
|
|
return docType.PublicId;
|
|
if ( name == strSystemID )
|
|
return docType.SystemId;
|
|
return null;
|
|
}
|
|
|
|
public String GetDocumentTypeAttr( int i ) {
|
|
if ( nDocTypeAttrCount == -1 )
|
|
InitDocTypeAttr();
|
|
return docTypeNodeAttributes[i].value;
|
|
}
|
|
|
|
public int GetDocTypeAttrInd( String name ) {
|
|
if ( nDocTypeAttrCount == -1 )
|
|
InitDocTypeAttr();
|
|
for ( int i = 0 ; i < nDocTypeAttrCount; i++ ) {
|
|
if ( docTypeNodeAttributes[i].name == name )
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private String GetAttributeFromElement( XmlElement elem, String name ) {
|
|
XmlAttribute attr = elem.GetAttributeNode( name );
|
|
if ( attr != null )
|
|
return attr.Value;
|
|
return null;
|
|
}
|
|
|
|
public String GetAttribute( String name ) {
|
|
if( this.bCreatedOnAttribute )
|
|
return null;
|
|
switch ( curNode.NodeType ) {
|
|
case XmlNodeType.Element:
|
|
return GetAttributeFromElement((XmlElement)curNode, name);
|
|
case XmlNodeType.Attribute :
|
|
return GetAttributeFromElement((XmlElement)elemNode, name);
|
|
case XmlNodeType.XmlDeclaration:
|
|
return GetDeclarationAttr( (XmlDeclaration)curNode, name );
|
|
case XmlNodeType.DocumentType:
|
|
return GetDocumentTypeAttr( (XmlDocumentType)curNode, name );
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private String GetAttributeFromElement( XmlElement elem, String name, String ns ) {
|
|
XmlAttribute attr = elem.GetAttributeNode( name, ns );
|
|
if ( attr != null )
|
|
return attr.Value;
|
|
return null;
|
|
}
|
|
public String GetAttribute( String name, String ns ) {
|
|
if( this.bCreatedOnAttribute )
|
|
return null;
|
|
switch ( curNode.NodeType ) {
|
|
case XmlNodeType.Element:
|
|
return GetAttributeFromElement((XmlElement)curNode, name, ns);
|
|
case XmlNodeType.Attribute :
|
|
return GetAttributeFromElement((XmlElement)elemNode, name, ns);
|
|
case XmlNodeType.XmlDeclaration:
|
|
return (ns.Length == 0) ? GetDeclarationAttr( (XmlDeclaration)curNode, name ) : null;
|
|
case XmlNodeType.DocumentType:
|
|
return (ns.Length == 0) ? GetDocumentTypeAttr( (XmlDocumentType)curNode, name ) : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public String GetAttribute( int attributeIndex ) {
|
|
if( this.bCreatedOnAttribute )
|
|
return null;
|
|
switch ( curNode.NodeType ) {
|
|
case XmlNodeType.Element:
|
|
CheckIndexCondition( attributeIndex );
|
|
return ((XmlElement)curNode).Attributes[attributeIndex].Value;
|
|
case XmlNodeType.Attribute :
|
|
CheckIndexCondition( attributeIndex );
|
|
return ((XmlElement)elemNode).Attributes[attributeIndex].Value;
|
|
case XmlNodeType.XmlDeclaration: {
|
|
CheckIndexCondition( attributeIndex );
|
|
return GetDeclarationAttr( attributeIndex );
|
|
}
|
|
case XmlNodeType.DocumentType: {
|
|
CheckIndexCondition( attributeIndex );
|
|
return GetDocumentTypeAttr( attributeIndex );
|
|
}
|
|
}
|
|
throw new ArgumentOutOfRangeException( "attributeIndex" ); //for other senario, AttributeCount is 0, i has to be out of range
|
|
}
|
|
|
|
public void LogMove( int level ) {
|
|
logNode = curNode;
|
|
nLogLevel = level;
|
|
nLogAttrInd = nAttrInd;
|
|
logAttrIndex = attrIndex;
|
|
this.bLogOnAttrVal = this.bOnAttrVal;
|
|
}
|
|
|
|
//The function has to be used in pair with ResetMove when the operation fails after LogMove() is
|
|
// called because it relies on the values of nOrigLevel, logNav and nOrigAttrInd to be acurate.
|
|
public void RollBackMove( ref int level ) {
|
|
curNode = logNode;
|
|
level = nLogLevel;
|
|
nAttrInd = nLogAttrInd;
|
|
attrIndex = logAttrIndex;
|
|
this.bOnAttrVal = this.bLogOnAttrVal;
|
|
}
|
|
|
|
private bool IsOnDeclOrDocType {
|
|
get {
|
|
XmlNodeType nt = curNode.NodeType;
|
|
return ( nt == XmlNodeType.XmlDeclaration || nt == XmlNodeType.DocumentType );
|
|
}
|
|
}
|
|
|
|
public void ResetToAttribute( ref int level ) {
|
|
//the current cursor is pointing at one of the attribute children -- this could be caused by
|
|
// the calls to ReadAttributeValue(..)
|
|
if( this.bCreatedOnAttribute )
|
|
return;
|
|
if ( this.bOnAttrVal ) {
|
|
if ( IsOnDeclOrDocType ) {
|
|
level-=2;
|
|
} else {
|
|
while ( curNode.NodeType != XmlNodeType.Attribute && ( ( curNode = curNode.ParentNode ) != null ) )
|
|
level-- ;
|
|
}
|
|
this.bOnAttrVal = false;
|
|
}
|
|
}
|
|
|
|
public void ResetMove( ref int level, ref XmlNodeType nt ) {
|
|
LogMove( level );
|
|
if( this.bCreatedOnAttribute )
|
|
return;
|
|
if ( nAttrInd != -1 ) {
|
|
Debug.Assert( IsOnDeclOrDocType );
|
|
if ( this.bOnAttrVal ) {
|
|
level--;
|
|
this.bOnAttrVal = false;
|
|
}
|
|
nLogAttrInd = nAttrInd;
|
|
level--;
|
|
nAttrInd = -1;
|
|
nt = curNode.NodeType;
|
|
return;
|
|
}
|
|
if ( this.bOnAttrVal && curNode.NodeType != XmlNodeType.Attribute )
|
|
ResetToAttribute( ref level );
|
|
if ( curNode.NodeType == XmlNodeType.Attribute ) {
|
|
curNode = ((XmlAttribute)curNode).OwnerElement;
|
|
attrIndex = -1;
|
|
level--;
|
|
nt = XmlNodeType.Element;
|
|
}
|
|
if ( curNode.NodeType == XmlNodeType.Element )
|
|
elemNode = curNode;
|
|
}
|
|
|
|
public bool MoveToAttribute( string name ) {
|
|
return MoveToAttribute( name, string.Empty );
|
|
}
|
|
private bool MoveToAttributeFromElement( XmlElement elem, String name, String ns ) {
|
|
XmlAttribute attr = null;
|
|
if( ns.Length == 0 )
|
|
attr = elem.GetAttributeNode( name );
|
|
else
|
|
attr = elem.GetAttributeNode( name, ns );
|
|
if ( attr != null ) {
|
|
this.bOnAttrVal = false;
|
|
elemNode = elem;
|
|
curNode = attr;
|
|
attrIndex = elem.Attributes.FindNodeOffsetNS(attr);
|
|
if (attrIndex != -1) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool MoveToAttribute( string name, string namespaceURI ) {
|
|
if( this.bCreatedOnAttribute )
|
|
return false;
|
|
XmlNodeType nt = curNode.NodeType;
|
|
if ( nt == XmlNodeType.Element )
|
|
return MoveToAttributeFromElement((XmlElement)curNode, name, namespaceURI );
|
|
else if ( nt == XmlNodeType.Attribute )
|
|
return MoveToAttributeFromElement((XmlElement)elemNode, name, namespaceURI );
|
|
else if ( nt == XmlNodeType.XmlDeclaration && namespaceURI.Length == 0 ) {
|
|
if ( ( nAttrInd = GetDecAttrInd( name ) ) != -1 ) {
|
|
this.bOnAttrVal = false;
|
|
return true;
|
|
}
|
|
} else if ( nt == XmlNodeType.DocumentType && namespaceURI.Length == 0 ) {
|
|
if ( ( nAttrInd = GetDocTypeAttrInd( name ) ) != -1 ) {
|
|
this.bOnAttrVal = false;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void MoveToAttribute( int attributeIndex ) {
|
|
if( this.bCreatedOnAttribute )
|
|
return;
|
|
XmlAttribute attr = null;
|
|
switch ( curNode.NodeType ) {
|
|
case XmlNodeType.Element:
|
|
CheckIndexCondition( attributeIndex );
|
|
attr = ((XmlElement)curNode).Attributes[attributeIndex];
|
|
if ( attr != null ) {
|
|
elemNode = curNode;
|
|
curNode = (XmlNode) attr;
|
|
attrIndex = attributeIndex;
|
|
}
|
|
break;
|
|
case XmlNodeType.Attribute:
|
|
CheckIndexCondition( attributeIndex );
|
|
attr = ((XmlElement)elemNode).Attributes[attributeIndex];
|
|
if ( attr != null ) {
|
|
curNode = (XmlNode) attr;
|
|
attrIndex = attributeIndex;
|
|
}
|
|
break;
|
|
case XmlNodeType.XmlDeclaration :
|
|
case XmlNodeType.DocumentType :
|
|
CheckIndexCondition( attributeIndex );
|
|
nAttrInd = attributeIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public bool MoveToNextAttribute( ref int level ) {
|
|
if( this.bCreatedOnAttribute )
|
|
return false;
|
|
XmlNodeType nt = curNode.NodeType;
|
|
if ( nt == XmlNodeType.Attribute ) {
|
|
if( attrIndex >= ( elemNode.Attributes.Count-1 ) )
|
|
return false;
|
|
else {
|
|
curNode = elemNode.Attributes[++attrIndex];
|
|
return true;
|
|
}
|
|
} else if ( nt == XmlNodeType.Element ) {
|
|
if ( curNode.Attributes.Count > 0 ) {
|
|
level++;
|
|
elemNode = curNode;
|
|
curNode = curNode.Attributes[0];
|
|
attrIndex = 0;
|
|
return true;
|
|
}
|
|
} else if ( nt == XmlNodeType.XmlDeclaration ) {
|
|
if ( nDeclarationAttrCount == -1 )
|
|
InitDecAttr();
|
|
nAttrInd++;
|
|
if ( nAttrInd < nDeclarationAttrCount ) {
|
|
if ( nAttrInd == 0 ) level++;
|
|
this.bOnAttrVal = false;
|
|
return true;
|
|
}
|
|
nAttrInd--;
|
|
} else if ( nt == XmlNodeType.DocumentType ) {
|
|
if ( nDocTypeAttrCount == -1 )
|
|
InitDocTypeAttr();
|
|
nAttrInd++;
|
|
if ( nAttrInd < nDocTypeAttrCount ) {
|
|
if ( nAttrInd == 0 ) level++;
|
|
this.bOnAttrVal = false;
|
|
return true;
|
|
}
|
|
nAttrInd--;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool MoveToParent() {
|
|
XmlNode parent = curNode.ParentNode;
|
|
if ( parent != null ) {
|
|
curNode = parent;
|
|
if( !bOnAttrVal )
|
|
attrIndex = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool MoveToFirstChild() {
|
|
XmlNode firstChild = curNode.FirstChild;
|
|
if ( firstChild != null ) {
|
|
curNode = firstChild;
|
|
if( !bOnAttrVal )
|
|
attrIndex = -1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool MoveToNextSibling( XmlNode node ) {
|
|
XmlNode nextSibling = node.NextSibling;
|
|
if ( nextSibling != null ) {
|
|
curNode = nextSibling;
|
|
if( !bOnAttrVal )
|
|
attrIndex = -1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool MoveToNext() {
|
|
if ( curNode.NodeType != XmlNodeType.Attribute )
|
|
return MoveToNextSibling( curNode );
|
|
else
|
|
return MoveToNextSibling( elemNode );
|
|
}
|
|
|
|
public bool MoveToElement() {
|
|
if( this.bCreatedOnAttribute )
|
|
return false;
|
|
switch ( curNode.NodeType ) {
|
|
case XmlNodeType.Attribute :
|
|
if ( elemNode != null ) {
|
|
curNode = elemNode;
|
|
attrIndex = -1;
|
|
return true;
|
|
}
|
|
break;
|
|
case XmlNodeType.XmlDeclaration :
|
|
case XmlNodeType.DocumentType : {
|
|
if ( nAttrInd != -1 ) {
|
|
nAttrInd = -1;
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public String LookupNamespace(string prefix) {
|
|
if( this.bCreatedOnAttribute )
|
|
return null;
|
|
if ( prefix == "xmlns" ) {
|
|
return nameTable.Add( XmlReservedNs.NsXmlNs );
|
|
}
|
|
if ( prefix == "xml" ) {
|
|
return nameTable.Add( XmlReservedNs.NsXml );
|
|
}
|
|
|
|
// construct the name of the xmlns attribute
|
|
string attrName;
|
|
if ( prefix == null )
|
|
prefix = string.Empty;
|
|
if ( prefix.Length == 0 )
|
|
attrName = "xmlns";
|
|
else
|
|
attrName = "xmlns:" + prefix;
|
|
|
|
// walk up the XmlNode parent chain, looking for the xmlns attribute
|
|
XmlNode node = curNode;
|
|
while ( node != null ) {
|
|
if ( node.NodeType == XmlNodeType.Element ) {
|
|
XmlElement elem = (XmlElement)node;
|
|
if ( elem.HasAttributes ) {
|
|
XmlAttribute attr = elem.GetAttributeNode( attrName );
|
|
if ( attr != null ) {
|
|
return attr.Value;
|
|
}
|
|
}
|
|
}
|
|
else if ( node.NodeType == XmlNodeType.Attribute ) {
|
|
node = ((XmlAttribute)node).OwnerElement;
|
|
continue;
|
|
}
|
|
node = node.ParentNode;
|
|
}
|
|
if ( prefix.Length == 0 ) {
|
|
return string.Empty;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal string DefaultLookupNamespace( string prefix ) {
|
|
if( !this.bCreatedOnAttribute ) {
|
|
if ( prefix == "xmlns" ) {
|
|
return nameTable.Add( XmlReservedNs.NsXmlNs );
|
|
}
|
|
if ( prefix == "xml" ) {
|
|
return nameTable.Add( XmlReservedNs.NsXml );
|
|
}
|
|
if ( prefix == string.Empty ) {
|
|
return nameTable.Add( string.Empty );
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal String LookupPrefix(string namespaceName) {
|
|
if( this.bCreatedOnAttribute || namespaceName == null ) {
|
|
return null;
|
|
}
|
|
if ( namespaceName == XmlReservedNs.NsXmlNs ) {
|
|
return nameTable.Add( "xmlns" );
|
|
}
|
|
if ( namespaceName == XmlReservedNs.NsXml ) {
|
|
return nameTable.Add( "xml" );
|
|
}
|
|
if ( namespaceName == string.Empty ) {
|
|
return string.Empty;
|
|
}
|
|
// walk up the XmlNode parent chain, looking for the xmlns attribute with namespaceName value
|
|
XmlNode node = curNode;
|
|
while ( node != null ) {
|
|
if ( node.NodeType == XmlNodeType.Element ) {
|
|
XmlElement elem = (XmlElement)node;
|
|
if ( elem.HasAttributes ) {
|
|
XmlAttributeCollection attrs = elem.Attributes;
|
|
for ( int i = 0; i < attrs.Count; i++ ) {
|
|
XmlAttribute a = attrs[i];
|
|
if ( a.Value == namespaceName ) {
|
|
if ( a.Prefix.Length == 0 && a.LocalName == "xmlns" ) {
|
|
if ( LookupNamespace( string.Empty ) == namespaceName ) {
|
|
return string.Empty;
|
|
}
|
|
}
|
|
else if ( a.Prefix == "xmlns" ) {
|
|
string pref = a.LocalName;
|
|
if ( LookupNamespace( pref ) == namespaceName ) {
|
|
return nameTable.Add( pref );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( node.NodeType == XmlNodeType.Attribute ) {
|
|
node = ((XmlAttribute)node).OwnerElement;
|
|
continue;
|
|
}
|
|
node = node.ParentNode;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal IDictionary<string,string> GetNamespacesInScope( XmlNamespaceScope scope ) {
|
|
Dictionary<string,string> dict = new Dictionary<string, string>();
|
|
if( this.bCreatedOnAttribute )
|
|
return dict;
|
|
|
|
// walk up the XmlNode parent chain and add all namespace declarations to the dictionary
|
|
XmlNode node = curNode;
|
|
while ( node != null ) {
|
|
if ( node.NodeType == XmlNodeType.Element ) {
|
|
XmlElement elem = (XmlElement)node;
|
|
if ( elem.HasAttributes ) {
|
|
XmlAttributeCollection attrs = elem.Attributes;
|
|
for ( int i = 0; i < attrs.Count; i++ ) {
|
|
XmlAttribute a = attrs[i];
|
|
if ( a.LocalName == "xmlns" && a.Prefix.Length == 0 ) {
|
|
if ( !dict.ContainsKey( string.Empty ) ) {
|
|
dict.Add( nameTable.Add( string.Empty ), nameTable.Add( a.Value ) );
|
|
}
|
|
}
|
|
else if ( a.Prefix == "xmlns" ) {
|
|
string localName = a.LocalName;
|
|
if ( !dict.ContainsKey( localName ) ) {
|
|
dict.Add( nameTable.Add( localName ), nameTable.Add( a.Value ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( scope == XmlNamespaceScope.Local ) {
|
|
break;
|
|
}
|
|
}
|
|
else if ( node.NodeType == XmlNodeType.Attribute ) {
|
|
node = ((XmlAttribute)node).OwnerElement;
|
|
continue;
|
|
}
|
|
node = node.ParentNode;
|
|
};
|
|
|
|
if ( scope != XmlNamespaceScope.Local ) {
|
|
if ( dict.ContainsKey( string.Empty ) && dict[string.Empty] == string.Empty ) {
|
|
dict.Remove( string.Empty );
|
|
}
|
|
if ( scope == XmlNamespaceScope.All ) {
|
|
dict.Add( nameTable.Add( "xml" ), nameTable.Add( XmlReservedNs.NsXml ) );
|
|
}
|
|
}
|
|
return dict;
|
|
}
|
|
|
|
public bool ReadAttributeValue( ref int level, ref bool bResolveEntity, ref XmlNodeType nt ) {
|
|
if ( nAttrInd != -1 ) {
|
|
Debug.Assert( curNode.NodeType == XmlNodeType.XmlDeclaration || curNode.NodeType == XmlNodeType.DocumentType );
|
|
if ( !this.bOnAttrVal ) {
|
|
this.bOnAttrVal = true;
|
|
level++;
|
|
nt = XmlNodeType.Text;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if( curNode.NodeType == XmlNodeType.Attribute ) {
|
|
XmlNode firstChild = curNode.FirstChild;
|
|
if ( firstChild != null ) {
|
|
curNode = firstChild;
|
|
nt = curNode.NodeType;
|
|
level++;
|
|
this.bOnAttrVal = true;
|
|
return true;
|
|
}
|
|
}
|
|
else if ( this.bOnAttrVal ) {
|
|
XmlNode nextSibling = null;
|
|
if ( curNode.NodeType == XmlNodeType.EntityReference && bResolveEntity ) {
|
|
//going down to ent ref node
|
|
curNode = curNode.FirstChild;
|
|
nt = curNode.NodeType;
|
|
Debug.Assert( curNode != null );
|
|
level++;
|
|
bResolveEntity = false;
|
|
return true;
|
|
}
|
|
else
|
|
nextSibling = curNode.NextSibling;
|
|
if ( nextSibling == null ) {
|
|
XmlNode parentNode = curNode.ParentNode;
|
|
//Check if its parent is entity ref node is sufficient, because in this senario, ent ref node can't have more than 1 level of children that are not other ent ref nodes
|
|
if ( parentNode != null && parentNode.NodeType == XmlNodeType.EntityReference ) {
|
|
//come back from ent ref node
|
|
curNode = parentNode;
|
|
nt = XmlNodeType.EndEntity;
|
|
level--;
|
|
return true;
|
|
}
|
|
}
|
|
if ( nextSibling != null ) {
|
|
curNode = nextSibling;
|
|
nt = curNode.NodeType;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public XmlDocument Document {
|
|
get {
|
|
return this.doc;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Represents a reader that provides fast, non-cached forward only stream access
|
|
// to XML data in an XmlDocument or a specific XmlNode within an XmlDocument.
|
|
public class XmlNodeReader: XmlReader, IXmlNamespaceResolver
|
|
{
|
|
XmlNodeReaderNavigator readerNav;
|
|
|
|
XmlNodeType nodeType; // nodeType of the node that the reader is currently positioned on
|
|
int curDepth; // depth of attrNav ( also functions as reader's depth )
|
|
ReadState readState; // current reader's state
|
|
bool fEOF; // flag to show if reaches the end of file
|
|
//mark to the state that EntityReference node is supposed to be resolved
|
|
bool bResolveEntity;
|
|
bool bStartFromDocument;
|
|
|
|
bool bInReadBinary;
|
|
ReadContentAsBinaryHelper readBinaryHelper;
|
|
|
|
|
|
// Creates an instance of the XmlNodeReader class using the specified XmlNode.
|
|
public XmlNodeReader ( XmlNode node ) {
|
|
if (node == null) {
|
|
throw new ArgumentNullException("node");
|
|
}
|
|
readerNav = new XmlNodeReaderNavigator( node );
|
|
this.curDepth = 0;
|
|
|
|
readState = ReadState.Initial;
|
|
fEOF = false;
|
|
nodeType = XmlNodeType.None;
|
|
bResolveEntity = false;
|
|
bStartFromDocument = false;
|
|
}
|
|
|
|
//function returns if the reader currently in valid reading states
|
|
internal bool IsInReadingStates() {
|
|
return ( readState == ReadState.Interactive ); // || readState == ReadState.EndOfFile
|
|
}
|
|
|
|
//
|
|
// Node Properties
|
|
//
|
|
|
|
// Gets the type of the current node.
|
|
public override XmlNodeType NodeType {
|
|
get { return ( IsInReadingStates() )? nodeType : XmlNodeType.None; }
|
|
}
|
|
|
|
// Gets the name of
|
|
// the current node, including the namespace prefix.
|
|
public override string Name {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return String.Empty;
|
|
return readerNav.Name;
|
|
}
|
|
}
|
|
|
|
// Gets the name of the current node without the namespace prefix.
|
|
public override string LocalName {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return String.Empty;
|
|
return readerNav.LocalName;
|
|
}
|
|
}
|
|
|
|
// Gets the namespace URN (as defined in the W3C Namespace Specification)
|
|
// of the current namespace scope.
|
|
public override string NamespaceURI {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return String.Empty;
|
|
return readerNav.NamespaceURI;
|
|
}
|
|
}
|
|
|
|
// Gets the namespace prefix associated with the current node.
|
|
public override string Prefix {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return String.Empty;
|
|
return readerNav.Prefix;
|
|
}
|
|
}
|
|
|
|
// Gets a value indicating whether
|
|
// XmlNodeReader.Value has a value to return.
|
|
public override bool HasValue {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
return readerNav.HasValue;
|
|
}
|
|
}
|
|
|
|
// Gets the text value of the current node.
|
|
public override string Value {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return String.Empty;
|
|
return readerNav.Value;
|
|
}
|
|
}
|
|
|
|
// Gets the depth of the
|
|
// current node in the XML element stack.
|
|
public override int Depth {
|
|
get { return curDepth; }
|
|
}
|
|
|
|
// Gets the base URI of the current node.
|
|
public override String BaseURI {
|
|
get { return readerNav.BaseURI; }
|
|
}
|
|
|
|
public override bool CanResolveEntity {
|
|
get { return true; }
|
|
}
|
|
|
|
// Gets a value indicating whether the current
|
|
// node is an empty element (for example, <MyElement/>.
|
|
public override bool IsEmptyElement {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
return readerNav.IsEmptyElement;
|
|
}
|
|
}
|
|
|
|
// Gets a value indicating whether the current node is an
|
|
// attribute that was generated from the default value defined
|
|
// in the DTD or schema.
|
|
public override bool IsDefault {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
return readerNav.IsDefault;
|
|
}
|
|
}
|
|
|
|
// Gets the current xml:space scope.
|
|
public override XmlSpace XmlSpace {
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return XmlSpace.None;
|
|
return readerNav.XmlSpace;
|
|
}
|
|
}
|
|
|
|
// Gets the current xml:lang scope.
|
|
public override string XmlLang {
|
|
// Assume everything is in Unicode
|
|
get {
|
|
if ( !IsInReadingStates() )
|
|
return String.Empty;
|
|
return readerNav.XmlLang;
|
|
}
|
|
}
|
|
|
|
public override IXmlSchemaInfo SchemaInfo {
|
|
get {
|
|
if (!IsInReadingStates()) {
|
|
return null;
|
|
}
|
|
return readerNav.SchemaInfo;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Attribute Accessors
|
|
//
|
|
|
|
// Gets the number of attributes on the current node.
|
|
public override int AttributeCount {
|
|
get {
|
|
if ( !IsInReadingStates() || nodeType == XmlNodeType.EndElement )
|
|
return 0;
|
|
return readerNav.AttributeCount;
|
|
}
|
|
}
|
|
|
|
// Gets the value of the attribute with the specified name.
|
|
public override string GetAttribute(string name) {
|
|
//if not on Attribute, only element node could have attributes
|
|
if ( !IsInReadingStates() )
|
|
return null;
|
|
return readerNav.GetAttribute( name );
|
|
}
|
|
|
|
// Gets the value of the attribute with the specified name and namespace.
|
|
public override string GetAttribute(string name, string namespaceURI) {
|
|
//if not on Attribute, only element node could have attributes
|
|
if ( !IsInReadingStates() )
|
|
return null;
|
|
String ns = ( namespaceURI == null ) ? String.Empty : namespaceURI;
|
|
return readerNav.GetAttribute( name, ns );
|
|
}
|
|
|
|
// Gets the value of the attribute with the specified index.
|
|
public override string GetAttribute(int attributeIndex) {
|
|
if ( !IsInReadingStates() )
|
|
throw new ArgumentOutOfRangeException( "attributeIndex" );
|
|
//CheckIndexCondition( i );
|
|
//Debug.Assert( nav.NodeType == XmlNodeType.Element );
|
|
return readerNav.GetAttribute( attributeIndex );
|
|
}
|
|
|
|
// Moves to the attribute with the specified name.
|
|
public override bool MoveToAttribute(string name) {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
readerNav.ResetMove( ref curDepth, ref nodeType );
|
|
if ( readerNav.MoveToAttribute( name ) ) { //, ref curDepth ) ) {
|
|
curDepth++;
|
|
nodeType = readerNav.NodeType;
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
return true;
|
|
}
|
|
readerNav.RollBackMove(ref curDepth);
|
|
return false;
|
|
}
|
|
|
|
// Moves to the attribute with the specified name and namespace.
|
|
public override bool MoveToAttribute(string name, string namespaceURI) {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
readerNav.ResetMove( ref curDepth, ref nodeType );
|
|
String ns = ( namespaceURI == null ) ? String.Empty : namespaceURI;
|
|
if ( readerNav.MoveToAttribute( name, ns ) ) { //, ref curDepth ) ) {
|
|
curDepth++;
|
|
nodeType = readerNav.NodeType;
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
return true;
|
|
}
|
|
readerNav.RollBackMove(ref curDepth);
|
|
return false;
|
|
}
|
|
|
|
// Moves to the attribute with the specified index.
|
|
public override void MoveToAttribute(int attributeIndex) {
|
|
if ( !IsInReadingStates() )
|
|
throw new ArgumentOutOfRangeException( "attributeIndex" );
|
|
readerNav.ResetMove( ref curDepth, ref nodeType );
|
|
try {
|
|
if (AttributeCount > 0) {
|
|
readerNav.MoveToAttribute( attributeIndex );
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
}
|
|
else
|
|
throw new ArgumentOutOfRangeException( "attributeIndex" );
|
|
} catch {
|
|
readerNav.RollBackMove(ref curDepth);
|
|
throw;
|
|
}
|
|
curDepth++;
|
|
nodeType = readerNav.NodeType;
|
|
}
|
|
|
|
// Moves to the first attribute.
|
|
public override bool MoveToFirstAttribute() {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
readerNav.ResetMove( ref curDepth, ref nodeType );
|
|
if (AttributeCount > 0) {
|
|
readerNav.MoveToAttribute( 0 );
|
|
curDepth++;
|
|
nodeType = readerNav.NodeType;
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
return true;
|
|
}
|
|
readerNav.RollBackMove( ref curDepth );
|
|
return false;
|
|
}
|
|
|
|
// Moves to the next attribute.
|
|
public override bool MoveToNextAttribute() {
|
|
if ( !IsInReadingStates() || nodeType == XmlNodeType.EndElement )
|
|
return false;
|
|
readerNav.LogMove( curDepth );
|
|
readerNav.ResetToAttribute( ref curDepth );
|
|
if ( readerNav.MoveToNextAttribute( ref curDepth ) ) {
|
|
nodeType = readerNav.NodeType;
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
return true;
|
|
}
|
|
readerNav.RollBackMove( ref curDepth );
|
|
return false;
|
|
}
|
|
|
|
// Moves to the element that contains the current attribute node.
|
|
public override bool MoveToElement() {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
readerNav.LogMove( curDepth );
|
|
readerNav.ResetToAttribute( ref curDepth );
|
|
if ( readerNav.MoveToElement() ) {
|
|
curDepth--;
|
|
nodeType = readerNav.NodeType;
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
return true;
|
|
}
|
|
readerNav.RollBackMove( ref curDepth );
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Moving through the Stream
|
|
//
|
|
|
|
// Reads the next node from the stream.
|
|
public override bool Read() {
|
|
return Read( false );
|
|
}
|
|
private bool Read( bool fSkipChildren ) {
|
|
if( fEOF )
|
|
return false;
|
|
|
|
if ( readState == ReadState.Initial ) {
|
|
// if nav is pointing at the document node, start with its children
|
|
// otherwise,start with the node.
|
|
if ( ( readerNav.NodeType == XmlNodeType.Document ) || ( readerNav.NodeType == XmlNodeType.DocumentFragment ) ) {
|
|
bStartFromDocument = true;
|
|
if ( !ReadNextNode(fSkipChildren) ) {
|
|
readState = ReadState.Error;
|
|
return false;
|
|
}
|
|
}
|
|
ReSetReadingMarks();
|
|
readState = ReadState.Interactive;
|
|
nodeType = readerNav.NodeType;
|
|
//_depth = 0;
|
|
curDepth = 0;
|
|
return true;
|
|
}
|
|
|
|
if ( bInReadBinary ) {
|
|
FinishReadBinary();
|
|
}
|
|
|
|
bool bRead = false;
|
|
if( ( readerNav.CreatedOnAttribute ) )
|
|
return false;
|
|
ReSetReadingMarks();
|
|
bRead = ReadNextNode(fSkipChildren);
|
|
if ( bRead ) {
|
|
return true;
|
|
} else {
|
|
if ( readState == ReadState.Initial || readState == ReadState.Interactive )
|
|
readState = ReadState.Error;
|
|
if ( readState == ReadState.EndOfFile )
|
|
nodeType = XmlNodeType.None;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool ReadNextNode( bool fSkipChildren ) {
|
|
if ( readState != ReadState.Interactive && readState != ReadState.Initial ) {
|
|
nodeType = XmlNodeType.None;
|
|
return false;
|
|
}
|
|
|
|
bool bDrillDown = !fSkipChildren;
|
|
XmlNodeType nt = readerNav.NodeType;
|
|
//only goes down when nav.NodeType is of element or of document at the initial state, other nav.NodeType will not be parsed down
|
|
//if nav.NodeType is of EntityReference, ResolveEntity() could be called to get the content parsed;
|
|
bDrillDown = bDrillDown
|
|
&& ( nodeType != XmlNodeType.EndElement )
|
|
&& ( nodeType != XmlNodeType.EndEntity )
|
|
&& ( nt == XmlNodeType.Element || ( nt == XmlNodeType.EntityReference && bResolveEntity ) ||
|
|
( ( ( readerNav.NodeType == XmlNodeType.Document ) || ( readerNav.NodeType == XmlNodeType.DocumentFragment ) ) && readState == ReadState.Initial) );
|
|
//first see if there are children of current node, so to move down
|
|
if ( bDrillDown ) {
|
|
if ( readerNav.MoveToFirstChild() ) {
|
|
nodeType = readerNav.NodeType;
|
|
curDepth++;
|
|
if ( bResolveEntity )
|
|
bResolveEntity = false;
|
|
return true;
|
|
} else if ( readerNav.NodeType == XmlNodeType.Element
|
|
&& !readerNav.IsEmptyElement ) {
|
|
nodeType = XmlNodeType.EndElement;
|
|
return true;
|
|
}
|
|
else if (readerNav.NodeType == XmlNodeType.EntityReference && bResolveEntity) {
|
|
bResolveEntity = false;
|
|
nodeType = XmlNodeType.EndEntity;
|
|
return true;
|
|
}
|
|
// if fails to move to it 1st Child, try to move to next below
|
|
return ReadForward( fSkipChildren );
|
|
} else {
|
|
if ( readerNav.NodeType == XmlNodeType.EntityReference && bResolveEntity ) {
|
|
//The only way to get to here is because Skip() is called directly after ResolveEntity()
|
|
// in this case, user wants to skip the first Child of EntityRef node and fSkipChildren is true
|
|
// We want to pointing to the first child node.
|
|
if (readerNav.MoveToFirstChild()) {
|
|
nodeType = readerNav.NodeType;
|
|
curDepth++;
|
|
}
|
|
else {
|
|
nodeType = XmlNodeType.EndEntity;
|
|
}
|
|
bResolveEntity = false;
|
|
return true;
|
|
}
|
|
}
|
|
return ReadForward( fSkipChildren ); //has to get the next node by moving forward
|
|
}
|
|
|
|
private void SetEndOfFile() {
|
|
fEOF = true;
|
|
readState = ReadState.EndOfFile;
|
|
nodeType = XmlNodeType.None;
|
|
}
|
|
|
|
private bool ReadAtZeroLevel(bool fSkipChildren) {
|
|
Debug.Assert( curDepth == 0 );
|
|
if ( !fSkipChildren
|
|
&& nodeType != XmlNodeType.EndElement
|
|
&& readerNav.NodeType == XmlNodeType.Element
|
|
&& !readerNav.IsEmptyElement ) {
|
|
nodeType = XmlNodeType.EndElement;
|
|
return true;
|
|
} else {
|
|
SetEndOfFile();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool ReadForward( bool fSkipChildren ) {
|
|
if ( readState == ReadState.Error )
|
|
return false;
|
|
|
|
if ( !bStartFromDocument && curDepth == 0 ) {
|
|
//already on top most node and we shouldn't move to next
|
|
return ReadAtZeroLevel(fSkipChildren);
|
|
}
|
|
//else either we are not on top level or we are starting from the document at the very beginning in which case
|
|
// we will need to read all the "top" most nodes
|
|
if ( readerNav.MoveToNext() ) {
|
|
nodeType = readerNav.NodeType;
|
|
return true;
|
|
} else {
|
|
//need to check its parent
|
|
if ( curDepth == 0 )
|
|
return ReadAtZeroLevel(fSkipChildren);
|
|
if ( readerNav.MoveToParent() ) {
|
|
if ( readerNav.NodeType == XmlNodeType.Element ) {
|
|
curDepth--;
|
|
nodeType = XmlNodeType.EndElement;
|
|
return true;
|
|
} else if ( readerNav.NodeType == XmlNodeType.EntityReference ) {
|
|
//coming back from entity reference node -- must be getting down through call ResolveEntity()
|
|
curDepth--;
|
|
nodeType = XmlNodeType.EndEntity;
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//the function reset the marks used for ReadChars() and MoveToAttribute(...), ReadAttributeValue(...)
|
|
private void ReSetReadingMarks() {
|
|
//_attrValInd = -1;
|
|
readerNav.ResetMove( ref curDepth, ref nodeType );
|
|
//attrNav.MoveTo( nav );
|
|
//curDepth = _depth;
|
|
}
|
|
|
|
// Gets a value indicating whether the reader is positioned at the
|
|
// end of the stream.
|
|
public override bool EOF {
|
|
get { return (readState != ReadState.Closed) && fEOF; }
|
|
}
|
|
|
|
// Closes the stream, changes the XmlNodeReader.ReadState
|
|
// to Closed, and sets all the properties back to zero.
|
|
public override void Close() {
|
|
readState = ReadState.Closed;
|
|
}
|
|
|
|
// Gets the read state of the stream.
|
|
public override ReadState ReadState {
|
|
get { return readState; }
|
|
}
|
|
|
|
// Skips to the end tag of the current element.
|
|
public override void Skip() {
|
|
Read( true );
|
|
}
|
|
|
|
// Reads the contents of an element as a string.
|
|
public override string ReadString() {
|
|
if ((this.NodeType == XmlNodeType.EntityReference) && bResolveEntity) {
|
|
if (! this.Read()) {
|
|
throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
|
|
}
|
|
}
|
|
return base.ReadString();
|
|
}
|
|
|
|
//
|
|
// Partial Content Read Methods
|
|
//
|
|
|
|
// Gets a value indicating whether the current node
|
|
// has any attributes.
|
|
public override bool HasAttributes {
|
|
get {
|
|
return ( AttributeCount > 0 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Nametable and Namespace Helpers
|
|
//
|
|
|
|
// Gets the XmlNameTable associated with this implementation.
|
|
public override XmlNameTable NameTable {
|
|
get { return readerNav.NameTable; }
|
|
}
|
|
|
|
// Resolves a namespace prefix in the current element's scope.
|
|
public override String LookupNamespace(string prefix) {
|
|
if ( !IsInReadingStates() )
|
|
return null;
|
|
string ns = readerNav.LookupNamespace( prefix );
|
|
if (ns != null && ns.Length == 0) {
|
|
return null;
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
// Resolves the entity reference for nodes of NodeType EntityReference.
|
|
public override void ResolveEntity() {
|
|
if ( !IsInReadingStates() || ( nodeType != XmlNodeType.EntityReference ) )
|
|
throw new InvalidOperationException(Res.GetString(Res.Xnr_ResolveEntity));
|
|
bResolveEntity = true;;
|
|
}
|
|
|
|
// Parses the attribute value into one or more Text and/or
|
|
// EntityReference node types.
|
|
public override bool ReadAttributeValue() {
|
|
if ( !IsInReadingStates() )
|
|
return false;
|
|
if ( readerNav.ReadAttributeValue( ref curDepth, ref bResolveEntity, ref nodeType ) ) {
|
|
bInReadBinary = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override bool CanReadBinaryContent {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override int ReadContentAsBase64( byte[] buffer, int index, int count ) {
|
|
if ( readState != ReadState.Interactive ) {
|
|
return 0;
|
|
}
|
|
|
|
// init ReadContentAsBinaryHelper when called first time
|
|
if ( !bInReadBinary ) {
|
|
readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
|
|
}
|
|
|
|
// turn off bInReadBinary in order to have a normal Read() behavior when called from readBinaryHelper
|
|
bInReadBinary = false;
|
|
|
|
// call to the helper
|
|
int readCount = readBinaryHelper.ReadContentAsBase64( buffer, index, count );
|
|
|
|
// turn on bInReadBinary in again and return
|
|
bInReadBinary = true;
|
|
return readCount;
|
|
}
|
|
|
|
public override int ReadContentAsBinHex( byte[] buffer, int index, int count ) {
|
|
if ( readState != ReadState.Interactive ) {
|
|
return 0;
|
|
}
|
|
|
|
// init ReadContentAsBinaryHelper when called first time
|
|
if ( !bInReadBinary ) {
|
|
readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
|
|
}
|
|
|
|
// turn off bInReadBinary in order to have a normal Read() behavior when called from readBinaryHelper
|
|
bInReadBinary = false;
|
|
|
|
// call to the helper
|
|
int readCount = readBinaryHelper.ReadContentAsBinHex( buffer, index, count );
|
|
|
|
// turn on bInReadBinary in again and return
|
|
bInReadBinary = true;
|
|
return readCount;
|
|
}
|
|
|
|
public override int ReadElementContentAsBase64( byte[] buffer, int index, int count ) {
|
|
if ( readState != ReadState.Interactive ) {
|
|
return 0;
|
|
}
|
|
|
|
// init ReadContentAsBinaryHelper when called first time
|
|
if ( !bInReadBinary ) {
|
|
readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
|
|
}
|
|
|
|
// turn off bInReadBinary in order to have a normal Read() behavior when called from readBinaryHelper
|
|
bInReadBinary = false;
|
|
|
|
// call to the helper
|
|
int readCount = readBinaryHelper.ReadElementContentAsBase64( buffer, index, count );
|
|
|
|
// turn on bInReadBinary in again and return
|
|
bInReadBinary = true;
|
|
return readCount;
|
|
}
|
|
|
|
public override int ReadElementContentAsBinHex( byte[] buffer, int index, int count ) {
|
|
if ( readState != ReadState.Interactive ) {
|
|
return 0;
|
|
}
|
|
|
|
// init ReadContentAsBinaryHelper when called first time
|
|
if ( !bInReadBinary ) {
|
|
readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
|
|
}
|
|
|
|
// turn off bInReadBinary in order to have a normal Read() behavior when called from readBinaryHelper
|
|
bInReadBinary = false;
|
|
|
|
// call to the helper
|
|
int readCount = readBinaryHelper.ReadElementContentAsBinHex( buffer, index, count );
|
|
|
|
// turn on bInReadBinary in again and return
|
|
bInReadBinary = true;
|
|
return readCount;
|
|
}
|
|
|
|
void FinishReadBinary() {
|
|
bInReadBinary = false;
|
|
readBinaryHelper.Finish();
|
|
}
|
|
|
|
//
|
|
// IXmlNamespaceResolver
|
|
//
|
|
|
|
IDictionary<string,string> IXmlNamespaceResolver.GetNamespacesInScope( XmlNamespaceScope scope ) {
|
|
return readerNav.GetNamespacesInScope( scope );
|
|
}
|
|
|
|
string IXmlNamespaceResolver.LookupPrefix( string namespaceName ) {
|
|
return readerNav.LookupPrefix( namespaceName );
|
|
}
|
|
|
|
String IXmlNamespaceResolver.LookupNamespace( string prefix ) {
|
|
if ( !IsInReadingStates() ) {
|
|
return readerNav.DefaultLookupNamespace( prefix );
|
|
}
|
|
string ns = readerNav.LookupNamespace( prefix );
|
|
if ( ns != null ) {
|
|
ns = readerNav.NameTable.Add( ns );
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
// DTD/Schema info used by XmlReader.GetDtdSchemaInfo()
|
|
internal override IDtdInfo DtdInfo {
|
|
get {
|
|
return readerNav.Document.DtdSchemaInfo;
|
|
}
|
|
}
|
|
}
|
|
}
|