//
// (C) 2002 Kral Ferch
//
+// [FIXME]
+// Document state should be considered.
+//
using System;
using System.Collections;
XmlSpace xmlSpace = XmlSpace.None;
bool openXmlLang = false;
bool openXmlSpace = false;
+ string openElementPrefix;
+ string openElementNS;
+ bool hasRoot = false;
+ Hashtable writtenAttributes = new Hashtable ();
+ bool checkMultipleAttributes = false;
#endregion
#endregion
#region Methods
+ private void AddMissingElementXmlns ()
+ {
+ // output namespace declaration if not exist.
+ string prefix = openElementPrefix;
+ string ns = openElementNS;
+ openElementPrefix = null;
+ openElementNS = null;
+
+ // LAMESPEC: If prefix was already assigned another nsuri, then this element's nsuri goes away!
+
+ if (ns != null)
+ {
+ string formatXmlns = String.Empty;
+ if (ns != String.Empty)
+ {
+ string existingPrefix = namespaceManager.LookupPrefix (ns);
+ bool addDefaultNamespace = false;
+
+ if (existingPrefix == null)
+ {
+ namespaceManager.AddNamespace (prefix, ns);
+ addDefaultNamespace = true;
+ }
+
+ if (prefix == String.Empty)
+ prefix = existingPrefix;
+
+ if (prefix != existingPrefix)
+ formatXmlns = String.Format (" xmlns:{0}={1}{2}{1}", prefix, quoteChar, ns);
+ else if (addDefaultNamespace)
+ formatXmlns = String.Format (" xmlns={0}{1}{0}", quoteChar, ns);
+ }
+ else if ((prefix == String.Empty) && (namespaceManager.LookupNamespace (prefix) != ns))
+ {
+ namespaceManager.AddNamespace (prefix, ns);
+ formatXmlns = String.Format (" xmlns={0}{0}", quoteChar);
+ }
+ if(formatXmlns != String.Empty) {
+ string xmlns = formatXmlns.Trim ();
+ if (checkMultipleAttributes && !writtenAttributes.Contains (xmlns.Substring (0, xmlns.IndexOf ('='))))
+ w.Write(formatXmlns);
+ }
+ }
+ }
private void CheckState ()
{
throw new InvalidOperationException ("The Writer is closed.");
}
if ((documentStarted == true) && (formatting == Formatting.Indented) && (!IndentingOverriden)) {
- indentFormatting = "\r\n";
+ indentFormatting = w.NewLine;
if (indentLevel > 0) {
for (int i = 0; i < indentLevel; i++)
indentFormatting += indentChars;
private void CloseStartElement ()
{
- if (openStartElement) {
- w.Write(">");
- ws = WriteState.Content;
- openStartElement = false;
- attributeWrittenForElement = false;
- }
+ if (!openStartElement)
+ return;
+
+ AddMissingElementXmlns ();
+
+ w.Write (">");
+ ws = WriteState.Content;
+ openStartElement = false;
+ attributeWrittenForElement = false;
+ checkMultipleAttributes = false;
+ writtenAttributes.Clear ();
}
public override void Flush ()
{
string prefix = namespaceManager.LookupPrefix (ns);
- if (prefix == String.Empty)
- prefix = null;
-
+ // XmlNamespaceManager has changed to return null when NSURI not found.
+ // (Contradiction to the documentation.)
+ //if (prefix == String.Empty)
+ // prefix = null;
return prefix;
}
{
CloseOpenAttributeAndElements ();
- if ((ws == WriteState.Start) || (ws == WriteState.Prolog))
+ if (!hasRoot)
throw new ArgumentException ("This document does not have a root element.");
ws = WriteState.Start;
+ hasRoot = false;
}
public override void WriteEndElement ()
indentLevel--;
CheckState ();
+ AddMissingElementXmlns ();
if (openStartElement) {
if (openAttribute)
WriteEndElementInternal (true);
}
- [MonoTODO]
+ private void CheckValidChars (string name, bool firstOnlyLetter)
+ {
+ foreach (char c in name) {
+ if (XmlConvert.IsInvalid (c, firstOnlyLetter))
+ throw new ArgumentException ("There is an invalid character: '" + c +
+ "'", "name");
+ }
+ }
+
public override void WriteName (string name)
{
- throw new NotImplementedException ();
+ CheckValidChars (name, true);
+ w.Write (name);
}
- [MonoTODO]
public override void WriteNmToken (string name)
{
- throw new NotImplementedException ();
+ CheckValidChars (name, false);
+ w.Write (name);
}
public override void WriteProcessingInstruction (string name, string text)
WriteStringInternal (data, false);
}
- [MonoTODO]
public override void WriteRaw (char[] buffer, int index, int count)
{
- throw new NotImplementedException ();
+ WriteStringInternal (new string (buffer, index, count), false);
}
public override void WriteStartAttribute (string prefix, string localName, string ns)
if ((prefix == "xml") && (localName == "space"))
openXmlSpace = true;
- if ((prefix == "xmlns") && (localName == "xmlns"))
- throw new ArgumentException ("Prefixes beginning with \"xml\" (regardless of whether the characters are uppercase, lowercase, or some combination thereof) are reserved for use by XML.");
+ if ((prefix == "xmlns") && (localName.ToLower ().StartsWith ("xml")))
+ throw new ArgumentException ("Prefixes beginning with \"xml\" (regardless of whether the characters are uppercase, lowercase, or some combination thereof) are reserved for use by XML: " + prefix + ":" + localName);
CheckState ();
string existingPrefix = namespaceManager.LookupPrefix (ns);
if (prefix == String.Empty)
- prefix = existingPrefix;
+ prefix = (existingPrefix == null) ?
+ String.Empty : existingPrefix;
}
if (prefix != String.Empty)
if (openStartElement || attributeWrittenForElement)
formatSpace = " ";
+ // If already written, then break up.
+ if (checkMultipleAttributes &&
+ writtenAttributes.Contains (formatPrefix + localName))
+ return;
+
w.Write ("{0}{1}{2}={3}", formatSpace, formatPrefix, localName, quoteChar);
+ if (checkMultipleAttributes)
+ writtenAttributes.Add (formatPrefix + localName, formatPrefix + localName);
openAttribute = true;
attributeWrittenForElement = true;
ws = WriteState.Attribute;
+ if (prefix == String.Empty && localName == "xmlns") {
+ if (namespaceManager.LookupNamespace (prefix) == null)
+ namespaceManager.AddNamespace (prefix, ns);
+ } else if (prefix == "xmlns") {
+ if (namespaceManager.LookupNamespace (localName) == null)
+ namespaceManager.AddNamespace (localName, ns);
+ }
}
public override void WriteStartDocument ()
if (documentStarted == true)
throw new InvalidOperationException("WriteStartDocument should be the first call.");
+ if (hasRoot)
+ throw new XmlException ("WriteStartDocument called twice.");
+
+ hasRoot = true;
+
CheckState ();
string encodingFormatting = "";
if (!nullEncoding)
- encodingFormatting = String.Format (" encoding={0}{1}{0}", quoteChar, w.Encoding.HeaderName);
+ encodingFormatting = String.Format (" encoding={0}{1}{0}", quoteChar, w.Encoding.WebName);
w.Write("<?xml version={0}1.0{0}{1}{2}?>", quoteChar, encodingFormatting, standaloneFormatting);
ws = WriteState.Prolog;
private void WriteStartElementInternal (string prefix, string localName, string ns)
{
- if (prefix == null)
- prefix = String.Empty;
-
- if ((prefix != String.Empty) && ((ns == null) || (ns == String.Empty)))
+ if ((prefix != null && prefix != String.Empty) && ((ns == null) || (ns == String.Empty)))
throw new ArgumentException ("Cannot use a prefix with an empty namespace.");
CheckState ();
CloseStartElement ();
+ writtenAttributes.Clear ();
+ checkMultipleAttributes = true;
- string formatXmlns = "";
- string formatPrefix = "";
-
- if(ns != null)
- {
- if (ns != String.Empty)
- {
- string existingPrefix = namespaceManager.LookupPrefix (ns);
-
- if (prefix == String.Empty)
- prefix = existingPrefix;
+ if (prefix == null)
+ prefix = namespaceManager.LookupPrefix (ns);
+ if (prefix == null)
+ prefix = String.Empty;
- if (prefix != existingPrefix)
- formatXmlns = String.Format (" xmlns:{0}={1}{2}{1}", prefix, quoteChar, ns);
- else if (existingPrefix == String.Empty)
- formatXmlns = String.Format (" xmlns={0}{1}{0}", quoteChar, ns);
- }
- else if ((prefix == String.Empty) && (namespaceManager.LookupNamespace(prefix) != String.Empty)) {
- formatXmlns = String.Format (" xmlns={0}{0}", quoteChar);
- }
+ string formatPrefix = "";
- if (prefix != String.Empty) {
+ if(ns != null) {
+ if (prefix != String.Empty)
formatPrefix = prefix + ":";
- }
}
- w.Write ("{0}<{1}{2}{3}", indentFormatting, formatPrefix, localName, formatXmlns);
-
+ w.Write ("{0}<{1}{2}", indentFormatting, formatPrefix, localName);
openElements.Push (new XmlTextWriterOpenElement (formatPrefix + localName));
ws = WriteState.Element;
openStartElement = true;
+ openElementNS = ns;
+ openElementPrefix = prefix;
namespaceManager.PushScope ();
- if(ns != null)
- {
- namespaceManager.AddNamespace (prefix, ns);
- }
indentLevel++;
}