X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.XML%2FSystem.Xml%2FXmlTextWriter.cs;h=3f6c19e29841cd6cd77cfe291943e82d5c6c3f45;hb=f8abecbb7fc52d6d161dd3a9155437ca4440d72f;hp=bd561bc400292c08fe32810b97399b123a12c5f5;hpb=7816a48c1223e0f16c776c3d9ebd9d36d7455ffc;p=mono.git diff --git a/mcs/class/System.XML/System.Xml/XmlTextWriter.cs b/mcs/class/System.XML/System.Xml/XmlTextWriter.cs index bd561bc4002..3f6c19e2984 100644 --- a/mcs/class/System.XML/System.Xml/XmlTextWriter.cs +++ b/mcs/class/System.XML/System.Xml/XmlTextWriter.cs @@ -18,23 +18,31 @@ namespace System.Xml { #region Fields - protected TextWriter w; - protected bool nullEncoding = false; - protected bool openWriter = true; - protected bool openStartElement = false; - protected bool openStartAttribute = false; - protected bool documentStarted = false; - protected bool namespaces = true; - protected bool openAttribute = false; - protected Stack openElements = new Stack (); - protected Formatting formatting = Formatting.None; - protected int indentation = 2; - protected char indentChar = ' '; - protected string indentChars = " "; - protected char quoteChar = '\"'; - protected int indentLevel = 0; - protected string indentFormatting; - protected Stream baseStream = null; + TextWriter w; + bool nullEncoding = false; + bool openWriter = true; + bool openStartElement = false; + bool openStartAttribute = false; + bool documentStarted = false; + bool namespaces = true; + bool openAttribute = false; + bool attributeWrittenForElement = false; + Stack openElements = new Stack (); + Formatting formatting = Formatting.None; + int indentation = 2; + char indentChar = ' '; + string indentChars = " "; + char quoteChar = '\"'; + int indentLevel = 0; + string indentFormatting; + Stream baseStream = null; + string xmlLang = null; + XmlSpace xmlSpace = XmlSpace.None; + bool openXmlLang = false; + bool openXmlSpace = false; + string openElementPrefix; + string openElementNS; + bool hasRoot = false; #endregion @@ -43,6 +51,7 @@ namespace System.Xml public XmlTextWriter (TextWriter w) : base () { this.w = w; + nullEncoding = (w.Encoding == null); try { baseStream = ((StreamWriter)w).BaseStream; @@ -61,10 +70,9 @@ namespace System.Xml baseStream = w; } - public XmlTextWriter (string filename, Encoding encoding) : base () + public XmlTextWriter (string filename, Encoding encoding) : + this (new FileStream (filename, FileMode.Create, FileAccess.Write, FileShare.None), encoding) { - this.w = new StreamWriter(filename, false, encoding); - baseStream = ((StreamWriter)w).BaseStream; } #endregion @@ -81,7 +89,7 @@ namespace System.Xml set { formatting = value; } } - public bool IndentingOverriden + private bool IndentingOverriden { get { if (openElements.Count == 0) @@ -121,7 +129,6 @@ namespace System.Xml } } - [MonoTODO] public char QuoteChar { get { return quoteChar; } set { @@ -136,28 +143,87 @@ namespace System.Xml get { return ws; } } - [MonoTODO] public override string XmlLang { - get { throw new NotImplementedException(); } + get { + string xmlLang = null; + int i; + + for (i = 0; i < openElements.Count; i++) + { + xmlLang = ((XmlTextWriterOpenElement)openElements.ToArray().GetValue(i)).XmlLang; + if (xmlLang != null) + break; + } + + return xmlLang; + } } - [MonoTODO] public override XmlSpace XmlSpace { - get { throw new NotImplementedException(); } + get { + XmlSpace xmlSpace = XmlSpace.None; + int i; + + for (i = 0; i < openElements.Count; i++) + { + xmlSpace = ((XmlTextWriterOpenElement)openElements.ToArray().GetValue(i)).XmlSpace; + if (xmlSpace != XmlSpace.None) + break; + } + + return xmlSpace; + } } #endregion #region Methods + private void AddMissingElementXmlns () + { + // output namespace declaration if not exist. + string prefix = openElementPrefix; + string ns = openElementNS; + if (ns != null/* && LookupPrefix (ns) != prefix*/) + { + 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) != String.Empty)) + { + namespaceManager.AddNamespace (prefix, ns); + formatXmlns = String.Format (" xmlns={0}{0}", quoteChar); + } + if(formatXmlns != String.Empty) + w.Write(formatXmlns); + openElementPrefix = null; + openElementNS = null; + } + } private void CheckState () { if (!openWriter) { 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; @@ -171,32 +237,34 @@ namespace System.Xml public override void Close () { - while (openElements.Count > 0) { - WriteEndElement(); - } + CloseOpenAttributeAndElements (); w.Close(); ws = WriteState.Closed; openWriter = false; } - private void CloseStartAttribute () + private void CloseOpenAttributeAndElements () { - if (openStartAttribute) - { - w.Write("={0}", quoteChar); - openStartAttribute = false; + if (openAttribute) + WriteEndAttribute (); + + while (openElements.Count > 0) { + WriteEndElement(); } } private void CloseStartElement () { - if (openStartElement) - { - w.Write(">"); - ws = WriteState.Content; - openStartElement = false; - } + if (!openStartElement) + return; + + AddMissingElementXmlns (); + + w.Write (">"); + ws = WriteState.Content; + openStartElement = false; + attributeWrittenForElement = false; } public override void Flush () @@ -204,10 +272,15 @@ namespace System.Xml w.Flush (); } - [MonoTODO] public override string LookupPrefix (string ns) { - throw new NotImplementedException (); + string prefix = namespaceManager.LookupPrefix (ns); + + // XmlNamespaceManager has changed to return null when NSURI not found. + // (Contradiction to the documentation.) + //if (prefix == String.Empty) + // prefix = null; + return prefix; } private void UpdateIndentChars () @@ -217,10 +290,9 @@ namespace System.Xml indentChars += indentChar; } - [MonoTODO] public override void WriteBase64 (byte[] buffer, int index, int count) { - throw new NotImplementedException (); + w.Write (Convert.ToBase64String (buffer, index, count)); } [MonoTODO] @@ -231,10 +303,8 @@ namespace System.Xml public override void WriteCData (string text) { - if (text.IndexOf("]]>") > 0) - { + if (text.IndexOf("]]>") > 0) throw new ArgumentException (); - } CheckState (); CloseStartElement (); @@ -242,10 +312,16 @@ namespace System.Xml w.Write("", text); } - [MonoTODO] public override void WriteCharEntity (char ch) { - throw new NotImplementedException (); + Int16 intCh = (Int16)ch; + + // Make sure the character is not in the surrogate pair + // character range, 0xd800- 0xdfff + if ((intCh >= -10240) && (intCh <= -8193)) + throw new ArgumentException ("Surrogate Pair is invalid."); + + w.Write("&#x{0:X};", intCh); } [MonoTODO] @@ -266,10 +342,23 @@ namespace System.Xml w.Write ("", text); } - [MonoTODO] public override void WriteDocType (string name, string pubid, string sysid, string subset) { - throw new NotImplementedException (); + if (name == null || name.Trim ().Length == 0) + throw new ArgumentException ("Invalid DOCTYPE name", "name"); + + w.Write ("'); } public override void WriteEndAttribute () @@ -279,38 +368,64 @@ namespace System.Xml CheckState (); - if (openStartAttribute) - CloseStartAttribute (); + if (openXmlLang) { + w.Write (xmlLang); + openXmlLang = false; + ((XmlTextWriterOpenElement)openElements.Peek()).XmlLang = xmlLang; + } + + if (openXmlSpace) + { + w.Write (xmlSpace.ToString ().ToLower ()); + openXmlSpace = false; + ((XmlTextWriterOpenElement)openElements.Peek()).XmlSpace = xmlSpace; + } w.Write ("{0}", quoteChar); openAttribute = false; } - [MonoTODO] public override void WriteEndDocument () { - throw new NotImplementedException (); + CloseOpenAttributeAndElements (); + + if (!hasRoot) + throw new ArgumentException ("This document does not have a root element."); + + ws = WriteState.Start; + hasRoot = false; } public override void WriteEndElement () + { + WriteEndElementInternal (false); + } + + private void WriteEndElementInternal (bool fullEndElement) { if (openElements.Count == 0) throw new InvalidOperationException("There was no XML start tag open."); indentLevel--; - CheckState (); + AddMissingElementXmlns (); if (openStartElement) { - w.Write (" />"); + if (openAttribute) + WriteEndAttribute (); + if (fullEndElement) + w.Write (">", ((XmlTextWriterOpenElement)openElements.Peek ()).Name); + else + w.Write (" />"); + openElements.Pop (); openStartElement = false; - } - else { + } else { w.Write ("{0}", indentFormatting, openElements.Pop ()); - namespaceManager.PopScope(); } + + namespaceManager.PopScope(); } [MonoTODO] @@ -319,22 +434,30 @@ namespace System.Xml throw new NotImplementedException (); } - [MonoTODO] public override void WriteFullEndElement () { - throw new NotImplementedException (); + WriteEndElementInternal (true); + } + + 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"); + } } - [MonoTODO] 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) @@ -352,28 +475,39 @@ namespace System.Xml [MonoTODO] public override void WriteQualifiedName (string localName, string ns) { - throw new NotImplementedException (); + if (localName == null || localName == String.Empty) + throw new ArgumentException (); + + CheckState (); + w.Write ("{0}:{1}", ns, localName); } - [MonoTODO] public override void WriteRaw (string data) { - throw new NotImplementedException (); + 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 == "lang")) + openXmlLang = true; + + 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."); CheckState (); + if (ws == WriteState.Content) + throw new InvalidOperationException ("Token StartAttribute in state " + WriteState + " would result in an invalid XML document."); + if (prefix == null) prefix = String.Empty; @@ -381,13 +515,15 @@ namespace System.Xml ns = String.Empty; string formatPrefix = ""; + string formatSpace = ""; if (ns != String.Empty) { string existingPrefix = namespaceManager.LookupPrefix (ns); if (prefix == String.Empty) - prefix = existingPrefix; + prefix = (existingPrefix == null) ? + String.Empty : existingPrefix; } if (prefix != String.Empty) @@ -395,11 +531,14 @@ namespace System.Xml formatPrefix = prefix + ":"; } - w.Write (" {0}{1}", formatPrefix, localName); + if (openStartElement || attributeWrittenForElement) + formatSpace = " "; + + w.Write ("{0}{1}{2}={3}", formatSpace, formatPrefix, localName, quoteChar); openAttribute = true; + attributeWrittenForElement = true; ws = WriteState.Attribute; - openStartAttribute = true; } public override void WriteStartDocument () @@ -424,11 +563,16 @@ namespace System.Xml 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) + if (!nullEncoding) encodingFormatting = String.Format (" encoding={0}{1}{0}", quoteChar, w.Encoding.HeaderName); w.Write("", quoteChar, encodingFormatting, standaloneFormatting); @@ -444,52 +588,39 @@ namespace System.Xml WriteStartElementInternal (prefix, localName, ns); } - protected override void WriteStartElementInternal (string prefix, string localName, string ns) + private void WriteStartElementInternal (string prefix, string localName, string ns) { - if (prefix == null) - prefix = String.Empty; - - if (ns == null) - ns = 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 (); + + if (prefix == null) + prefix = namespaceManager.LookupPrefix (ns); + if (prefix == null) + prefix = String.Empty; string formatXmlns = ""; string formatPrefix = ""; - if (ns != String.Empty) - { - string existingPrefix = namespaceManager.LookupPrefix (ns); - - if (prefix == String.Empty) - prefix = existingPrefix; - - 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); - } - - if (prefix != String.Empty) { - formatPrefix = prefix + ":"; + if(ns != null) { + if (prefix != String.Empty) + formatPrefix = prefix + ":"; } w.Write ("{0}<{1}{2}{3}", indentFormatting, formatPrefix, localName, formatXmlns); + openElements.Push (new XmlTextWriterOpenElement (formatPrefix + localName)); ws = WriteState.Element; openStartElement = true; + openElementNS = ns; + openElementPrefix = prefix; namespaceManager.PushScope (); - namespaceManager.AddNamespace (prefix, ns); - +// if(ns != null) +// namespaceManager.AddNamespace (prefix, ns); indentLevel++; } @@ -498,32 +629,60 @@ namespace System.Xml if (ws == WriteState.Prolog) throw new InvalidOperationException ("Token content in state Prolog would result in an invalid XML document."); + WriteStringInternal (text, true); + } + + private void WriteStringInternal (string text, bool entitize) + { if (text == null) text = String.Empty; - if (text != String.Empty) { + if (text != String.Empty) + { CheckState (); - text = text.Replace ("&", "&"); - text = text.Replace ("<", "<"); - text = text.Replace (">", ">"); - - if (openStartAttribute) { - if (quoteChar == '"') - text = text.Replace ("\"", """); - else - text = text.Replace ("'", "'"); + if (entitize) + { + text = text.Replace ("&", "&"); + text = text.Replace ("<", "<"); + text = text.Replace (">", ">"); + + if (openAttribute) + { + if (quoteChar == '"') + text = text.Replace ("\"", """); + else + text = text.Replace ("'", "'"); + } } - if (openStartAttribute) - CloseStartAttribute (); - else + if (!openAttribute) + { + IndentingOverriden = true; CloseStartElement (); - - w.Write (text); + } + if (!openXmlLang && !openXmlSpace) + w.Write (text); + else + { + if (openXmlLang) + xmlLang = text; + else + { + switch (text) + { + case "default": + xmlSpace = XmlSpace.Default; + break; + case "preserve": + xmlSpace = XmlSpace.Preserve; + break; + default: + throw new ArgumentException ("'{0}' is an invalid xml:space value."); + } + } + } } - - IndentingOverriden = true; } [MonoTODO] @@ -532,10 +691,14 @@ namespace System.Xml throw new NotImplementedException (); } - [MonoTODO] public override void WriteWhitespace (string ws) { - throw new NotImplementedException (); + foreach (char c in ws) { + if ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n')) + throw new ArgumentException (); + } + + w.Write (ws); } #endregion