Merge pull request #93 from konrad-kruczynski/dispatcher_timer_fix
[mono.git] / mcs / class / System.XML / System.Xml / XmlDocument.cs
index 85c102b101a44dd91601f9d36d5b5294b9bca6b6..6a9627da2b01927745171e1177a159d2024dcd32 100644 (file)
@@ -49,9 +49,11 @@ using Mono.Xml.XPath;
 
 namespace System.Xml
 {
-       public class XmlDocument : XmlNode
+       public class XmlDocument : XmlNode, IHasXmlChildNode
        {
                #region Fields
+               static readonly Type [] optimal_create_types = new Type [] {typeof (string), typeof (string), typeof (string)};
+               bool optimal_create_element, optimal_create_attribute;
 
                XmlNameTable nameTable;
                string baseURI = String.Empty;
@@ -60,6 +62,8 @@ namespace System.Xml
                XmlResolver resolver;
                Hashtable idTable = new Hashtable ();
                XmlNameEntryCache nameCache;
+               XmlLinkedNode lastLinkedChild;
+               XmlAttribute nsNodeXml;
 #if NET_2_0
                XmlSchemaSet schemas;
                IXmlSchemaInfo schemaInfo;
@@ -98,6 +102,10 @@ namespace System.Xml
                        nameCache = new XmlNameEntryCache (nameTable);
                        AddDefaultNameTableKeys ();
                        resolver = new XmlUrlResolver ();
+                       
+                       Type type = GetType ();
+                       optimal_create_element = type.GetMethod ("CreateElement", optimal_create_types).DeclaringType == typeof (XmlDocument);
+                       optimal_create_attribute = type.GetMethod ("CreateAttribute", optimal_create_types).DeclaringType == typeof (XmlDocument);
                }
                #endregion
 
@@ -119,6 +127,21 @@ namespace System.Xml
 
                #region Properties
 
+               internal XmlAttribute NsNodeXml {
+                       get {
+                               if (nsNodeXml == null) {
+                                       nsNodeXml = CreateAttribute ("xmlns", "xml", "http://www.w3.org/2000/xmlns/");
+                                       nsNodeXml.Value = "http://www.w3.org/XML/1998/namespace";
+                               }
+                               return nsNodeXml;
+                       }
+               }
+
+               XmlLinkedNode IHasXmlChildNode.LastLinkedChild {
+                       get { return lastLinkedChild; }
+                       set { lastLinkedChild = value; }
+               }
+
                public override string BaseURI {
                        get {
                                return baseURI;
@@ -141,9 +164,12 @@ namespace System.Xml
 
                public virtual XmlDocumentType DocumentType {
                        get {
-                               for (XmlNode n = FirstChild; n != null; n = n.NextSibling)
-                                       if(n.NodeType == XmlNodeType.DocumentType)
-                                               return (XmlDocumentType)n;
+                               for (XmlNode n = FirstChild; n != null; n = n.NextSibling) {
+                                       if (n.NodeType == XmlNodeType.DocumentType)
+                                               return (XmlDocumentType) n;
+                                       else if (n.NodeType == XmlNodeType.Element) // document element
+                                               return null;
+                               }
 
                                return null;
                        }
@@ -153,6 +179,12 @@ namespace System.Xml
                        get { return implementation; }
                }
 
+#if NET_4_0
+               public override string InnerText {
+                       set { throw new InvalidOperationException (); }
+               }
+#endif
+
                public override string InnerXml {
                        get {
                                return base.InnerXml;
@@ -244,7 +276,11 @@ namespace System.Xml
                }
 
                public XmlSchemaSet Schemas {
-                       get { return schemas; }
+                       get {
+                               if (schemas == null)
+                                       schemas = new XmlSchemaSet ();
+                               return schemas;
+                       }
                        set { schemas = value; }
                }
 
@@ -303,15 +339,18 @@ namespace System.Xml
 
                public virtual XmlAttribute CreateAttribute (string prefix, string localName, string namespaceURI)
                {
-                       return CreateAttribute (prefix, localName, namespaceURI, false, true);
+                       if ((localName == null) || (localName == String.Empty))
+                               throw new ArgumentException ("The attribute local name cannot be empty.");
+
+                       return new XmlAttribute (prefix, localName, namespaceURI, this, false, true);
                }
 
                internal XmlAttribute CreateAttribute (string prefix, string localName, string namespaceURI, bool atomizedNames, bool checkNamespace)
                {
-                       if ((localName == null) || (localName == String.Empty))
-                               throw new ArgumentException ("The attribute local name cannot be empty.");
-
-                       return new XmlAttribute (prefix, localName, namespaceURI, this, atomizedNames, checkNamespace);
+                       if (optimal_create_attribute)
+                               return new XmlAttribute (prefix, localName, namespaceURI, this, atomizedNames, checkNamespace);
+                       else
+                               return CreateAttribute (prefix, localName, namespaceURI);
                }
 
                public virtual XmlCDataSection CreateCDataSection (string data)
@@ -370,14 +409,29 @@ namespace System.Xml
                        string localName,
                        string namespaceURI)
                {
-                       if ((localName == null) || (localName == String.Empty))
-                               throw new ArgumentException ("The local name for elements or attributes cannot be null or an empty string.");
                        // LAMESPEC: MS.NET has a weird behavior that they can Load() from XmlTextReader 
                        // whose Namespaces = false, but their CreateElement() never allows qualified name.
                        // I leave it as it is.
                        return new XmlElement (prefix != null ? prefix : String.Empty, localName, namespaceURI != null ? namespaceURI : String.Empty, this, false);
                }
 
+               internal XmlElement CreateElement (
+                       string prefix,
+                       string localName,
+                       string namespaceURI,
+                       bool nameAtomized)
+               {
+                       if ((localName == null) || (localName == String.Empty))
+                               throw new ArgumentException ("The local name for elements or attributes cannot be null or an empty string.");
+                       if (optimal_create_element)
+                               // LAMESPEC: MS.NET has a weird behavior that they can Load() from XmlTextReader 
+                               // whose Namespaces = false, but their CreateElement() never allows qualified name.
+                               // I leave it as it is.
+                               return new XmlElement (prefix != null ? prefix : String.Empty, localName, namespaceURI != null ? namespaceURI : String.Empty, this, nameAtomized);
+                       else
+                               return CreateElement (prefix, localName, namespaceURI);
+               }
+
                public virtual XmlEntityReference CreateEntityReference (string name)
                {
                        return new XmlEntityReference (name, this);
@@ -584,7 +638,7 @@ namespace System.Xml
                                return df;
 
                        case XmlNodeType.DocumentType:
-                               throw new XmlException ("DocumentType cannot be imported.");
+                               return ((XmlDocumentType) node).CloneNode (deep);
 
                        case XmlNodeType.Element:
                                XmlElement src = (XmlElement)node;
@@ -636,7 +690,10 @@ namespace System.Xml
                {
                        XmlTextReader reader = new XmlTextReader (inStream, NameTable);
                        reader.XmlResolver = resolver;
-                       Load (reader);
+                       XmlValidatingReader vr = new XmlValidatingReader (reader);
+                       vr.EntityHandling = EntityHandling.ExpandCharEntities;
+                       vr.ValidationType = ValidationType.None;
+                       Load (vr);
                }
 
                public virtual void Load (string filename)
@@ -645,7 +702,10 @@ namespace System.Xml
                        try {
                                xr = new XmlTextReader (filename, NameTable);
                                xr.XmlResolver = resolver;
-                               Load (xr);
+                               XmlValidatingReader vr = new XmlValidatingReader (xr);
+                               vr.EntityHandling = EntityHandling.ExpandCharEntities;
+                               vr.ValidationType = ValidationType.None;
+                               Load (vr);
                        } finally {
                                if (xr != null)
                                        xr.Close ();
@@ -655,8 +715,11 @@ namespace System.Xml
                public virtual void Load (TextReader txtReader)
                {
                        XmlTextReader xr = new XmlTextReader (txtReader, NameTable);
+                       XmlValidatingReader vr = new XmlValidatingReader (xr);
+                       vr.EntityHandling = EntityHandling.ExpandCharEntities;
+                       vr.ValidationType = ValidationType.None;
                        xr.XmlResolver = resolver;
-                       Load (xr);
+                       Load (vr);
                }
 
                public virtual void Load (XmlReader xmlReader)
@@ -677,7 +740,7 @@ namespace System.Xml
                                                break;
                                        if (preserveWhitespace || n.NodeType != XmlNodeType.Whitespace)
                                                AppendChild (n, false);
-                               } while (true);
+                               } while (xmlReader.NodeType != XmlNodeType.EndElement);
 #if NET_2_0
                                if (xmlReader.Settings != null)
                                        schemas = xmlReader.Settings.Schemas;
@@ -692,7 +755,7 @@ namespace System.Xml
                        XmlTextReader xmlReader = new XmlTextReader (
                                xml,
                                XmlNodeType.Document,
-                               new XmlParserContext (NameTable, null, null, XmlSpace.None));
+                               new XmlParserContext (NameTable, new XmlNamespaceManager (NameTable), null, XmlSpace.None));
                        try {
                                xmlReader.XmlResolver = resolver;
                                Load (xmlReader);
@@ -765,10 +828,10 @@ namespace System.Xml
                                reader.MoveToFirstAttribute ();
                        else if (reader.NodeType != XmlNodeType.Attribute)
                                throw new InvalidOperationException (MakeReaderErrorMessage ("bad position to read attribute.", reader));
-                       XmlAttribute attribute = CreateAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI, false, false); // different NameTable
+                       XmlAttribute attribute = CreateAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
 #if NET_2_0
                        if (reader.SchemaInfo != null)
-                               SchemaInfo = new XmlSchemaInfo (reader.SchemaInfo);
+                               SchemaInfo = reader.SchemaInfo;
 #endif
                        bool isDefault = reader.IsDefault;
 
@@ -794,6 +857,24 @@ namespace System.Xml
 
                [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
                public virtual XmlNode ReadNode (XmlReader reader)
+               {
+                       if (PreserveWhitespace)
+                               return ReadNodeCore (reader);
+                       XmlTextReader xtr = reader as XmlTextReader;
+                       if (xtr != null && xtr.WhitespaceHandling ==
+                           WhitespaceHandling.All) {
+                               try {
+                                       xtr.WhitespaceHandling = WhitespaceHandling.Significant;
+                                       return ReadNodeCore (reader);
+                               } finally {
+                                       xtr.WhitespaceHandling = WhitespaceHandling.All;
+                               }
+                       }
+                       else
+                               return ReadNodeCore (reader);
+               }
+
+               XmlNode ReadNodeCore (XmlReader reader)
                {
                        switch (reader.ReadState) {
                        case ReadState.Interactive:
@@ -801,7 +882,7 @@ namespace System.Xml
                        case ReadState.Initial:
 #if NET_2_0
                                if (reader.SchemaInfo != null)
-                                       this.SchemaInfo = new XmlSchemaInfo (reader.SchemaInfo);
+                                       SchemaInfo = reader.SchemaInfo;
 #endif
                                reader.Read ();
                                break;
@@ -829,31 +910,43 @@ namespace System.Xml
                                break;
 
                        case XmlNodeType.Element:
-                               XmlElement element = CreateElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
+                               XmlElement element = CreateElement (reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.NameTable == this.NameTable);
 #if NET_2_0
                                if (reader.SchemaInfo != null)
-                                       SchemaInfo = new XmlSchemaInfo (reader.SchemaInfo);
+                                       SchemaInfo = reader.SchemaInfo;
 #endif
                                element.IsEmpty = reader.IsEmptyElement;
 
                                // set the element's attributes.
+                               for (int i = 0; i < reader.AttributeCount; i++) {
+                                       reader.MoveToAttribute (i);
+                                       element.SetAttributeNode (
+                                               ReadAttributeNode (reader));
+                                       reader.MoveToElement ();
+                               }
+                               // FIXME: the code below should be fine and
+                               // in some XmlReaders it is much faster, but
+                               // caused some breakage in sys.data test.
+                               /*
                                if (reader.MoveToFirstAttribute ()) {
                                        do {
                                                element.SetAttributeNode (ReadAttributeNode (reader));
                                        } while (reader.MoveToNextAttribute ());
                                        reader.MoveToElement ();
                                }
+                               */
+                               reader.MoveToElement ();
 
                                int depth = reader.Depth;
 
-                               if (element.IsEmpty) {
+                               if (reader.IsEmptyElement) {
                                        n = element;
                                        break;
                                }
 
                                reader.Read ();
                                while (reader.Depth > depth) {
-                                       n = ReadNode (reader);
+                                       n = ReadNodeCore (reader);
                                        if (preserveWhitespace || n.NodeType != XmlNodeType.Whitespace)
                                                element.AppendChild (n, false);
                                }