2003-01-21 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlDocument.cs
index f8b8c54977ac7c1eccacbfdc819aa931fadd57ea..e54a1ed4dcc9111d7104a74683a9c7453010063a 100644 (file)
@@ -173,7 +173,6 @@ namespace System.Xml
                        get { return null; }
                }
 
-               [MonoTODO("check its behavior")]
                public bool PreserveWhitespace {
                        get { return preserveWhitespace; }
                        set { preserveWhitespace = value; }
@@ -274,7 +273,7 @@ namespace System.Xml
                        string localName;
 
                        ParseName (qualifiedName, out prefix, out localName);
-
+                       
                        return CreateElement (prefix, localName, namespaceURI);
                }
 
@@ -285,7 +284,7 @@ namespace System.Xml
                {
                        if ((localName == null) || (localName == String.Empty))
                                throw new ArgumentException ("The local name for elements or attributes cannot be null or an empty string.");
-
+                       CheckName (localName);
                        return new XmlElement (prefix != null ? prefix : String.Empty, localName, namespaceURI != null ? namespaceURI : String.Empty, this);
                }
 
@@ -577,11 +576,12 @@ namespace System.Xml
                        // like properties we have, etc.
                        RemoveAll ();
 
-                       XmlNode currentNode = this;
-
-                       // This method of XmlNode is previously written here.
-                       // Then I(ginga) moved them to use this logic with XmlElement.
-                       this.ConstructDOM(xmlReader, currentNode);
+                       // create all contents with use of ReadNode()
+                       do {
+                               XmlNode n = ReadNode (xmlReader);
+                               if(n == null) break;
+                               AppendChild (n);
+                       } while (true);
                }
 
                public virtual void LoadXml (string xml)
@@ -651,15 +651,181 @@ namespace System.Xml
                        }
                }
 
-               [MonoTODO]
+               // Checks that Element's name is valid
+               private void CheckName (String name)
+               {
+                       // TODO: others validations?
+                       if (name.IndexOf (" ") >= 0)
+                               throw new XmlException ("The ' ' characted cannot be included in a name");
+               }
+
+               // Reads XmlReader and creates Attribute Node.
+               private XmlAttribute ReadAttributeNode(XmlReader reader)
+               {
+                       if(reader.NodeType == XmlNodeType.Element)
+                               reader.MoveToFirstAttribute ();
+                       else if(reader.NodeType != XmlNodeType.Attribute)
+                               throw new InvalidOperationException ("bad position to read attribute.");
+                       XmlAttribute attribute = CreateAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
+                       ReadAttributeNodeValue (reader, attribute);
+                       return attribute;
+               }
+
+               // Reads attribute from XmlReader and then creates attribute value children. XmlAttribute also uses this.
+               internal void ReadAttributeNodeValue(XmlReader reader, XmlAttribute attribute)
+               {
+                       while(reader.ReadAttributeValue ()) {
+                               if(reader.NodeType == XmlNodeType.EntityReference)
+                                       // FIXME: if DocumentType is available, then try to resolve it.
+                                       attribute.AppendChild (CreateEntityReference (reader.Name));
+                               // FIXME: else if(NodeType == EndEntity) -- reset BaseURI and so on -- ;
+                               else
+                                       // (IMHO) Children of Attribute is likely restricted to Text and EntityReference.
+                                       attribute.AppendChild (CreateTextNode (reader.Value));
+                       }
+               }
+
+               [MonoTODO("DTD parser is not completed.")]
                public virtual XmlNode ReadNode(XmlReader reader)
                {
-                       throw new NotImplementedException ();
+                       // This logic was formerly defined in 'XmlNode.ConstructDOM()'
+
+                       XmlNode resultNode = null;
+                       XmlNode newNode = null;
+                       XmlNode currentNode = null;
+                       // It was originally XmlDocument.Load(reader reader) when mcs was v0.16.
+                       int startDepth = reader.Depth;
+                       bool atStart = true;
+                       bool ignoredWhitespace;
+
+                       do {
+                               ignoredWhitespace = false;
+                               reader.Read ();
+                               // This complicated check is because we shouldn't make
+                               // improper additional XmlReader.Read() by this method itself.
+                               if(atStart && (reader.NodeType == XmlNodeType.EndElement || 
+                                       reader.NodeType == XmlNodeType.EndEntity))
+                                       throw new InvalidOperationException ("the XmlReader now holds invalid position.");
+                               atStart = false;
+                               switch (reader.NodeType) {
+
+                               case XmlNodeType.Attribute:
+                                       newNode = ReadAttributeNode (reader);
+                                       break;
+
+                               case XmlNodeType.CDATA:
+                                       newNode = CreateCDataSection (reader.Value);
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (newNode);
+                                       break;
+
+                               case XmlNodeType.Comment:
+                                       newNode = CreateComment (reader.Value);
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (newNode);
+                                       break;
+
+                               case XmlNodeType.Element:
+                                       XmlElement element = CreateElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
+                                       element.IsEmpty = reader.IsEmptyElement;
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (element);
+                                       else
+                                               resultNode = element;
+
+                                       // set the element's attributes.
+                                       while (reader.MoveToNextAttribute ()) {
+                                               element.SetAttributeNode (ReadAttributeNode (reader));
+                                       }
+
+                                       reader.MoveToElement ();
+
+                                       if (!reader.IsEmptyElement)
+                                               currentNode = element;
+
+                                       break;
+
+                               case XmlNodeType.EndElement:
+                                       if(currentNode.Name != reader.Name)
+                                               throw new XmlException ("mismatch end tag.");
+                                       currentNode = currentNode.ParentNode;
+                                       break;
+
+                               case XmlNodeType.EndEntity:
+                                       break;  // no operation
+
+                               case XmlNodeType.ProcessingInstruction:
+                                       newNode = CreateProcessingInstruction (reader.Name, reader.Value);
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (newNode);
+                                       break;
+
+                               case XmlNodeType.Text:
+                                       newNode = CreateTextNode (reader.Value);
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (newNode);
+                                       break;
+
+                               case XmlNodeType.XmlDeclaration:
+                                       // empty strings are dummy, then gives over setting value contents to setter.
+                                       newNode = CreateXmlDeclaration ("1.0" , String.Empty, String.Empty);
+                                       ((XmlDeclaration)newNode).Value = reader.Value;
+                                       if(currentNode != null)
+                                               throw new XmlException ("XmlDeclaration at invalid position.");
+                                       break;
+
+                               case XmlNodeType.DocumentType:
+                                       // This logic is kinda hack;-)
+                                       XmlTextReader xtReader = reader as XmlTextReader;
+                                       if(xtReader == null) {
+                                               xtReader = new XmlTextReader (reader.ReadOuterXml (),
+                                                       XmlNodeType.DocumentType,
+                                                       new XmlParserContext (NameTable, ConstructNamespaceManager(), XmlLang, XmlSpace));
+                                               xtReader.Read ();
+                                       }
+                                       newNode = CreateDocumentType (xtReader.Name,
+                                               xtReader.GetAttribute ("PUBLIC"),
+                                               xtReader.GetAttribute ("SYSTEM"),
+                                               xtReader.Value);
+                                       if(currentNode != null)
+                                               throw new XmlException ("XmlDocumentType at invalid position.");
+                                       break;
+
+                               case XmlNodeType.EntityReference:
+                                       newNode = CreateEntityReference (reader.Name);
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (newNode);
+                                       break;
+
+                               case XmlNodeType.SignificantWhitespace:
+                                       newNode = CreateSignificantWhitespace (reader.Value);
+                                       if(currentNode != null)
+                                               currentNode.AppendChild (newNode);
+                                       break;
+
+                               case XmlNodeType.Whitespace:
+                                       if(PreserveWhitespace) {
+                                               newNode = CreateWhitespace (reader.Value);
+                                               if(currentNode != null)
+                                                       currentNode.AppendChild (newNode);
+                                       }
+                                       else
+                                               ignoredWhitespace = true;
+                                       break;
+                               }
+                       } while(ignoredWhitespace ||
+                               reader.Depth > startDepth || 
+                               // This complicated condition is because reader.Depth was set
+                               // before XmlTextReader.depth increments ;-)
+                               (reader.Depth == startDepth && reader.NodeType == XmlNodeType.Element && reader.IsEmptyElement == false)
+                               );
+                       return resultNode != null ? resultNode : newNode;
                }
 
                public virtual void Save(Stream outStream)
                {
                        XmlTextWriter xmlWriter = new XmlTextWriter (outStream, Encoding.UTF8);
+                       xmlWriter.Formatting = Formatting.Indented;
                        WriteContentTo (xmlWriter);
                        xmlWriter.Close ();
                }
@@ -667,6 +833,7 @@ namespace System.Xml
                public virtual void Save (string filename)
                {
                        XmlTextWriter xmlWriter = new XmlTextWriter (filename, Encoding.UTF8);
+                       xmlWriter.Formatting = Formatting.Indented;
                        WriteContentTo (xmlWriter);
                        xmlWriter.Close ();
                }
@@ -675,6 +842,7 @@ namespace System.Xml
                public virtual void Save (TextWriter writer)
                {
                        XmlTextWriter xmlWriter = new XmlTextWriter (writer);
+                       xmlWriter.Formatting = Formatting.Indented;
                        WriteContentTo (xmlWriter);
                        xmlWriter.Flush ();
                }
@@ -692,9 +860,6 @@ namespace System.Xml
                {
                        foreach(XmlNode childNode in ChildNodes) {
                                childNode.WriteTo (w);
-                               if(!PreserveWhitespace) {
-                                       w.WriteRaw ("\n");
-                               }
                        }
                }