834 lines
20 KiB
C#
834 lines
20 KiB
C#
//
|
|
// System.Xml.XmlNodeReaderImpl.cs - implements the core part of XmlNodeReader
|
|
//
|
|
// Author:
|
|
// Atsushi Enomoto (atsushi@ximian.com)
|
|
//
|
|
// (C) 2004 Novell Inc.
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
//
|
|
// This serves the implementation part of XmlNodeReader except for
|
|
// ResolveEntity().
|
|
//
|
|
|
|
using System;
|
|
#if NET_2_0
|
|
using System.Collections.Generic;
|
|
#endif
|
|
using System.Xml;
|
|
using System.Text;
|
|
using Mono.Xml;
|
|
#if NET_2_0
|
|
using System.Xml.Schema;
|
|
#endif
|
|
|
|
namespace System.Xml
|
|
{
|
|
#if NET_2_0
|
|
internal class XmlNodeReaderImpl : XmlReader, IHasXmlParserContext, IXmlNamespaceResolver
|
|
#else
|
|
internal class XmlNodeReaderImpl : XmlReader, IHasXmlParserContext
|
|
#endif
|
|
{
|
|
XmlDocument document;
|
|
XmlNode startNode;
|
|
XmlNode current;
|
|
XmlNode ownerLinkedNode;
|
|
ReadState state = ReadState.Initial;
|
|
int depth;
|
|
bool isEndElement;
|
|
bool ignoreStartNode;
|
|
|
|
#region Constructor
|
|
|
|
internal XmlNodeReaderImpl (XmlNodeReaderImpl entityContainer)
|
|
: this (entityContainer.current)
|
|
{
|
|
}
|
|
|
|
public XmlNodeReaderImpl (XmlNode node)
|
|
{
|
|
startNode = node;
|
|
depth = 0;
|
|
document = startNode.NodeType == XmlNodeType.Document ?
|
|
startNode as XmlDocument : startNode.OwnerDocument;
|
|
|
|
switch (node.NodeType) {
|
|
case XmlNodeType.Document:
|
|
case XmlNodeType.DocumentFragment:
|
|
case XmlNodeType.EntityReference:
|
|
ignoreStartNode = true;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public override int AttributeCount {
|
|
get {
|
|
if (state != ReadState.Interactive)
|
|
return 0;
|
|
|
|
if (isEndElement || current == null)
|
|
return 0;
|
|
XmlNode n = ownerLinkedNode;
|
|
return n.Attributes != null ? n.Attributes.Count : 0;
|
|
}
|
|
}
|
|
|
|
public override string BaseURI {
|
|
get {
|
|
if (current == null)
|
|
return startNode.BaseURI;
|
|
return current.BaseURI;
|
|
}
|
|
}
|
|
|
|
#if NET_2_0
|
|
public override bool CanReadBinaryContent {
|
|
get { return true; }
|
|
}
|
|
|
|
public override bool CanReadValueChunk {
|
|
get { return true; }
|
|
}
|
|
#else
|
|
internal override bool CanReadBinaryContent {
|
|
get { return true; }
|
|
}
|
|
|
|
internal override bool CanReadValueChunk {
|
|
get { return true; }
|
|
}
|
|
#endif
|
|
|
|
public override bool CanResolveEntity {
|
|
get { return false; }
|
|
}
|
|
|
|
public override int Depth {
|
|
get {
|
|
return current == null ? 0 :
|
|
current == ownerLinkedNode ? depth :
|
|
current.NodeType == XmlNodeType.Attribute ? depth + 1 :
|
|
depth + 2;
|
|
}
|
|
}
|
|
|
|
public override bool EOF {
|
|
get { return state == ReadState.EndOfFile || state == ReadState.Error; }
|
|
}
|
|
|
|
public override bool HasAttributes {
|
|
get {
|
|
if (isEndElement || current == null)
|
|
return false;
|
|
|
|
// MS BUG: inconsistent return value between XmlTextReader and XmlNodeReader.
|
|
// As for attribute and its descendants, XmlReader returns element's HasAttributes.
|
|
XmlNode n = ownerLinkedNode;
|
|
|
|
if (n.Attributes == null ||
|
|
n.Attributes.Count == 0)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override bool HasValue {
|
|
get {
|
|
if (current == null)
|
|
return false;
|
|
|
|
switch (current.NodeType) {
|
|
case XmlNodeType.Element:
|
|
case XmlNodeType.EntityReference:
|
|
case XmlNodeType.Document:
|
|
case XmlNodeType.DocumentFragment:
|
|
case XmlNodeType.Notation:
|
|
case XmlNodeType.EndElement:
|
|
case XmlNodeType.EndEntity:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public override bool IsDefault {
|
|
get {
|
|
if (current == null)
|
|
return false;
|
|
|
|
if (current.NodeType != XmlNodeType.Attribute)
|
|
return false;
|
|
else
|
|
{
|
|
return !((XmlAttribute) current).Specified;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool IsEmptyElement {
|
|
get {
|
|
if (current == null)
|
|
return false;
|
|
|
|
if(current.NodeType == XmlNodeType.Element)
|
|
return ((XmlElement) current).IsEmpty;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#if NET_2_0
|
|
#else
|
|
public override string this [int i] {
|
|
get { return GetAttribute (i); }
|
|
}
|
|
|
|
public override string this [string name] {
|
|
get { return GetAttribute (name); }
|
|
}
|
|
|
|
public override string this [string name, string namespaceURI] {
|
|
get { return GetAttribute (name, namespaceURI); }
|
|
}
|
|
#endif
|
|
|
|
public override string LocalName {
|
|
get {
|
|
if (current == null)
|
|
return String.Empty;
|
|
|
|
switch (current.NodeType) {
|
|
case XmlNodeType.Attribute:
|
|
case XmlNodeType.DocumentType:
|
|
case XmlNodeType.Element:
|
|
case XmlNodeType.EntityReference:
|
|
case XmlNodeType.ProcessingInstruction:
|
|
case XmlNodeType.XmlDeclaration:
|
|
return current.LocalName;
|
|
}
|
|
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
public override string Name {
|
|
get {
|
|
if (current == null)
|
|
return String.Empty;
|
|
|
|
switch (current.NodeType) {
|
|
case XmlNodeType.Attribute:
|
|
case XmlNodeType.DocumentType:
|
|
case XmlNodeType.Element:
|
|
case XmlNodeType.EntityReference:
|
|
case XmlNodeType.ProcessingInstruction:
|
|
case XmlNodeType.XmlDeclaration:
|
|
return current.Name;
|
|
}
|
|
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
public override string NamespaceURI {
|
|
get {
|
|
if (current == null)
|
|
return String.Empty;
|
|
|
|
return current.NamespaceURI;
|
|
}
|
|
}
|
|
|
|
public override XmlNameTable NameTable {
|
|
get { return document.NameTable; }
|
|
}
|
|
|
|
public override XmlNodeType NodeType {
|
|
get {
|
|
if (current == null)
|
|
return XmlNodeType.None;
|
|
|
|
return isEndElement ? XmlNodeType.EndElement : current.NodeType;
|
|
}
|
|
}
|
|
|
|
public override string Prefix {
|
|
get {
|
|
if (current == null)
|
|
return String.Empty;
|
|
|
|
return current.Prefix;
|
|
}
|
|
}
|
|
|
|
#if NET_2_0
|
|
#else
|
|
public override char QuoteChar {
|
|
get {
|
|
return '"';
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public override ReadState ReadState {
|
|
get { return state; }
|
|
}
|
|
|
|
#if NET_2_0
|
|
public override IXmlSchemaInfo SchemaInfo {
|
|
get { return current != null ? current.SchemaInfo : null; }
|
|
}
|
|
#endif
|
|
|
|
public override string Value {
|
|
get {
|
|
if (NodeType == XmlNodeType.DocumentType)
|
|
return ((XmlDocumentType) current).InternalSubset;
|
|
else
|
|
return HasValue ? current.Value : String.Empty;
|
|
}
|
|
}
|
|
|
|
public override string XmlLang {
|
|
get {
|
|
if (current == null)
|
|
return startNode.XmlLang;
|
|
|
|
return current.XmlLang;
|
|
}
|
|
}
|
|
|
|
public override XmlSpace XmlSpace {
|
|
get {
|
|
if (current == null)
|
|
return startNode.XmlSpace;
|
|
|
|
return current.XmlSpace;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public override void Close ()
|
|
{
|
|
current = null;
|
|
state = ReadState.Closed;
|
|
}
|
|
|
|
public override string GetAttribute (int attributeIndex)
|
|
{
|
|
if (NodeType == XmlNodeType.XmlDeclaration) {
|
|
XmlDeclaration decl = current as XmlDeclaration;
|
|
if (attributeIndex == 0)
|
|
return decl.Version;
|
|
else if (attributeIndex == 1) {
|
|
if (decl.Encoding != String.Empty)
|
|
return decl.Encoding;
|
|
else if (decl.Standalone != String.Empty)
|
|
return decl.Standalone;
|
|
}
|
|
else if (attributeIndex == 2 &&
|
|
decl.Encoding != String.Empty && decl.Standalone != null)
|
|
return decl.Standalone;
|
|
throw new ArgumentOutOfRangeException ("Index out of range.");
|
|
} else if (NodeType == XmlNodeType.DocumentType) {
|
|
XmlDocumentType doctype = current as XmlDocumentType;
|
|
if (attributeIndex == 0) {
|
|
if (doctype.PublicId != "")
|
|
return doctype.PublicId;
|
|
else if (doctype.SystemId != "")
|
|
return doctype.SystemId;
|
|
} else if (attributeIndex == 1)
|
|
if (doctype.PublicId == "" && doctype.SystemId != "")
|
|
return doctype.SystemId;
|
|
throw new ArgumentOutOfRangeException ("Index out of range.");
|
|
}
|
|
|
|
// This is MS.NET bug which returns attributes in spite of EndElement.
|
|
if (isEndElement || current == null)
|
|
return null;
|
|
|
|
if (attributeIndex < 0 || attributeIndex > AttributeCount)
|
|
throw new ArgumentOutOfRangeException ("Index out of range.");
|
|
|
|
return ownerLinkedNode.Attributes [attributeIndex].Value;
|
|
}
|
|
|
|
public override string GetAttribute (string name)
|
|
{
|
|
// This is MS.NET bug which returns attributes in spite of EndElement.
|
|
if (isEndElement || current == null)
|
|
return null;
|
|
|
|
if (NodeType == XmlNodeType.XmlDeclaration)
|
|
return GetXmlDeclarationAttribute (name);
|
|
else if (NodeType == XmlNodeType.DocumentType)
|
|
return GetDocumentTypeAttribute (name);
|
|
|
|
if (ownerLinkedNode.Attributes == null)
|
|
return null;
|
|
XmlAttribute attr = ownerLinkedNode.Attributes [name];
|
|
if (attr == null)
|
|
return null;
|
|
else
|
|
return attr.Value;
|
|
}
|
|
|
|
public override string GetAttribute (string name, string namespaceURI)
|
|
{
|
|
// This is MS.NET bug which returns attributes in spite of EndElement.
|
|
if (isEndElement || current == null)
|
|
return null;
|
|
|
|
if (NodeType == XmlNodeType.XmlDeclaration)
|
|
return GetXmlDeclarationAttribute (name);
|
|
else if (NodeType == XmlNodeType.DocumentType)
|
|
return GetDocumentTypeAttribute (name);
|
|
|
|
if (ownerLinkedNode.Attributes == null)
|
|
return null;
|
|
XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
|
|
if (attr == null)
|
|
return null; // In fact MS.NET returns null instead of String.Empty.
|
|
else
|
|
return attr.Value;
|
|
}
|
|
|
|
private string GetXmlDeclarationAttribute (string name)
|
|
{
|
|
XmlDeclaration decl = current as XmlDeclaration;
|
|
switch (name) {
|
|
case "version":
|
|
return decl.Version;
|
|
case "encoding":
|
|
// This is MS.NET bug that XmlNodeReturns in case of string.empty.
|
|
return decl.Encoding != String.Empty ? decl.Encoding : null;
|
|
case "standalone":
|
|
return decl.Standalone;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private string GetDocumentTypeAttribute (string name)
|
|
{
|
|
XmlDocumentType doctype = current as XmlDocumentType;
|
|
switch (name) {
|
|
case "PUBLIC":
|
|
return doctype.PublicId;
|
|
case "SYSTEM":
|
|
return doctype.SystemId;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
XmlParserContext IHasXmlParserContext.ParserContext {
|
|
get {
|
|
return new XmlParserContext (document.NameTable,
|
|
current == null ?
|
|
new XmlNamespaceManager (document.NameTable) :
|
|
current.ConstructNamespaceManager (),
|
|
document.DocumentType != null ? document.DocumentType.DTD : null,
|
|
current == null ? document.BaseURI : current.BaseURI,
|
|
XmlLang, XmlSpace, Encoding.Unicode);
|
|
}
|
|
}
|
|
|
|
#if NET_2_0
|
|
public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
|
|
{
|
|
IDictionary<string, string> table = new Dictionary<string, string> ();
|
|
XmlNode n = current ?? startNode;
|
|
do {
|
|
if (n.NodeType == XmlNodeType.Document)
|
|
break;
|
|
for (int i = 0; i < n.Attributes.Count; i++) {
|
|
XmlAttribute a = n.Attributes [i];
|
|
if (a.NamespaceURI == XmlNamespaceManager.XmlnsXmlns) {
|
|
string key = a.Prefix == XmlNamespaceManager.PrefixXmlns ? a.LocalName : String.Empty;
|
|
if (!table.ContainsKey (key))
|
|
table.Add (key, a.Value);
|
|
}
|
|
}
|
|
if (scope == XmlNamespaceScope.Local)
|
|
return table;
|
|
n = n.ParentNode;
|
|
} while (n != null);
|
|
if (scope == XmlNamespaceScope.All)
|
|
table.Add (XmlNamespaceManager.PrefixXml, XmlNamespaceManager.XmlnsXml);
|
|
return table;
|
|
}
|
|
#endif
|
|
|
|
private XmlElement GetCurrentElement ()
|
|
{
|
|
XmlElement el = null;
|
|
switch (current.NodeType) {
|
|
case XmlNodeType.Attribute:
|
|
el = ((XmlAttribute) current).OwnerElement;
|
|
break;
|
|
case XmlNodeType.Element:
|
|
el = (XmlElement) current;
|
|
break;
|
|
case XmlNodeType.Text:
|
|
case XmlNodeType.CDATA:
|
|
case XmlNodeType.EntityReference:
|
|
case XmlNodeType.Comment:
|
|
case XmlNodeType.SignificantWhitespace:
|
|
case XmlNodeType.Whitespace:
|
|
case XmlNodeType.ProcessingInstruction:
|
|
el = current.ParentNode as XmlElement;
|
|
break;
|
|
}
|
|
return el;
|
|
}
|
|
|
|
public override string LookupNamespace (string prefix)
|
|
{
|
|
if (current == null)
|
|
return null;
|
|
|
|
XmlElement el = GetCurrentElement ();
|
|
|
|
for (; el != null; el = el.ParentNode as XmlElement) {
|
|
for (int i = 0; i < el.Attributes.Count; i++) {
|
|
XmlAttribute attr = el.Attributes [i];
|
|
if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
|
|
continue;
|
|
if (prefix == "") {
|
|
if (attr.Prefix == "")
|
|
return attr.Value;
|
|
}
|
|
else if (attr.LocalName == prefix)
|
|
return attr.Value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (prefix) {
|
|
case XmlNamespaceManager.PrefixXml:
|
|
return XmlNamespaceManager.XmlnsXml;
|
|
case XmlNamespaceManager.PrefixXmlns:
|
|
return XmlNamespaceManager.XmlnsXmlns;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
#if NET_2_0
|
|
public string LookupPrefix (string ns)
|
|
{
|
|
return LookupPrefix (ns, false);
|
|
}
|
|
|
|
public string LookupPrefix (string ns, bool atomizedNames)
|
|
{
|
|
if (current == null)
|
|
return null;
|
|
|
|
XmlElement el = GetCurrentElement ();
|
|
|
|
for (; el != null; el = el.ParentNode as XmlElement) {
|
|
for (int i = 0; i < el.Attributes.Count; i++) {
|
|
XmlAttribute attr = el.Attributes [i];
|
|
if (atomizedNames) {
|
|
if (!Object.ReferenceEquals (attr.NamespaceURI, XmlNamespaceManager.XmlnsXmlns))
|
|
continue;
|
|
if (Object.ReferenceEquals (attr.Value, ns))
|
|
// xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
|
|
return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
|
|
} else {
|
|
if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
|
|
continue;
|
|
if (attr.Value == ns)
|
|
// xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
|
|
return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
|
|
}
|
|
}
|
|
}
|
|
switch (ns) {
|
|
case XmlNamespaceManager.XmlnsXml:
|
|
return XmlNamespaceManager.PrefixXml;
|
|
case XmlNamespaceManager.XmlnsXmlns:
|
|
return XmlNamespaceManager.PrefixXmlns;
|
|
}
|
|
return null;
|
|
}
|
|
#endif
|
|
|
|
public override void MoveToAttribute (int attributeIndex)
|
|
{
|
|
if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
|
|
throw new ArgumentOutOfRangeException ();
|
|
|
|
state = ReadState.Interactive;
|
|
current = ownerLinkedNode.Attributes [attributeIndex];
|
|
}
|
|
|
|
public override bool MoveToAttribute (string name)
|
|
{
|
|
if (isEndElement || current == null)
|
|
return false;
|
|
XmlNode tmpCurrent = current;
|
|
if (current.ParentNode.NodeType == XmlNodeType.Attribute)
|
|
current = current.ParentNode;
|
|
|
|
if (ownerLinkedNode.Attributes == null)
|
|
return false;
|
|
XmlAttribute attr = ownerLinkedNode.Attributes [name];
|
|
if (attr == null) {
|
|
current = tmpCurrent;
|
|
return false;
|
|
}
|
|
else {
|
|
current = attr;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override bool MoveToAttribute (string name, string namespaceURI)
|
|
{
|
|
if (isEndElement || current == null)
|
|
return false;
|
|
|
|
if (ownerLinkedNode.Attributes == null)
|
|
return false;
|
|
XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
|
|
if (attr == null)
|
|
return false;
|
|
else {
|
|
current = attr;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override bool MoveToElement ()
|
|
{
|
|
if (current == null)
|
|
return false;
|
|
XmlNode n = ownerLinkedNode;
|
|
if (current != n) {
|
|
current = n;
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
public override bool MoveToFirstAttribute ()
|
|
{
|
|
if (current == null)
|
|
return false;
|
|
|
|
if (ownerLinkedNode.Attributes == null)
|
|
return false;
|
|
if(ownerLinkedNode.Attributes.Count > 0)
|
|
{
|
|
current = ownerLinkedNode.Attributes [0];
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
public override bool MoveToNextAttribute ()
|
|
{
|
|
if (current == null)
|
|
return false;
|
|
|
|
XmlNode anode = current;
|
|
if (current.NodeType != XmlNodeType.Attribute) {
|
|
// then it's either an attribute child or anything on the tree.
|
|
if (current.ParentNode == null || // document, or non-tree node
|
|
current.ParentNode.NodeType != XmlNodeType.Attribute) // not an attr value
|
|
return MoveToFirstAttribute ();
|
|
anode = current.ParentNode;
|
|
}
|
|
|
|
{
|
|
XmlAttributeCollection ac = ((XmlAttribute) anode).OwnerElement.Attributes;
|
|
for (int i=0; i<ac.Count-1; i++)
|
|
{
|
|
XmlAttribute attr = ac [i];
|
|
if (attr == anode)
|
|
{
|
|
i++;
|
|
if (i == ac.Count)
|
|
return false;
|
|
current = ac [i];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override bool Read ()
|
|
{
|
|
// FIXME: at some stage inlining might work effectively.
|
|
// if (EOF)
|
|
switch (state) {
|
|
case ReadState.EndOfFile:
|
|
case ReadState.Error:
|
|
case ReadState.Closed:
|
|
return false;
|
|
}
|
|
|
|
#if NET_2_0
|
|
if (Binary != null)
|
|
Binary.Reset ();
|
|
#endif
|
|
|
|
bool ret = ReadContent ();
|
|
ownerLinkedNode = current;
|
|
return ret;
|
|
}
|
|
|
|
bool ReadContent ()
|
|
{
|
|
if (ReadState == ReadState.Initial) {
|
|
current = startNode;
|
|
state = ReadState.Interactive;
|
|
// when startNode is document or fragment
|
|
if (ignoreStartNode)
|
|
current = startNode.FirstChild;
|
|
if (current == null) {
|
|
state = ReadState.Error;
|
|
return false;
|
|
} else
|
|
return true;
|
|
}
|
|
|
|
MoveToElement ();
|
|
|
|
// don't step into EntityReference's children. Also
|
|
// avoid re-entering children of already-consumed
|
|
// element (i.e. when it is regarded as EndElement).
|
|
XmlNode firstChild =
|
|
!isEndElement && current.NodeType != XmlNodeType.EntityReference ?
|
|
current.FirstChild : null;
|
|
if (firstChild != null) {
|
|
isEndElement = false;
|
|
current = firstChild;
|
|
depth++;
|
|
return true;
|
|
}
|
|
|
|
if (current == startNode) { // Currently it is on the start node.
|
|
if (IsEmptyElement || isEndElement) {
|
|
// The start node is already consumed.
|
|
isEndElement = false;
|
|
current = null;
|
|
state = ReadState.EndOfFile;
|
|
return false;
|
|
} else {
|
|
// The start node is the only element
|
|
// which should be processed. Now it
|
|
// is set as EndElement.
|
|
isEndElement = true;
|
|
return true;
|
|
}
|
|
}
|
|
if (!isEndElement && !IsEmptyElement &&
|
|
current.NodeType == XmlNodeType.Element) {
|
|
// element, currently not EndElement, and has
|
|
// no child. (such as <foo></foo>, which
|
|
// should become EndElement).
|
|
isEndElement = true;
|
|
return true;
|
|
}
|
|
|
|
// If NextSibling is available, move to there.
|
|
XmlNode next = current.NextSibling;
|
|
if (next != null) {
|
|
isEndElement = false;
|
|
current = next;
|
|
return true;
|
|
}
|
|
|
|
// Otherwise, parent.
|
|
XmlNode parent = current.ParentNode;
|
|
if (parent == null || parent == startNode && ignoreStartNode) {
|
|
// Parent is not available, or reached to
|
|
// the start node. This reader never sets
|
|
// startNode as current if it was originally
|
|
// ignored (e.g. startNode is XmlDocument).
|
|
isEndElement = false;
|
|
current = null;
|
|
state = ReadState.EndOfFile;
|
|
return false;
|
|
} else {
|
|
// Parent was available, so return it as
|
|
// EndElement.
|
|
current = parent;
|
|
depth--;
|
|
isEndElement = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override bool ReadAttributeValue ()
|
|
{
|
|
if (current.NodeType == XmlNodeType.Attribute) {
|
|
if (current.FirstChild == null)
|
|
return false;
|
|
current = current.FirstChild;
|
|
return true;
|
|
} else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
|
|
if (current.NextSibling == null)
|
|
return false;
|
|
current = current.NextSibling;
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
public override string ReadString ()
|
|
{
|
|
return base.ReadString ();
|
|
}
|
|
|
|
public override void ResolveEntity ()
|
|
{
|
|
throw new NotSupportedException ("Should not happen.");
|
|
}
|
|
|
|
public override void Skip ()
|
|
{
|
|
// Why is this overriden? Such skipping might raise
|
|
// (or ignore) unexpected validation error.
|
|
base.Skip ();
|
|
}
|
|
#endregion
|
|
}
|
|
}
|