Fixed MoveToParent issues with the navigator and attributes.
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader.cs
index fe0c5ae52fa9a7ea10d2991276b899883a3b96db..91611af2ee9d2ac6254437660226abf26b9ee56b 100644 (file)
@@ -1,8 +1,9 @@
 //
-// XmlTextReader.cs
+// System.Xml.XmlTextReader
 //
 // Author:
 //   Jason Diamond (jason@injektilo.org)
+//   Adam Treat (manyoso@yahoo.com)
 //
 // (C) 2001, 2002 Jason Diamond  http://injektilo.org/
 //
 //   There's also no checking being done for either well-formedness
 //   or validity.
 //
-//   ParserContext and NameTables aren't being used yet.
+//   NameTables aren't being used everywhere yet.
 //
 //   Some thought needs to be given to performance. There's too many
 //   strings being allocated.
 //
-//   None of the MoveTo methods have been implemented yet.
+//   Some of the MoveTo methods haven't been implemented yet.
 //
 //   LineNumber and LinePosition aren't being tracked.
 //
@@ -48,18 +49,30 @@ namespace System.Xml
                [MonoTODO]
                public XmlTextReader (Stream input)
                {
-                       throw new NotImplementedException ();
+                       // We can share some code in the constructors (at least for this one and next 2)
+                       XmlNameTable nt = new NameTable ();
+                       XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
+                       parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
+                       Init ();
+                       reader = new StreamReader (input);
                }
 
                [MonoTODO]
                public XmlTextReader (string url)
                {
-                       throw new NotImplementedException ();
+                       XmlNameTable nt = new NameTable ();
+                       XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
+                       parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
+                       Init ();
+                       reader = new StreamReader(url);
                }
 
                [MonoTODO]
                public XmlTextReader (TextReader input)
                {
+                       XmlNameTable nt = new NameTable ();
+                       XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
+                       parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
                        Init ();
                        reader = input;
                }
@@ -121,7 +134,10 @@ namespace System.Xml
                [MonoTODO]
                public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
                {
-                       throw new NotImplementedException ();
+                       //Waiting for Validating reader for fragType rules.
+                       parserContext = context;
+                       Init ();
+                       reader = new StringReader(xmlFragment);
                }
 
                #endregion
@@ -230,7 +246,7 @@ namespace System.Xml
 
                public override XmlNameTable NameTable
                {
-                       get { return nameTable; }
+                       get { return parserContext.NameTable; }
                }
 
                public override XmlNodeType NodeType
@@ -331,7 +347,7 @@ namespace System.Xml
                                                        return attributes [thisName] as string;
                                        }
                                } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
-                                       return attributes[thisName] as string;
+                                       return attributes [thisName] as string;
                        }
 
                        return String.Empty;
@@ -346,12 +362,12 @@ namespace System.Xml
                [MonoTODO]
                bool IXmlLineInfo.HasLineInfo ()
                {
-                       throw new NotImplementedException ();
+                       return false;
                }
 
                public override string LookupNamespace (string prefix)
                {
-                       return namespaceManager.LookupNamespace (prefix);
+                       return parserContext.NamespaceManager.LookupNamespace (prefix);
                }
 
                [MonoTODO]
@@ -360,10 +376,39 @@ namespace System.Xml
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                public override bool MoveToAttribute (string name)
                {
-                       throw new NotImplementedException ();
+                       MoveToElement ();
+                       bool match = false;
+
+                       if (attributes == null)
+                               return false;
+
+                       if (orderedAttributesEnumerator == null) {
+                               SaveProperties ();
+                               orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
+                       }
+
+                       while (orderedAttributesEnumerator.MoveNext ()) {
+                               if(name == orderedAttributesEnumerator.Current as string) {
+                                       match = true;
+                                       break;
+                               }
+                       }
+
+                       if (match) {
+                                       
+                               string value = attributes [name] as string;
+                               SetProperties (
+                                       XmlNodeType.Attribute, // nodeType
+                                       name, // name
+                                       false, // isEmptyElement
+                                       value, // value
+                                       false // clearAttributes
+                               );
+                       }
+                       
+                       return match;
                }
 
                [MonoTODO]
@@ -372,22 +417,47 @@ namespace System.Xml
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                public override bool MoveToElement ()
                {
-                       throw new NotImplementedException ();
+                       if (orderedAttributesEnumerator != null) {
+                               orderedAttributesEnumerator = null;
+                               RestoreProperties ();
+                               return true;
+                       }
+
+                       return false;
                }
 
-               [MonoTODO]
                public override bool MoveToFirstAttribute ()
                {
-                       throw new NotImplementedException ();
+                       MoveToElement ();
+                       return MoveToNextAttribute ();
                }
 
-               [MonoTODO]
                public override bool MoveToNextAttribute ()
                {
-                       throw new NotImplementedException ();
+                       if (attributes == null)
+                               return false;
+
+                       if (orderedAttributesEnumerator == null) {
+                               SaveProperties ();
+                               orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
+                       }
+
+                       if (orderedAttributesEnumerator.MoveNext ()) {
+                               string name = orderedAttributesEnumerator.Current as string;
+                               string value = attributes [name] as string;
+                               SetProperties (
+                                       XmlNodeType.Attribute, // nodeType
+                                       name, // name
+                                       false, // isEmptyElement
+                                       value, // value
+                                       false // clearAttributes
+                               );
+                               return true;
+                       }
+
+                       return false;
                }
 
                public override bool Read ()
@@ -408,19 +478,19 @@ namespace System.Xml
                }
 
                [MonoTODO]
-               public int ReadBase64 (byte[] buffer, int offset, int length)
+               public int ReadBase64 (byte [] buffer, int offset, int length)
                {
                        throw new NotImplementedException ();
                }
 
                [MonoTODO]
-               public int ReadBinHex (byte[] buffer, int offset, int length)
+               public int ReadBinHex (byte [] buffer, int offset, int length)
                {
                        throw new NotImplementedException ();
                }
 
                [MonoTODO]
-               public int ReadChars (char[] buffer, int offset, int length)
+               public int ReadChars (char [] buffer, int offset, int length)
                {
                        throw new NotImplementedException ();
                }
@@ -428,13 +498,52 @@ namespace System.Xml
                [MonoTODO]
                public override string ReadInnerXml ()
                {
-                       throw new NotImplementedException ();
+                       // Still need a Well Formedness check.
+                       // Will wait for Validating reader ;-)
+                       if (NodeType == XmlNodeType.Attribute) {
+                               return Value;
+                       } else {
+                               saveToXmlBuffer = true;
+                               string startname = this.Name;
+                               string endname = string.Empty;
+                               readState = ReadState.Interactive;
+
+                               while (startname != endname) {
+                                       ReadContent ();
+                               endname = this.Name;
+                               }
+
+                               xmlBuffer.Replace(currentTag.ToString (), "");
+                               saveToXmlBuffer = false;
+                               string InnerXml = xmlBuffer.ToString ();
+                               xmlBuffer.Length = 0;
+                               return InnerXml;
+                       }
                }
 
                [MonoTODO]
                public override string ReadOuterXml ()
                {
-                       throw new NotImplementedException ();
+                       // Still need a Well Formedness check.
+                       // Will wait for Validating reader ;-)
+                       if (NodeType == XmlNodeType.Attribute) {
+                               return Name+"=\""+Value+"\"";
+                       } else {
+                               saveToXmlBuffer = true;
+                               xmlBuffer.Append(currentTag.ToString ());
+                               string startname = this.Name;
+                               string endname = string.Empty;
+                               readState = ReadState.Interactive;
+
+                               while (startname != endname) {
+                                       ReadContent ();
+                               endname = this.Name;
+                               }
+                               saveToXmlBuffer = false;
+                               string OuterXml = xmlBuffer.ToString ();
+                               xmlBuffer.Length = 0;
+                               return OuterXml;
+                       }
                }
 
                [MonoTODO]
@@ -459,14 +568,14 @@ namespace System.Xml
 
                // privates
 
+               private XmlParserContext parserContext;
+
                private TextReader reader;
                private ReadState readState;
 
                private int depth;
                private bool depthDown;
 
-               private XmlNameTable nameTable;
-               private XmlNamespaceManager namespaceManager;
                private bool popScope;
 
                private XmlNodeType nodeType;
@@ -476,52 +585,68 @@ namespace System.Xml
                private string namespaceURI;
                private bool isEmptyElement;
                private string value;
+
+               private XmlNodeType saveNodeType;
+               private string saveName;
+               private string savePrefix;
+               private string saveLocalName;
+               private string saveNamespaceURI;
+               private bool saveIsEmptyElement;
+
                private Hashtable attributes;
+               private ArrayList orderedAttributes;
+               private IEnumerator orderedAttributesEnumerator;
 
                private bool returnEntityReference;
                private string entityReferenceName;
 
-               private char[] nameBuffer;
+               private char [] nameBuffer;
                private int nameLength;
                private int nameCapacity;
                private const int initialNameCapacity = 256;
 
-               private char[] valueBuffer;
+               private char [] valueBuffer;
                private int valueLength;
                private int valueCapacity;
                private const int initialValueCapacity = 8192;
 
+               private StringBuilder xmlBuffer; // This is for Read(Inner|Outer)Xml
+               private StringBuilder currentTag; // A buffer for ReadContent for ReadOuterXml
+               private bool saveToXmlBuffer;
+
                private void Init ()
                {
-                       if (nameTable == null)
-                               nameTable = new NameTable ();
-
-                       namespaceManager = new XmlNamespaceManager (nameTable);
-                       popScope = false;
-
                        readState = ReadState.Initial;
 
                        depth = -1;
                        depthDown = false;
 
+                       popScope = false;
+
                        nodeType = XmlNodeType.None;
                        name = String.Empty;
                        prefix = String.Empty;
                        localName = string.Empty;
                        isEmptyElement = false;
                        value = String.Empty;
+
                        attributes = new Hashtable ();
-                       
+                       orderedAttributes = new ArrayList ();
+                       orderedAttributesEnumerator = null;
+
                        returnEntityReference = false;
                        entityReferenceName = String.Empty;
 
-                       nameBuffer = new char[initialNameCapacity];
+                       nameBuffer = new char [initialNameCapacity];
                        nameLength = 0;
                        nameCapacity = initialNameCapacity;
 
-                       valueBuffer = new char[initialValueCapacity];
+                       valueBuffer = new char [initialValueCapacity];
                        valueLength = 0;
                        valueCapacity = initialValueCapacity;
+
+                       xmlBuffer = new StringBuilder ();
+                       currentTag = new StringBuilder ();
                }
 
                // Use this method rather than setting the properties
@@ -557,15 +682,42 @@ namespace System.Xml
                        namespaceURI = LookupNamespace (prefix);
                }
 
+               private void SaveProperties ()
+               {
+                       saveNodeType = nodeType;
+                       saveName = name;
+                       savePrefix = prefix;
+                       saveLocalName = localName;
+                       saveNamespaceURI = namespaceURI;
+                       saveIsEmptyElement = isEmptyElement;
+                       // An element's value is always String.Empty.
+               }
+
+               private void RestoreProperties ()
+               {
+                       nodeType = saveNodeType;
+                       name = saveName;
+                       prefix = savePrefix;
+                       localName = saveLocalName;
+                       namespaceURI = saveNamespaceURI;
+                       isEmptyElement = saveIsEmptyElement;
+                       value = String.Empty;
+               }
+
                private void AddAttribute (string name, string value)
                {
                        attributes.Add (name, value);
+                       orderedAttributes.Add (name);
                }
 
                private void ClearAttributes ()
                {
-                       if (attributes.Count > 0)
+                       if (attributes.Count > 0) {
                                attributes.Clear ();
+                               orderedAttributes.Clear ();
+                       }
+
+                       orderedAttributesEnumerator = null;
                }
 
                private int PeekChar ()
@@ -575,7 +727,12 @@ namespace System.Xml
 
                private int ReadChar ()
                {
-                       return reader.Read ();
+                       int ch = reader.Read ();
+                       if (saveToXmlBuffer) {
+                               xmlBuffer.Append ((char) ch);
+                       }
+                       currentTag.Append ((char) ch);
+                       return ch;
                }
 
                // This should really keep track of some state so
@@ -584,9 +741,9 @@ namespace System.Xml
                private bool ReadContent ()
                {
                        bool more = false;
-
+                       currentTag.Length = 0;
                        if (popScope) {
-                               namespaceManager.PopScope ();
+                               parserContext.NamespaceManager.PopScope ();
                                popScope = false;
                        }
 
@@ -598,7 +755,7 @@ namespace System.Xml
                                SetEntityReferenceProperties ();
                                more = true;
                        } else {
-                               switch (PeekChar ())
+                       switch (PeekChar ())
                                {
                                case '<':
                                        ReadChar ();
@@ -666,7 +823,7 @@ namespace System.Xml
                // The leading '<' has already been consumed.
                private void ReadStartTag ()
                {
-                       namespaceManager.PushScope ();
+                       parserContext.NamespaceManager.PushScope ();
 
                        string name = ReadName ();
                        SkipWhitespace ();
@@ -722,15 +879,15 @@ namespace System.Xml
                private void AppendNameChar (int ch)
                {
                        CheckNameCapacity ();
-                       nameBuffer[nameLength++] = (char)ch;
+                       nameBuffer [nameLength++] = (char)ch;
                }
 
                private void CheckNameCapacity ()
                {
                        if (nameLength == nameCapacity) {
                                nameCapacity = nameCapacity * 2;
-                               char[] oldNameBuffer = nameBuffer;
-                               nameBuffer = new char[nameCapacity];
+                               char [] oldNameBuffer = nameBuffer;
+                               nameBuffer = new char [nameCapacity];
                                Array.Copy (oldNameBuffer, nameBuffer, nameLength);
                        }
                }
@@ -743,15 +900,15 @@ namespace System.Xml
                private void AppendValueChar (int ch)
                {
                        CheckValueCapacity ();
-                       valueBuffer[valueLength++] = (char)ch;
+                       valueBuffer [valueLength++] = (char)ch;
                }
 
                private void CheckValueCapacity ()
                {
                        if (valueLength == valueCapacity) {
                                valueCapacity = valueCapacity * 2;
-                               char[] oldValueBuffer = valueBuffer;
-                               valueBuffer = new char[valueCapacity];
+                               char [] oldValueBuffer = valueBuffer;
+                               valueBuffer = new char [valueCapacity];
                                Array.Copy (oldValueBuffer, valueBuffer, valueLength);
                        }
                }
@@ -920,9 +1077,9 @@ namespace System.Xml
                                SkipWhitespace ();
 
                                if (name == "xmlns")
-                                       namespaceManager.AddNamespace (String.Empty, value);
+                                       parserContext.NamespaceManager.AddNamespace (String.Empty, value);
                                else if (name.StartsWith ("xmlns:"))
-                                       namespaceManager.AddNamespace (name.Substring (6), value);
+                                       parserContext.NamespaceManager.AddNamespace (name.Substring (6), value);
 
                                AddAttribute (name, value);
                        } while (PeekChar () != '/' && PeekChar () != '>' && PeekChar () != -1);