2003-10-25 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlWriter.cs
index c7d4bbd330efbd4ebccf9984a8f6049d68518690..de6317e25bee8ae7dedef6ddefa96a48d730c138 100644 (file)
@@ -1,10 +1,12 @@
 //
-// System.Xml.XmlTextWriter
+// System.Xml.XmlWriter
 //
-// Author:
+// Authors:
 //   Kral Ferch <kral_ferch@hotmail.com>
+//   Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
 //
 // (C) 2002 Kral Ferch
+// (C) 2002-2003 Atsushi Enomoto
 //
 
 using System;
@@ -13,13 +15,6 @@ namespace System.Xml
 {
        public abstract class XmlWriter
        {
-               #region Fields
-
-               protected WriteState ws = WriteState.Start;
-               protected XmlNamespaceManager namespaceManager = new XmlNamespaceManager (new NameTable ());
-
-               #endregion
-
                #region Constructors
 
                protected XmlWriter () { }
@@ -44,37 +39,49 @@ namespace System.Xml
 
                public abstract string LookupPrefix (string ns);
 
-               [MonoTODO("DTDs must be implemented to use 'defattr' parameter.")]
+               private void WriteAttribute (XmlReader reader, bool defattr)
+               {
+                       if (!defattr && reader.IsDefault)
+                               return;
+
+                       WriteStartAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
+                       while (reader.ReadAttributeValue ()) {
+                               switch (reader.NodeType) {
+                               case XmlNodeType.Text:
+                                       WriteString (reader.Value);
+                                       break;
+                               case XmlNodeType.EntityReference:
+                                       WriteEntityRef (reader.Name);
+                                       break;
+                               }
+                       }
+                       WriteEndAttribute ();
+               }
+
                public virtual void WriteAttributes (XmlReader reader, bool defattr)
                {
                        if(reader == null)
                                throw new ArgumentException("null XmlReader specified.", "reader");
 
-                       switch(reader.NodeType)
-                       {
-                               case XmlNodeType.XmlDeclaration:
-                                       // this method doesn't write "<?xml " and "?>", at least MS .NET Framework as yet.
-                                       XmlDeclaration decl = new XmlDeclaration("1.0", String.Empty, String.Empty, null);
-                                       decl.Value = reader.Value;
-                                       if(decl.Version != null && decl.Version != String.Empty) WriteAttributeString("version", decl.Version);
-                                       if(decl.Encoding != null && decl.Encoding != String.Empty) WriteAttributeString("encoding", decl.Encoding);
-                                       if(decl.Standalone != null && decl.Standalone != String.Empty) WriteAttributeString("standalone", decl.Standalone);
-                                       break;
-                               case XmlNodeType.Element:
-                                       while (reader.MoveToNextAttribute ()) 
-                                       {
-                                               WriteAttributeString(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value);
-                                       }
-                                       break;
-                               case XmlNodeType.Attribute:
-                                       do
-                                       {
-                                               WriteAttributeString(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value);
-                                       }
-                                       while (reader.MoveToNextAttribute ()) ;
-                                       break;
-                               default:
-                                       throw new XmlException("NodeType is not one of Element, Attribute, nor XmlDeclaration.");
+                       switch (reader.NodeType) {
+                       case XmlNodeType.XmlDeclaration:
+                               WriteAttributeString ("version", reader ["version"]);
+                               if (reader ["encoding"] != null)
+                                       WriteAttributeString ("encoding", reader ["encoding"]);
+                               if (reader ["standalone"] != null)
+                                       WriteAttributeString ("standalone", reader ["standalone"]);
+                               break;
+                       case XmlNodeType.Element:
+                               if (reader.MoveToFirstAttribute ())
+                                       goto case XmlNodeType.Attribute;
+                               break;
+                       case XmlNodeType.Attribute:
+                               do {
+                                       WriteAttribute (reader, defattr);
+                               } while (reader.MoveToNextAttribute ());
+                               break;
+                       default:
+                               throw new XmlException("NodeType is not one of Element, Attribute, nor XmlDeclaration.");
                        }
                }
 
@@ -90,31 +97,15 @@ namespace System.Xml
 
                public void WriteAttributeString (string prefix, string localName, string ns, string value)
                {
-                       if ((prefix == "xmlns") || (localName == "xmlns"))
-                         {
-                               ns = value;
-                               
-                               if (prefix == "xmlns" && namespaceManager.HasNamespace (localName))
-                                       return;
-                               
-                               /* Users need to be able to re-declare the default namespace for subnodes
-                               else if (localName == "xmlns" && namespaceManager.HasNamespace (String.Empty))
-                                       return;
-                               */
-                         }
-                       
+                       // In MS.NET (1.0), this check is done *here*, not at WriteStartAttribute.
+                       // (XmlTextWriter.WriteStartAttribute("xmlns", "anyname", null) throws an exception.
+                       if ((prefix == "xmlns") || (prefix == "" && localName == "xmlns"))
+                               if (ns == null)
+                                       ns = "http://www.w3.org/2000/xmlns/";
+
                        WriteStartAttribute (prefix, localName, ns);
                        WriteString (value);
                        WriteEndAttribute ();
-
-                       if ((prefix == "xmlns") || (localName == "xmlns")) 
-                       {
-                               if (prefix == "xmlns")
-                                       namespaceManager.AddNamespace (localName, ns);
-                               else
-                                       namespaceManager.AddNamespace ("", ns);
-                       }
-                       
                }
 
                public abstract void WriteBase64 (byte[] buffer, int index, int count);
@@ -159,61 +150,76 @@ namespace System.Xml
 
                public abstract void WriteNmToken (string name);
 
-               [MonoTODO("needs to test")]
                public virtual void WriteNode (XmlReader reader, bool defattr)
                {
                        if (reader == null)
                                throw new ArgumentException ();
 
                        if (reader.ReadState == ReadState.Initial) {
-                               while (reader.Read ())
+                               reader.Read ();
+                               do {
                                        WriteNode (reader, defattr);
+                               } while (!reader.EOF);
+                               return;
                        }
-                       else {
-                               switch (reader.NodeType) {
-                               case XmlNodeType.Element:
-                                       WriteStartElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
-                                       WriteAttributes (reader, defattr);
-                                       if (reader.IsEmptyElement)
-                                               WriteEndElement ();
-                                       break;
-                               case XmlNodeType.Attribute:
-                                       break;
-                               case XmlNodeType.Text:
-                                       WriteString (reader.Value);
-                                       break;
-                               case XmlNodeType.CDATA:
-                                       WriteCData (reader.Value);
-                                       break;
-                               case XmlNodeType.EntityReference:
-                                       WriteEntityRef (reader.Name);
-                                       break;
-                               case XmlNodeType.ProcessingInstruction:
-                                       WriteProcessingInstruction (reader.Name, reader.Value);
-                                       break;
-                               case XmlNodeType.Comment:
-                                       WriteComment (reader.Value);
-                                       break;
-                               case XmlNodeType.DocumentType:
-                                       WriteDocType (reader.Name,
-                                               reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
-                                       break;
-                               case XmlNodeType.SignificantWhitespace:
-                                       goto case XmlNodeType.Whitespace;
-                               case XmlNodeType.Whitespace:
-                                       WriteWhitespace (reader.Value);
-                                       break;
-                               case XmlNodeType.EndElement:
-                                       break;
-                               case XmlNodeType.EndEntity:
-                                       break;
-                               case XmlNodeType.XmlDeclaration:
-                                       WriteStartDocument (reader.GetAttribute  ("standalone").ToLower () == "yes");
-                                       break;
-                               default:
-                                       throw new NotImplementedException ();
+
+                       switch (reader.NodeType) {
+                       case XmlNodeType.Element:
+                               WriteStartElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
+                               WriteAttributes (reader, defattr);
+                               reader.MoveToElement ();
+                               if (reader.IsEmptyElement)
+                                       WriteEndElement ();
+                               else {
+                                       int depth = reader.Depth;
+                                       reader.Read ();
+                                       do {
+                                               WriteNode (reader, defattr);
+                                       } while (depth < reader.Depth);
+                                       WriteFullEndElement ();
                                }
+                               break;
+                       // In case of XmlAttribute, don't proceed reader.
+                       case XmlNodeType.Attribute:
+                               return;
+                       case XmlNodeType.Text:
+                               WriteString (reader.Value);
+                               break;
+                       case XmlNodeType.CDATA:
+                               WriteCData (reader.Value);
+                               break;
+                       case XmlNodeType.EntityReference:
+                               WriteEntityRef (reader.Name);
+                               break;
+                       case XmlNodeType.XmlDeclaration:
+                               // LAMESPEC: It means that XmlWriter implementation _must not_ check
+                               // whether PI name is "xml" (it is XML error) or not.
+                       case XmlNodeType.ProcessingInstruction:
+                               WriteProcessingInstruction (reader.Name, reader.Value);
+                               break;
+                       case XmlNodeType.Comment:
+                               WriteComment (reader.Value);
+                               break;
+                       case XmlNodeType.DocumentType:
+                               WriteDocType (reader.Name,
+                                       reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
+                               break;
+                       case XmlNodeType.SignificantWhitespace:
+                               goto case XmlNodeType.Whitespace;
+                       case XmlNodeType.Whitespace:
+                               WriteWhitespace (reader.Value);
+                               break;
+                       case XmlNodeType.EndElement:
+                               WriteFullEndElement ();
+                               break;
+                       case XmlNodeType.EndEntity:
+                               break;
+                       case XmlNodeType.None:
+                               return; // Do nothing, nor reporting errors.
+                       default:
+                               throw new XmlException ("Unexpected node " + reader.Name + " of type " + reader.NodeType);
                        }
+                       reader.Read ();
                }
 
                public abstract void WriteProcessingInstruction (string name, string text);
@@ -226,7 +232,7 @@ namespace System.Xml
 
                public void WriteStartAttribute (string localName, string ns)
                {
-                       WriteStartAttribute ("", localName, ns);
+                       WriteStartAttribute (null, localName, ns);
                }
 
                public abstract void WriteStartAttribute (string prefix, string localName, string ns);