2003-10-25 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlNodeReader.cs
index 7dc90f93009ea20b64d872ff0cfb275962b7cba2..23c6f1219a7d33b40a18a1a8421c3dbcbfbff66e 100755 (executable)
@@ -24,15 +24,21 @@ namespace System.Xml
                ReadState state = ReadState.Initial;
                int depth;
                bool isEndElement;
-               bool isEndEntity;
                bool nextIsEndElement;  // used for ReadString()
                bool alreadyRead;
                StringBuilder valueBuilder = new StringBuilder ();
                XmlNamespaceManager defaultNsmgr;
+               Stack entityReaderStack = new Stack ();
+               XmlTextReader entityReader;
 
                private XmlNode ownerElement {
                        get {
-                               return (current.NodeType == XmlNodeType.Attribute) ? ((XmlAttribute)current).OwnerElement : current;
+                               if (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute)
+                                       return ((XmlAttribute) current.ParentNode).OwnerElement;
+                               else if (current.NodeType == XmlNodeType.Attribute) 
+                                       return ((XmlAttribute) current).OwnerElement;
+                               else
+                                       return current;
                        }
                }
 
@@ -57,29 +63,48 @@ namespace System.Xml
 
                public override int AttributeCount {
                        get {
-                               if (isEndElement || current == null || current.Attributes == null)
+                               if (entityReader != null)
+                                       return entityReader.ReadState == ReadState.Interactive ?
+                                               entityReader.AttributeCount : 0;
+
+                               if (isEndElement || current == null)
                                        return 0;
-                               return ownerElement.Attributes.Count;
+                               XmlNode n = ownerElement;
+                               return n.Attributes != null ? n.Attributes.Count : 0;
                        }
                }
 
                public override string BaseURI {
-                       get { 
+                       get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.BaseURI;
+
                                if (current == null)
                                        return String.Empty;
                                return current.BaseURI;
                        }
                }
 
-               [MonoTODO("wait for XML resolver")]
                public override bool CanResolveEntity {
                        get {
-                               throw new NotImplementedException ();
+                               return true;
                        }
                }
 
                public override int Depth {
-                       get { return depth; }
+                       get {
+                               if (entityReader != null && entityReader.ReadState == ReadState.Interactive)
+                                       return entityReader.Depth + depth + entityReaderStack.Count + 1;
+
+                               if (current == null)
+                                       return 0;
+                               if (current.NodeType == XmlNodeType.Attribute)
+                                       return depth + 1;
+                               if (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute)
+                                       return depth + 2;
+
+                               return depth;
+                       }
                }
 
                public override bool EOF {
@@ -91,11 +116,19 @@ namespace System.Xml
 
                public override bool HasAttributes {
                        get {
+                               if (entityReader != null)
+                                       return entityReader.ReadState == ReadState.Interactive ?
+                                             entityReader.HasAttributes : false;
+
                                if (isEndElement || current == null)
                                        return false;
 
-                               if (current.Attributes == null ||
-                                       current.Attributes.Count == 0)
+                               // MS BUG: inconsistent return value between XmlTextReader and XmlNodeReader.
+                               // As for attribute and its descendants, XmlReader returns element's HasAttributes.
+                               XmlNode n = ownerElement;
+
+                               if (n.Attributes == null ||
+                                       n.Attributes.Count == 0)
                                        return false;
                                else
                                        return true;
@@ -104,26 +137,35 @@ namespace System.Xml
 
                public override bool HasValue {
                        get {
+                               if (entityReader != null)
+                                       return entityReader.ReadState == ReadState.Interactive ?
+                                               entityReader.IsDefault : false;
+
                                if (current == null)
                                        return false;
 
-                               if (current.NodeType == XmlNodeType.Element ||
-                                   current.NodeType == XmlNodeType.EntityReference ||
-                                   current.NodeType == XmlNodeType.Document ||
-                                   current.NodeType == XmlNodeType.DocumentFragment ||
-                                   current.NodeType == XmlNodeType.Notation ||
-                                   current.NodeType == XmlNodeType.EndElement ||
-                                   current.NodeType == XmlNodeType.EndEntity)
+                               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;
-                               else
+                               default:
                                        return true;
+                               }
                        }
                              
                }
 
-               [MonoTODO("waiting for DTD implementation")]
                public override bool IsDefault {
                        get {
+                               if (entityReader != null)
+                                       return entityReader.ReadState == ReadState.Interactive ?
+                                               entityReader.IsDefault : false;
+
                                if (current == null)
                                        return false;
 
@@ -138,6 +180,10 @@ namespace System.Xml
 
                public override bool IsEmptyElement {
                        get {
+                               if (entityReader != null)
+                                       return entityReader.ReadState == ReadState.Interactive ?
+                                               entityReader.IsDefault : false;
+
                                if (current == null)
                                        return false;
 
@@ -149,88 +195,22 @@ namespace System.Xml
                }
 
                public override string this [int i] {
-                       get {
-                               // This is MS.NET bug which returns attributes in spite of EndElement.
-                               if (isEndElement || current == null)
-                                       return null;
-
-                               if (NodeType == XmlNodeType.XmlDeclaration) {
-                                       XmlDeclaration decl = current as XmlDeclaration;
-                                       switch (i) {
-                                       case 0:
-                                               return decl.Version;
-                                       case 1:
-                                               if (decl.Encoding != String.Empty)
-                                                       return decl.Encoding;
-                                               else if (decl.Standalone != String.Empty)
-                                                       return decl.Standalone;
-                                               else
-                                                       throw new ArgumentOutOfRangeException ("Index out of range.");
-                                       case 2:
-                                               if (decl.Encoding != String.Empty && decl.Standalone != null)
-                                                       return decl.Standalone;
-                                               else
-                                                       throw new ArgumentOutOfRangeException ("Index out of range.");
-                                       }
-                               }
-
-                               if (i < 0 || i > AttributeCount)
-                                       throw new ArgumentOutOfRangeException ("Index out of range.");
-
-                               return ownerElement.Attributes [i].Value;
-                       }
-               }
-
-               private string GetXmlDeclarationAttribute (string name)
-               {
-                       XmlDeclaration decl = current as XmlDeclaration;
-                       switch (name) {
-                       case "version":
-                               return decl.Version;
-                       case "encoding":
-                               return decl.Encoding;
-                       case "standalone":
-                               return decl.Standalone;
-                       }
-                       return null;
+                       get { return GetAttribute (i); }
                }
 
                public override string this [string name] {
-                       get {
-                               // 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);
-
-                               XmlAttribute attr = ownerElement.Attributes [name];
-                               if (attr == null)
-                                       return null;
-                               else
-                                       return attr.Value;
-                       }
+                       get { return GetAttribute (name); }
                }
 
                public override string this [string name, string namespaceURI] {
-                       get {
-                               // 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);
-
-                               XmlAttribute attr = ownerElement.Attributes [name, namespaceURI];
-                               if (attr == null)
-                                       return null;    // In fact MS.NET returns null instead of String.Empty.
-                               else
-                                       return attr.Value;
-                       }
+                       get { return GetAttribute (name, namespaceURI); }
                }
 
                public override string LocalName {
                        get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.LocalName;
+
                                if (current == null)
                                        return String.Empty;
 
@@ -250,6 +230,9 @@ namespace System.Xml
 
                public override string Name {
                        get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.Name;
+
                                if (current == null)
                                        return String.Empty;
 
@@ -269,6 +252,9 @@ namespace System.Xml
 
                public override string NamespaceURI {
                        get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.NamespaceURI;
+
                                if (current == null)
                                        return String.Empty;
 
@@ -282,6 +268,16 @@ namespace System.Xml
 
                public override XmlNodeType NodeType {
                        get {
+                               if (entityReader != null)
+                                       switch (entityReader.ReadState) {
+                                       case ReadState.Interactive:
+                                               return entityReader.NodeType;
+                                       case ReadState.Initial:
+                                               return XmlNodeType.EntityReference;
+                                       case ReadState.EndOfFile:
+                                               return XmlNodeType.EndEntity;
+                                       }
+
                                if (current == null)
                                        return XmlNodeType.None;
 
@@ -291,15 +287,26 @@ namespace System.Xml
 
                public override string Prefix {
                        get { 
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.Prefix;
+
                                if (current == null)
                                        return String.Empty;
 
-                               return current.Prefix;
+//                             if (current.NodeType == XmlNodeType.Attribute)
+//                                     return current.Prefix != String.Empty ? current.Prefix : null;
+//                             else
+                                       return current.Prefix;
                        }
                }
 
                public override char QuoteChar {
-                       get { return '"'; }
+                       get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.QuoteChar;
+
+                               return '"';
+                       }
                }
 
                public override ReadState ReadState {
@@ -308,12 +315,21 @@ namespace System.Xml
 
                public override string Value {
                        get {
-                               return HasValue ? current.Value : String.Empty;
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.Value;
+
+                               if (NodeType == XmlNodeType.DocumentType)
+                                       return ((XmlDocumentType) current).InternalSubset;
+                               else
+                                       return HasValue ? current.Value : String.Empty;
                        }
                }
 
                public override string XmlLang {
                        get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.XmlLang;
+
                                if (current == null)
                                        return String.Empty;
 
@@ -323,6 +339,9 @@ namespace System.Xml
 
                public override XmlSpace XmlSpace {
                        get {
+                               if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                                       return entityReader.XmlSpace;
+
                                if (current == null)
                                        return XmlSpace.None;
 
@@ -333,29 +352,166 @@ namespace System.Xml
 
                #region Methods
 
+               // If current entityReference is a child of an attribute,
+               // then MoveToAttribute simply means that we no more need this entity reader.
+               // Otherwise, this invokation means that
+               // it is expected to move to resolved (maybe) element's attribute.
+               //
+               // This rule applies to many methods like MoveTo*Attribute().
+               private bool CheckAndResetEntityReaderOnMoveToAttribute ()
+               {
+                       if (entityReader == null)
+                               return false;
+
+                       if (current != null && current.ParentNode != null &&
+                               current.ParentNode.NodeType == XmlNodeType.Attribute) {
+                               entityReader.Close ();
+                               entityReader = entityReaderStack.Count > 0 ?
+                                       entityReaderStack.Pop () as XmlTextReader : null;
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
                public override void Close ()
                {
+                       if (entityReader != null)
+                               entityReader.Close ();
+                       while (entityReaderStack.Count > 0)
+                               ((XmlTextReader) entityReaderStack.Pop ()).Close ();
+
                        current = null;
                        state = ReadState.Closed;
                }
 
                public override string GetAttribute (int attributeIndex)
                {
-                       return this [attributeIndex];
+                       if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                               return entityReader.GetAttribute (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 ownerElement.Attributes [attributeIndex].Value;
                }
 
                public override string GetAttribute (string name)
                {
-                       return this [name];
+                       if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                               return entityReader.GetAttribute (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);
+
+                       XmlAttribute attr = ownerElement.Attributes [name];
+                       if (attr == null)
+                               return null;
+                       else
+                               return attr.Value;
                }
 
                public override string GetAttribute (string name, string namespaceURI)
                {
-                       return this [name, namespaceURI];
+                       if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                               return entityReader.GetAttribute (name, 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);
+
+                       XmlAttribute attr = ownerElement.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;
+               }
+
+               internal XmlParserContext GetInternalParserContext ()
+               {
+                       if (entityReader != null)
+                               return entityReader.GetInternalParserContext ();
+                       else
+                               return new XmlParserContext (document.NameTable,
+                                       current.ConstructNamespaceManager (),
+                                       document.DocumentType != null ? document.DocumentType.DTD : null,
+                                       current.BaseURI, XmlLang, XmlSpace, Encoding.Unicode);
                }
 
                public override string LookupNamespace (string prefix)
                {
+                       if (entityReader != null && entityReader.ReadState != ReadState.Initial)
+                               return entityReader.LookupNamespace (prefix);
+
                        if (current == null)
                                return null;
 
@@ -383,6 +539,14 @@ namespace System.Xml
 
                public override void MoveToAttribute (int attributeIndex)
                {
+                       if (entityReader != null) {
+                               if (!this.CheckAndResetEntityReaderOnMoveToAttribute ()) {
+                                       entityReader.MoveToAttribute (attributeIndex);
+                                       return;
+                               }
+                               // And in case of abondoning entityReader, go on...
+                       }
+
                        if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
                                throw new ArgumentOutOfRangeException ();
                        
@@ -392,6 +556,12 @@ namespace System.Xml
 
                public override bool MoveToAttribute (string name)
                {
+                       if (entityReader != null) {
+                               if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
+                                       return entityReader.MoveToAttribute (name);
+                               // And in case of abondoning entityReader, go on...
+                       }
+
                        if (isEndElement || current == null)
                                return false;
                        XmlNode tmpCurrent = current;
@@ -411,6 +581,12 @@ namespace System.Xml
 
                public override bool MoveToAttribute (string name, string namespaceURI)
                {
+                       if (entityReader != null) {
+                               if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
+                                       return entityReader.MoveToAttribute (name, namespaceURI);
+                               // And in case of abondoning entityReader, go on...
+                       }
+
                        if (isEndElement || current == null)
                                return false;
 
@@ -433,10 +609,18 @@ namespace System.Xml
 
                public override bool MoveToElement ()
                {
+                       if (entityReader != null) {
+                               if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
+                                       return entityReader.MoveToElement ();
+                               // And in case of abondoning entityReader, go on...
+                       }
+
                        if (current == null)
                                return false;
-                       if (current.NodeType == XmlNodeType.Attribute) {
-                               current = ((XmlAttribute) current).OwnerElement;
+                       XmlNode n = ownerElement;
+                       if (current != n) {
+//                     if (current.NodeType == XmlNodeType.Attribute) {
+                               current = n;//((XmlAttribute) current).OwnerElement;
                                return true;
                        } else 
                                return false;
@@ -444,6 +628,12 @@ namespace System.Xml
 
                public override bool MoveToFirstAttribute ()
                {
+                       if (entityReader != null) {
+                               if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
+                                       return entityReader.MoveToFirstAttribute ();
+                               // And in case of abondoning entityReader, go on...
+                       }
+
                        if (current == null)
                                return false;
 
@@ -458,6 +648,12 @@ namespace System.Xml
 
                public override bool MoveToNextAttribute ()
                {
+                       if (entityReader != null) {
+                               if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
+                                       return entityReader.MoveToNextAttribute ();
+                               // And in case of abondoning entityReader, go on...
+                       }
+
                        if (current == null)
                                return false;
 
@@ -506,12 +702,28 @@ namespace System.Xml
                                return true;
                }
 
-               [MonoTODO("Entity handling is not supported.")]
                public override bool Read ()
                {
                        if (EOF)
                                return false;
 
+                       this.CheckAndResetEntityReaderOnMoveToAttribute ();
+                       if (entityReader != null) {
+                               // Read finalizes entity reader.
+                               switch (entityReader.ReadState) {
+                               case ReadState.Interactive:
+                               case ReadState.Initial:
+                                       // If it is ended, then other properties/methods will take care.
+                                       entityReader.Read ();
+                                       return true;
+                               default:
+                                       entityReader = entityReaderStack.Count > 0 ?
+                                               entityReaderStack.Pop () as XmlTextReader : null;
+                                       return Read ();
+                               }
+                               // and go on ...
+                       }
+
                        if (ReadState == ReadState.Initial) {
                                current = startNode;
                                state = ReadState.Interactive;
@@ -528,7 +740,6 @@ namespace System.Xml
                        }
 
                        MoveToElement ();
-                       isEndEntity = false;
 
                        if (IsEmptyElement || isEndElement) {
                                // Then go up and move to next.
@@ -577,9 +788,25 @@ namespace System.Xml
 
                public override bool ReadAttributeValue ()
                {
+                       if (entityReader != null) {
+                               switch (entityReader.ReadState) {
+                               case ReadState.Interactive:
+                               case ReadState.Initial:
+                                       // If it is ended, then other properties/methods will take care.
+                                       return entityReader.ReadAttributeValue ();
+                               default:
+                                       entityReader = entityReaderStack.Count > 0 ?
+                                               entityReaderStack.Pop () as XmlTextReader : null;
+                                       // and go on ...
+                                       return ReadAttributeValue ();
+                               }
+                       }
+
                        if (current.NodeType == XmlNodeType.Attribute) {
+                               if (current.FirstChild == null)
+                                       return false;
                                current = current.FirstChild;
-                               return current != null;
+                               return true;
                        } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
                                if (current.NextSibling == null)
                                        return false;
@@ -589,14 +816,22 @@ namespace System.Xml
                                return false;
                }
 
+#if NET_1_0
                // Its traversal behavior is almost same as Read().
                public override string ReadInnerXml ()
                {
-                       if (this.state != ReadState.Interactive) {
-                               state = ReadState.Error;
-                               return String.Empty;
+                       if (entityReader != null) {
+                               if (entityReader.EOF) {
+                                       entityReader = entityReaderStack.Count > 0 ?
+                                               entityReaderStack.Pop () as XmlTextReader : null;
+                                       return ReadInnerXml ();
+                               } else
+                                       return entityReader.ReadInnerXml ();
                        }
 
+                       if (this.state != ReadState.Interactive)
+                               return String.Empty;
+
                        XmlNode initial = current;
                        // Almost copied from XmlTextReader.
                        switch (NodeType) {
@@ -627,19 +862,20 @@ namespace System.Xml
                        }
                }
 
-               [MonoTODO("Need to move to next content.")]
                // Its traversal behavior is almost same as Read().
                public override string ReadOuterXml ()
                {
+                       if (entityReader != null) {
+                               if (entityReader.EOF) {
+                                       entityReader = entityReaderStack.Count > 0 ?
+                                               entityReaderStack.Pop () as XmlTextReader : null;
+                                       return ReadOuterXml ();
+                               } else
+                                       return entityReader.ReadOuterXml ();
+                       }
+
                        if (NodeType == XmlNodeType.EndElement)
                                return String.Empty;
-/*
-                       if (current.NodeType != XmlNodeType.Attribute &&
-                           current.NodeType != XmlNodeType.Element)
-                               return String.Empty;
-                       else
-                               return current.OuterXml;
-*/
                        XmlNode initial = current;
 
                        switch (NodeType) {
@@ -658,21 +894,44 @@ namespace System.Xml
                                return String.Empty;
                        }
                }
+#endif
 
                public override string ReadString ()
                {
                        return ReadStringInternal ();
                }
 
-               [MonoTODO]
                public override void ResolveEntity ()
                {
-                       throw new NotImplementedException ();
-//                     if (current.NodeType != XmlNodeType.EntityReference)
-//                             throw new InvalidOperationException ("The current node is not an Entity Reference");
+                       if (NodeType != XmlNodeType.EntityReference)
+                               throw new InvalidOperationException ("The current node is not an Entity Reference");
+                       XmlEntity entity = document.DocumentType != null ?
+                               document.DocumentType.Entities.GetNamedItem (Name) as XmlEntity : null;
+
+                       // MS.NET seems simply ignoring undeclared entity reference ;-(
+                       string replacementText =
+                               (entity != null) ? entity.InnerText : String.Empty;
+
+                       XmlNodeType xmlReaderNodeType = 
+                               (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute) ?
+                               XmlNodeType.Attribute : XmlNodeType.Element;
+
+                       XmlParserContext ctx = null;
+                       if (entityReader != null) {
+                               entityReaderStack.Push (entityReader);
+                               ctx = entityReader.GetInternalParserContext ();
+                       }
+                       if (ctx == null) {
+                               ctx = new XmlParserContext (document.NameTable,
+                                       current.ConstructNamespaceManager (),
+                                       document.DocumentType != null ? document.DocumentType.DTD : null,
+                                       BaseURI, XmlLang, XmlSpace, Encoding.Unicode);
+                       }
+                       entityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ctx);
+                       entityReader.XmlResolver = document.Resolver;
+                       entityReader.SkipTextDeclaration ();
                }
 
-               [MonoTODO("test it.")]
                public override void Skip ()
                {
                        // Why is this overriden? Such skipping might raise