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;
char quote_char = '"';
+ bool v2;
+
// Constructors
public XmlTextWriter (string filename, Encoding encoding)
public XmlTextWriter (TextWriter writer)
{
+ if (writer == null)
+ throw new ArgumentNullException ("writer");
+ ignore_encoding = (writer.Encoding == null);
Initialize (writer);
allow_doc_fragment = true;
}
#if NET_2_0
internal XmlTextWriter (
- TextWriter writer, XmlWriterSettings settings)
+ TextWriter writer, XmlWriterSettings settings, bool closeOutput)
{
+ v2 = true;
+
if (settings == null)
settings = new XmlWriterSettings ();
Initialize (writer);
- close_output_stream = settings.CloseOutput;
+ close_output_stream = closeOutput;
allow_doc_fragment =
settings.ConformanceLevel != ConformanceLevel.Document;
switch (settings.ConformanceLevel) {
check_character_validity = settings.CheckCharacters;
newline_handling = settings.NewLineHandling;
+ namespace_handling = settings.NamespaceHandling;
}
#endif
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 ();
if (state != WriteState.Start)
throw StateError ("XmlDeclaration");
- state = WriteState.Prolog;
-
switch (xmldecl_state) {
case XmlDeclState.Ignore:
return;
throw InvalidOperation ("WriteStartDocument cannot be called when ConformanceLevel is Fragment.");
}
+ state = WriteState.Prolog;
+
writer.Write ("<?xml version=");
writer.Write (quote_char);
writer.Write ("1.0");
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.
if (open_count == 0)
throw InvalidOperation ("There is no more open element.");
- bool isEmpty = state != WriteState.Content;
+ // bool isEmpty = state != WriteState.Content;
CloseStartElementCore ();
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");
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
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)
}
if (indent_attributes)
- WriteIndent ();
+ WriteIndentAttribute ();
else if (state != WriteState.Start)
writer.Write (' ');
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":
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);
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);
void WriteIndent ()
{
- WriteIndentCore (0);
+ WriteIndentCore (0, false);
}
void WriteIndentEndElement ()
{
- WriteIndentCore (-1);
+ WriteIndentCore (-1, false);
}
- void WriteIndentCore (int nestFix)
+ void WriteIndentAttribute ()
+ {
+ if (!WriteIndentCore (0, true))
+ writer.Write (' '); // space is required instead.
+ }
+
+ bool WriteIndentCore (int nestFix, bool attribute)
{
if (!indent)
- return;
+ return false;
for (int i = open_count - 1; i >= 0; i--)
- if (elements [i].HasSimple)
- return;
+ if (!attribute && elements [i].HasSimple)
+ return false;
if (state != WriteState.Start)
writer.Write (newline);
for (int i = 0; i < open_count + nestFix; i++)
writer.Write (indent_string);
+ return true;
}
void OutputAutoStartDocument ()