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 ((object) prefix == null)
prefix = String.Empty;
// For xmlns URI, prefix is forced to be "xmlns"
bool isNSDecl = false;
if (namespaceUri == XmlnsNamespace) {
isNSDecl = true;
if (prefix.Length == 0 && localName != "xmlns")
prefix = "xmlns";
}
else
isNSDecl = (prefix == "xmlns" ||
localName == "xmlns" && prefix.Length == 0);
if (namespaces) {
// MS implementation is pretty hacky here.
// Regardless of namespace URI it is regarded
// as NS URI for "xml".
if (prefix == "xml")
namespaceUri = XmlNamespace;
// infer namespace URI.
else if ((object) namespaceUri == null) {
if (isNSDecl)
namespaceUri = XmlnsNamespace;
else
namespaceUri = String.Empty;
}
// It is silly design - null namespace with
// "xmlns" are allowed (for namespace-less
// output; while there is Namespaces property)
// On the other hand, namespace "" is not
// allowed.
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 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)
prefix = DetermineAttributePrefix (
prefix, localName, namespaceUri);
}
if (indent_attributes)
WriteIndentAttribute ();
else if (state != WriteState.Start)
writer.Write (' ');
if (prefix.Length > 0) {
writer.Write (prefix);
writer.Write (':');
}
writer.Write (localName);
writer.Write ('=');
writer.Write (quote_char);
if (isNSDecl || prefix == "xml") {
if (preserver == null)
preserver = new StringWriter ();
else
preserver.GetStringBuilder ().Length = 0;
writer = preserver;
if (!isNSDecl) {
is_preserved_xmlns = false;
preserved_name = localName;
} else {
is_preserved_xmlns = true;
preserved_name = localName == "xmlns" ?
String.Empty : localName;
}
}
state = WriteState.Attribute;
}