New tests.
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextWriter2.cs
index fecbe22fc4a1b9c7d0e1bb2e6530ba5b4b586360..a47d0edc80b5fb13c25696cb5891d83240d5f2d2 100644 (file)
@@ -229,6 +229,7 @@ namespace Mono.Xml
                XmlNodeInfo [] elements = new XmlNodeInfo [10];
                Stack new_local_namespaces = new Stack ();
                ArrayList explicit_nsdecls = new ArrayList ();
+               NamespaceHandling namespace_handling;
 
                bool indent;
                int indent_count = 2;
@@ -239,6 +240,8 @@ namespace Mono.Xml
 
                char quote_char = '"';
 
+               bool v2;
+
                // Constructors
 
                public XmlTextWriter (string filename, Encoding encoding)
@@ -257,6 +260,9 @@ namespace Mono.Xml
 
                public XmlTextWriter (TextWriter writer)
                {
+                       if (writer == null)
+                               throw new ArgumentNullException ("writer");
+                       ignore_encoding = (writer.Encoding == null);
                        Initialize (writer);
                        allow_doc_fragment = true;
                }
@@ -265,6 +271,8 @@ namespace Mono.Xml
                internal XmlTextWriter (
                        TextWriter writer, XmlWriterSettings settings, bool closeOutput)
                {
+                       v2 = true;
+
                        if (settings == null)
                                settings = new XmlWriterSettings ();
 
@@ -301,6 +309,7 @@ namespace Mono.Xml
 
                        check_character_validity = settings.CheckCharacters;
                        newline_handling = settings.NewLineHandling;
+                       namespace_handling = settings.NamespaceHandling;
                }
 #endif
 
@@ -420,10 +429,16 @@ namespace Mono.Xml
 
                public override void Close ()
                {
-                       if (state == WriteState.Attribute)
-                               WriteEndAttribute ();
-                       while (open_count > 0)
-                               WriteEndElement ();
+#if NET_2_0
+                       if (state != WriteState.Error) {
+#endif
+                               if (state == WriteState.Attribute)
+                                       WriteEndAttribute ();
+                               while (open_count > 0)
+                                       WriteEndElement ();
+#if NET_2_0
+                       }
+#endif
 
                        if (close_output_stream)
                                writer.Close ();
@@ -599,8 +614,14 @@ namespace Mono.Xml
                        if (!namespaces && prefix.Length > 0)
                                throw ArgumentError ("Namespace prefix is disabled in this XmlTextWriter.");
 
-                       if (prefix.Length > 0 && namespaceUri == null)
-                               throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
+                       // If namespace URI is empty, then either prefix
+                       // must be empty as well, or there is an
+                       // existing namespace mapping for the prefix.
+                       if (prefix.Length > 0 && namespaceUri == null) {
+                               namespaceUri = nsmanager.LookupNamespace (prefix, false);
+                               if (namespaceUri == null || namespaceUri.Length == 0)
+                                       throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
+                       }
                        // Considering the fact that WriteStartAttribute()
                        // automatically changes argument namespaceURI, this
                        // is kind of silly implementation. See bug #77094.
@@ -750,7 +771,7 @@ namespace Mono.Xml
                        if (open_count == 0)
                                throw InvalidOperation ("There is no more open element.");
 
-                       bool isEmpty = state != WriteState.Content;
+                       // bool isEmpty = state != WriteState.Content;
 
                        CloseStartElementCore ();
 
@@ -788,6 +809,14 @@ namespace Mono.Xml
                public override void WriteStartAttribute (
                        string prefix, string localName, string namespaceUri)
                {
+                       // LAMESPEC: this violates the expected behavior of
+                       // this method, as it incorrectly allows unbalanced
+                       // output of attributes. Microfot changes description
+                       // on its behavior at their will, regardless of
+                       // ECMA description.
+                       if (state == WriteState.Attribute)
+                               WriteEndAttribute ();
+
                        if (state != WriteState.Element && state != WriteState.Start)
                                throw StateError ("Attribute");
 
@@ -812,7 +841,7 @@ namespace Mono.Xml
                                if (prefix == "xml")
                                        namespaceUri = XmlNamespace;
                                // infer namespace URI.
-                               else if ((object) namespaceUri == null) {
+                               else if ((object) namespaceUri == null || (v2 && namespaceUri.Length == 0)) {
                                        if (isNSDecl)
                                                namespaceUri = XmlnsNamespace;
                                        else
@@ -827,10 +856,14 @@ namespace Mono.Xml
                                if (isNSDecl && namespaceUri != XmlnsNamespace)
                                        throw ArgumentError (String.Format ("The 'xmlns' attribute is bound to the reserved namespace '{0}'", XmlnsNamespace));
 
-                               // If namespace URI is empty, then prefix
-                               // must be empty as well.
-                               if (prefix.Length > 0 && namespaceUri.Length == 0)
-                                       throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
+                               // If namespace URI is empty, then either prefix
+                               // must be empty as well, or there is an
+                               // existing namespace mapping for the prefix.
+                               if (prefix.Length > 0 && namespaceUri.Length == 0) {
+                                       namespaceUri = nsmanager.LookupNamespace (prefix, false);
+                                       if (namespaceUri == null || namespaceUri.Length == 0)
+                                               throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
+                               }
 
                                // Dive into extremely complex procedure.
                                if (!isNSDecl && namespaceUri.Length > 0)
@@ -938,13 +971,24 @@ namespace Mono.Xml
                                            value.Length == 0)
                                                throw ArgumentError ("Non-empty prefix must be mapped to non-empty namespace URI.");
                                        string existing = nsmanager.LookupNamespace (preserved_name, false);
-                                       explicit_nsdecls.Add (preserved_name);
-                                       if (open_count > 0 &&
-                                           elements [open_count - 1].NS == String.Empty &&
-                                           elements [open_count - 1].Prefix == preserved_name)
-                                               ; // do nothing
-                                       else if (existing != value)
-                                               nsmanager.AddNamespace (preserved_name, value);
+
+                                       // consider OmitDuplicates here.
+                                       if ((namespace_handling & NamespaceHandling.OmitDuplicates) == 0 || existing != value)
+                                               explicit_nsdecls.Add (preserved_name);
+
+                                       if (open_count > 0) {
+
+                                               if (v2 &&
+                                                   elements [open_count - 1].Prefix == preserved_name &&
+                                                   elements [open_count - 1].NS != value)
+                                                       throw new XmlException (String.Format ("Cannot redefine the namespace for prefix '{0}' used at current element", preserved_name));
+
+                                               if (elements [open_count - 1].NS == String.Empty &&
+                                                   elements [open_count - 1].Prefix == preserved_name)
+                                                       ; // do nothing
+                                               else if (existing != value)
+                                                       nsmanager.AddNamespace (preserved_name, value);
+                                       }
                                } else {
                                        switch (preserved_name) {
                                        case "lang":
@@ -1058,7 +1102,7 @@ namespace Mono.Xml
 
                public override void WriteString (string text)
                {
-                       if (text == null || text.Length == 0)
+                       if (text == null || (text.Length == 0 && !v2))
                                return; // do nothing, including state transition.
                        ShiftStateContent ("Text", true);
 
@@ -1155,9 +1199,7 @@ namespace Mono.Xml
 
                        ShiftStateContent ("QName", true);
 
-                       string prefix =
-                               state == WriteState.Content || ns.Length > 0 ?
-                               LookupPrefix (ns) : String.Empty;
+                       string prefix = ns.Length > 0 ? LookupPrefix (ns) : String.Empty;
                        if (prefix == null) {
                                if (state == WriteState.Attribute)
                                        prefix = MockupPrefix (ns, false);