2 // System.Xml.XmlTextWriter
5 // Kral Ferch <kral_ferch@hotmail.com>
6 // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
9 // (C) 2003 Atsushi Enomoto
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Globalization;
40 public class XmlTextWriter : XmlWriter
43 const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
45 WriteState ws = WriteState.Start;
47 bool nullEncoding = false;
48 bool openWriter = true;
49 bool openStartElement = false;
50 bool documentStarted = false;
51 bool namespaces = true;
52 bool openAttribute = false;
53 bool attributeWrittenForElement = false;
54 ArrayList openElements = new ArrayList ();
56 Formatting formatting = Formatting.None;
58 char indentChar = ' ';
59 string indentChars = " ";
60 char quoteChar = '\"';
63 Stream baseStream = null;
64 string xmlLang = null;
65 XmlSpace xmlSpace = XmlSpace.None;
66 bool openXmlLang = false;
67 bool openXmlSpace = false;
68 string openElementPrefix;
71 bool isDocumentEntity = false;
72 Hashtable newAttributeNamespaces = new Hashtable ();
73 Hashtable userWrittenNamespaces = new Hashtable ();
74 StringBuilder cachedStringBuilder;
75 int autoCreatedPrefixes;
77 XmlNamespaceManager namespaceManager = new XmlNamespaceManager (new NameTable ());
78 string savingAttributeValue = String.Empty;
79 bool saveAttributeValue;
80 string savedAttributePrefix;
81 bool shouldAddSavedNsToManager;
82 bool shouldCheckElementXmlns;
84 // XmlWriterSettings support
86 bool closeOutput = true;
87 bool newLineOnAttributes;
90 bool outputXmlDeclaration;
91 ConformanceLevel conformanceLevel;
98 public XmlTextWriter (TextWriter w) : base ()
101 nullEncoding = (w.Encoding == null);
102 StreamWriter sw = w as StreamWriter;
104 baseStream = sw.BaseStream;
105 newLineChars = w.NewLine;
108 public XmlTextWriter (Stream w, Encoding encoding) : base ()
110 if (encoding == null) {
112 this.w = new StreamWriter (w);
114 this.w = new StreamWriter (w, encoding);
116 newLineChars = this.w.NewLine;
119 public XmlTextWriter (string filename, Encoding encoding) :
120 this (new FileStream (filename, FileMode.Create, FileAccess.Write, FileShare.None), encoding)
128 public Stream BaseStream {
129 get { return baseStream; }
133 public Formatting Formatting {
134 get { return formatting; }
135 set { formatting = value; }
138 private bool IndentingOverriden
141 if (openElementCount == 0)
144 return ((XmlTextWriterOpenElement)
145 openElements [openElementCount - 1]).IndentingOverriden;
148 if (openElementCount > 0)
149 ((XmlTextWriterOpenElement) openElements [openElementCount - 1]).IndentingOverriden = value;
153 private bool ParentIndentingOverriden {
155 if (openElementCount < 2)
157 return ((XmlTextWriterOpenElement) openElements [openElementCount - 2]).IndentingOverriden;
161 public int Indentation {
162 get { return indentation; }
165 UpdateIndentChars ();
169 public char IndentChar {
170 get { return indentChar; }
173 UpdateIndentChars ();
178 internal bool CheckCharacters {
179 get { return checkCharacters; }
180 set { checkCharacters = value; }
183 internal bool CloseOutput {
184 // get { return closeOutput; }
185 set { closeOutput = value; }
188 // As for ConformanceLevel, MS.NET is inconsistent with
189 // MSDN documentation. For example, even if ConformanceLevel
190 // is set as .Auto, multiple WriteStartDocument() calls
191 // result in an error.
192 // ms-help://MS.NETFramework.v20.en/wd_xml/html/7db8802b-53d8-4735-a637-4d2d2158d643.htm
194 internal ConformanceLevel ConformanceLevel {
195 get { return conformanceLevel; }
197 conformanceLevel = value;
198 if (value == ConformanceLevel.Fragment)
199 documentStarted = true;
203 internal string IndentChars {
204 // get { return indentChars; }
205 set { indentChars = value == null ? String.Empty : value; }
208 internal string NewLineChars {
209 // get { return newLineChars; }
210 set { newLineChars = value == null ? String.Empty : value; }
213 internal bool NewLineOnAttributes {
214 // get { return newLineOnAttributes; }
215 set { newLineOnAttributes = value; }
218 internal bool OmitXmlDeclaration {
219 // get { return !outputXmlDeclaration; }
220 set { outputXmlDeclaration = !value; }
224 public bool Namespaces {
225 get { return namespaces; }
227 if (ws != WriteState.Start)
228 throw new InvalidOperationException ("NotInWriteState.");
234 public char QuoteChar {
235 get { return quoteChar; }
237 if ((value != '\'') && (value != '\"'))
238 throw ArgumentError ("This is an invalid XML attribute quote character. Valid attribute quote characters are ' and \".");
244 public override WriteState WriteState {
248 public override string XmlLang {
250 string xmlLang = null;
253 for (i = openElementCount - 1; i >= 0; i--) {
254 xmlLang = ((XmlTextWriterOpenElement) openElements [i]).XmlLang;
263 public override XmlSpace XmlSpace {
265 XmlSpace xmlSpace = XmlSpace.None;
268 for (i = openElementCount - 1; i >= 0; i--) {
269 xmlSpace = ((XmlTextWriterOpenElement)openElements [i]).XmlSpace;
270 if (xmlSpace != XmlSpace.None)
282 private void CheckStartDocument ()
284 if (outputXmlDeclaration &&
285 conformanceLevel == ConformanceLevel.Document &&
286 ws == WriteState.Start)
287 WriteStartDocument ();
291 private void AddMissingElementXmlns ()
293 // output namespace declaration if not exist.
294 string prefix = openElementPrefix;
295 string ns = openElementNS;
296 openElementPrefix = null;
297 openElementNS = null;
299 // LAMESPEC: If prefix was already assigned another nsuri, then this element's nsuri goes away!
301 if (this.shouldCheckElementXmlns) {
302 if (userWrittenNamespaces [prefix] == null) {
303 if (prefix != string.Empty) {
308 w.Write (EscapeString (ns, false));
314 w.Write (EscapeString (ns, false));
319 shouldCheckElementXmlns = false;
322 if (newAttributeNamespaces.Count > 0)
324 foreach (DictionaryEntry ent in newAttributeNamespaces)
326 string ans = (string) ent.Value;
327 string aprefix = (string) ent.Key;
329 if (namespaceManager.LookupNamespace (aprefix, false) == ans)
331 ans = EscapeString (ans, false);
338 namespaceManager.AddNamespace (aprefix, ans);
340 newAttributeNamespaces.Clear ();
342 autoCreatedPrefixes = 0;
345 private void CheckState ()
348 CheckStartDocument ();
353 private void CheckOutputState ()
356 if (ws == WriteState.Error)
357 throw new InvalidOperationException ("Writing at state Error would result in a wrong result.");
360 throw new InvalidOperationException ("The Writer is closed.");
362 if ((documentStarted == true) && (formatting == Formatting.Indented) && (!IndentingOverriden)) {
368 documentStarted = true;
371 public override void Close ()
373 CloseOpenAttributeAndElements ();
377 else if (ws != WriteState.Closed)
379 ws = WriteState.Closed;
383 private void CloseOpenAttributeAndElements ()
386 WriteEndAttribute ();
388 while (openElementCount > 0) {
393 private void CloseStartElement ()
395 if (!openStartElement)
398 AddMissingElementXmlns ();
401 ws = WriteState.Content;
402 openStartElement = false;
403 attributeWrittenForElement = false;
404 newAttributeNamespaces.Clear ();
405 userWrittenNamespaces.Clear ();
408 public override void Flush ()
413 public override string LookupPrefix (string ns)
415 if (ns == null || ns == String.Empty)
416 throw ArgumentError ("The Namespace cannot be empty.");
418 string prefix = namespaceManager.LookupPrefix (ns, false);
419 // XmlNamespaceManager might return such prefix that
420 // is *previously* mapped to ns passed above.
421 if (prefix == null || namespaceManager.LookupNamespace (prefix) != ns)
424 // XmlNamespaceManager has changed to return null when NSURI not found.
425 // (Contradiction to the ECMA documentation.)
429 private void UpdateIndentChars ()
431 indentChars = new string (indentChar, indentation);
434 public override void WriteBase64 (byte[] buffer, int index, int count)
438 if (!openAttribute) {
439 IndentingOverriden = true;
440 CloseStartElement ();
443 w.Write (Convert.ToBase64String (buffer, index, count));
446 public override void WriteBinHex (byte[] buffer, int index, int count)
450 if (!openAttribute) {
451 IndentingOverriden = true;
452 CloseStartElement ();
455 XmlConvert.WriteBinHex (buffer, index, count, w);
458 public override void WriteCData (string text)
460 if (text.IndexOf ("]]>") >= 0)
461 throw ArgumentError ("CDATA section cannot contain text \"]]>\".");
464 IndentingOverriden = true;
465 CloseStartElement ();
467 w.Write ("<![CDATA[");
472 public override void WriteCharEntity (char ch)
474 Int16 intCh = (Int16)ch;
476 // Make sure the character is not in the surrogate pair
477 // character range, 0xd800- 0xdfff
478 if ((intCh >= -10240) && (intCh <= -8193))
479 throw ArgumentError ("Surrogate Pair is invalid.");
481 w.Write("&#x{0:X};", intCh);
484 public override void WriteChars (char[] buffer, int index, int count)
488 if (!openAttribute) {
489 IndentingOverriden = true;
490 CloseStartElement ();
493 w.Write (buffer, index, count);
496 public override void WriteComment (string text)
498 if (text.EndsWith("-"))
499 throw ArgumentError ("An XML comment cannot contain \"--\" inside.");
500 else if (text.IndexOf("--") > 0)
501 throw ArgumentError ("An XML comment cannot end with \"-\".");
504 CloseStartElement ();
513 public override void WriteDocType (string name, string pubid, string sysid, string subset)
515 if (name == null || name.Trim (XmlChar.WhitespaceChars).Length == 0)
516 throw ArgumentError ("Invalid DOCTYPE name", "name");
518 if (ws == WriteState.Prolog && formatting == Formatting.Indented)
521 w.Write ("<!DOCTYPE ");
524 w.Write (" PUBLIC ");
532 } else if (sysid != null) {
533 w.Write (" SYSTEM ");
539 if (subset != null) {
548 public override void WriteEndAttribute ()
551 throw InvalidOperationError ("Token EndAttribute in state Start would result in an invalid XML document.");
558 ((XmlTextWriterOpenElement) openElements [openElementCount - 1]).XmlLang = xmlLang;
563 if (xmlSpace == XmlSpace.Preserve)
564 w.Write ("preserve");
565 else if (xmlSpace == XmlSpace.Default)
567 openXmlSpace = false;
568 ((XmlTextWriterOpenElement) openElements [openElementCount - 1]).XmlSpace = xmlSpace;
573 openAttribute = false;
575 if (saveAttributeValue) {
576 if (savedAttributePrefix.Length > 0 && savingAttributeValue.Length == 0)
577 throw ArgumentError ("Cannot use prefix with an empty namespace.");
580 if (shouldAddSavedNsToManager) // not OLD one
581 namespaceManager.AddNamespace (savedAttributePrefix, savingAttributeValue);
582 userWrittenNamespaces [savedAttributePrefix] = savingAttributeValue;
583 saveAttributeValue = false;
584 savedAttributePrefix = String.Empty;
585 savingAttributeValue = String.Empty;
589 public override void WriteEndDocument ()
591 CloseOpenAttributeAndElements ();
594 throw ArgumentError ("This document does not have a root element.");
596 ws = WriteState.Start;
600 public override void WriteEndElement ()
602 WriteEndElementInternal (false);
605 private void WriteIndent ()
609 w.Write (newLineChars);
610 for (int i = 0; i < indentLevel; i++)
611 w.Write (indentChars);
614 private void WriteEndElementInternal (bool fullEndElement)
616 if (openElementCount == 0)
617 throw InvalidOperationError ("There was no XML start tag open.");
620 WriteEndAttribute ();
624 AddMissingElementXmlns ();
626 if (openStartElement) {
628 WriteEndAttribute ();
629 if (fullEndElement) {
631 if (!ParentIndentingOverriden)
634 XmlTextWriterOpenElement el = (XmlTextWriterOpenElement) openElements [openElementCount - 1];
635 if (el.Prefix != String.Empty) {
639 w.Write (el.LocalName);
645 openStartElement = false;
649 XmlTextWriterOpenElement el = (XmlTextWriterOpenElement) openElements [openElementCount - 1];
651 if (el.Prefix != String.Empty) {
655 w.Write (el.LocalName);
659 namespaceManager.PopScope();
662 public override void WriteEntityRef (string name)
665 WriteStringInternal (name, true);
669 public override void WriteFullEndElement ()
671 WriteEndElementInternal (true);
674 public override void WriteName (string name)
676 WriteNameInternal (name);
679 public override void WriteNmToken (string name)
681 WriteNmTokenInternal (name);
684 // LAMESPEC: It should reject such name that starts with "x" "m" "l" by XML specification, but
685 // in fact it is used to write XmlDeclaration in WriteNode() (and it is inevitable since
686 // WriteStartDocument() cannot specify encoding, while WriteNode() can write it).
687 public override void WriteProcessingInstruction (string name, string text)
689 if ((name == null) || (name == string.Empty))
690 throw ArgumentError ("Argument processing instruction name must not be null or empty.");
691 if (!XmlChar.IsName (name))
692 throw ArgumentError ("Invalid processing instruction name.");
693 if ((text.IndexOf("?>") > 0))
694 throw ArgumentError ("Processing instruction cannot contain \"?>\" as its value.");
697 CloseStartElement ();
707 public override void WriteQualifiedName (string localName, string ns)
709 if (!XmlChar.IsNCName (localName))
710 throw ArgumentError (String.Format ("Invalid local name '{0}'", localName));
714 CloseStartElement ();
716 // WriteQualifiedName internal will reject such
717 // qname whose namespace is not declared.
718 string prefix = null;
719 if (openAttribute && ns != String.Empty && LookupPrefix (ns) == null) {
720 prefix = CheckNewPrefix (true, null, ns);
721 namespaceManager.AddNamespace (prefix, ns);
724 WriteQualifiedNameInternal (localName, ns);
726 if (prefix != null) {
727 namespaceManager.RemoveNamespace (prefix, ns);
728 newAttributeNamespaces [prefix] = ns;
732 public override void WriteRaw (string data)
734 if (ws == WriteState.Start)
735 ws = WriteState.Prolog;
736 WriteStringInternal (data, false);
739 public override void WriteRaw (char[] buffer, int index, int count)
741 WriteRaw (new string (buffer, index, count));
744 public override void WriteStartAttribute (string prefix, string localName, string ns)
746 if (prefix == "xml") {
747 // MS.NET looks to allow other names than
748 // lang and space (e.g. xml:link, xml:hack).
749 ns = XmlNamespaceManager.XmlnsXml;
750 if (localName == "lang")
752 else if (localName == "space")
756 prefix = String.Empty;
758 if (prefix.Length > 0 && (ns == null || ns.Length == 0))
759 if (prefix != "xmlns")
760 throw ArgumentError ("Cannot use prefix with an empty namespace.");
762 if (prefix == "xmlns") {
763 if (localName == null || localName.Length == 0) {
765 prefix = String.Empty;
769 // Note that null namespace with "xmlns" are allowed.
771 if ((prefix == "xmlns" || localName == "xmlns" && prefix == String.Empty) && ns != XmlnsNamespace)
773 if ((prefix == "xmlns" || localName == "xmlns" && prefix == String.Empty) && ns != null && ns != XmlnsNamespace)
775 throw ArgumentError (String.Format ("The 'xmlns' attribute is bound to the reserved namespace '{0}'", XmlnsNamespace));
779 if (ws == WriteState.Content)
780 throw InvalidOperationError (String.Format ("Token StartAttribute in state {0} would result in an invalid XML document.", ws));
783 prefix = String.Empty;
788 string formatPrefix = "";
790 if (ns != String.Empty && prefix != "xmlns") {
791 string existingPrefix = namespaceManager.LookupPrefix (ns, false);
793 if (existingPrefix == null || existingPrefix == "") {
794 bool createPrefix = false;
798 string existingNs = namespaceManager.LookupNamespace (prefix, false);
799 if (existingNs != null) {
800 namespaceManager.RemoveNamespace (prefix, existingNs);
801 if (namespaceManager.LookupNamespace (prefix, false) != existingNs) {
803 namespaceManager.AddNamespace (prefix, existingNs);
808 prefix = CheckNewPrefix (createPrefix, prefix, ns);
811 if (prefix == String.Empty && ns != XmlnsNamespace)
812 prefix = (existingPrefix == null) ?
813 String.Empty : existingPrefix;
816 if (prefix != String.Empty)
818 formatPrefix = prefix + ":";
821 if (openStartElement || attributeWrittenForElement) {
822 if (newLineOnAttributes)
828 w.Write (formatPrefix);
833 openAttribute = true;
834 attributeWrittenForElement = true;
835 ws = WriteState.Attribute;
837 if (prefix == "xmlns" || prefix == String.Empty && localName == "xmlns") {
838 if (prefix != openElementPrefix || openElementNS == null)
839 shouldAddSavedNsToManager = true;
840 saveAttributeValue = true;
841 savedAttributePrefix = (prefix == "xmlns") ? localName : String.Empty;
842 savingAttributeValue = String.Empty;
846 private string CheckNewPrefix (bool createPrefix, string prefix, string ns)
850 prefix = "d" + indentLevel + "p" + (++autoCreatedPrefixes);
851 createPrefix = false;
852 // Check if prefix exists.
853 // If yes - check if namespace is the same.
854 if (newAttributeNamespaces [prefix] == null)
855 newAttributeNamespaces.Add (prefix, ns);
856 else if (!newAttributeNamespaces [prefix].Equals (ns))
858 } while (createPrefix);
862 public override void WriteStartDocument ()
864 WriteStartDocument ("");
867 public override void WriteStartDocument (bool standalone)
869 string standaloneFormatting;
871 if (standalone == true)
872 standaloneFormatting = String.Format (" standalone={0}yes{0}", quoteChar);
874 standaloneFormatting = String.Format (" standalone={0}no{0}", quoteChar);
876 WriteStartDocument (standaloneFormatting);
879 private void WriteStartDocument (string standaloneFormatting)
881 if (documentStarted == true)
882 throw InvalidOperationError ("WriteStartDocument should be the first call.");
885 throw XmlError ("WriteStartDocument called twice.");
886 isDocumentEntity = true;
891 string encodingFormatting = "";
894 encodingFormatting = String.Format (" encoding={0}{1}{0}", quoteChar, w.Encoding.WebName);
896 w.Write("<?xml version={0}1.0{0}{1}{2}?>", quoteChar, encodingFormatting, standaloneFormatting);
897 ws = WriteState.Prolog;
900 public override void WriteStartElement (string prefix, string localName, string ns)
902 if (!Namespaces && (((prefix != null) && (prefix != String.Empty))
903 || ((ns != null) && (ns != String.Empty))))
904 throw ArgumentError ("Cannot set the namespace if Namespaces is 'false'.");
905 if ((prefix != null && prefix != String.Empty) && ((ns == null) || (ns == String.Empty)))
906 throw ArgumentError ("Cannot use a prefix with an empty namespace.");
908 // ignore non-namespaced node's prefix.
909 if (ns == null || ns == String.Empty)
910 prefix = String.Empty;
913 WriteStartElementInternal (prefix, localName, ns);
916 private void WriteStartElementInternal (string prefix, string localName, string ns)
920 CloseStartElement ();
921 newAttributeNamespaces.Clear ();
922 userWrittenNamespaces.Clear ();
923 shouldCheckElementXmlns = false;
925 if (prefix == null && ns != null)
926 prefix = namespaceManager.LookupPrefix (ns, false);
928 prefix = String.Empty;
932 if (prefix != String.Empty) {
938 if (openElements.Count == openElementCount)
939 openElements.Add (new XmlTextWriterOpenElement (prefix, localName));
941 ((XmlTextWriterOpenElement) openElements [openElementCount]).Reset (prefix, localName);
943 ws = WriteState.Element;
944 openStartElement = true;
946 openElementPrefix = prefix;
948 namespaceManager.PushScope ();
953 string existing = LookupPrefix (ns);
954 if (existing != prefix) {
955 shouldCheckElementXmlns = true;
956 namespaceManager.AddNamespace (prefix, ns);
959 if (ns != namespaceManager.DefaultNamespace) {
960 shouldCheckElementXmlns = true;
961 namespaceManager.AddNamespace ("", ns);
967 public override void WriteString (string text)
970 case WriteState.Start:
971 case WriteState.Prolog:
972 if (isDocumentEntity)
973 throw InvalidOperationError ("Token content in state Prolog would result in an invalid XML document.");
974 ws = WriteState.Content;
978 WriteStringInternal (text, true);
980 // MS.NET (1.0) saves attribute value only at WriteString.
981 if (saveAttributeValue)
982 // In most cases it will be called one time, so simply use string + string.
983 savingAttributeValue += text;
986 string [] replacements = new string [] {
987 "&", "<", ">", """, "'",
990 private string EscapeString (string source, bool outsideAttribute)
994 int count = source.Length;
996 for (int i = 0; i < count; i++) {
997 switch (source [i]) {
998 case '&': pos = 0; break;
999 case '<': pos = 1; break;
1000 case '>': pos = 2; break;
1002 if (outsideAttribute) continue;
1003 if (QuoteChar == '\'') continue;
1006 if (outsideAttribute) continue;
1007 if (QuoteChar == '\"') continue;
1010 if (outsideAttribute)
1014 if (outsideAttribute)
1018 if (XmlChar.IsInvalid (source [i])) {
1019 if (Char.IsSurrogate (source [i]) && source [i] < 0xDC00 &&
1020 i + 1 < count && Char.IsSurrogate (source [i + 1]) && source [i + 1] >= 0xDC00) {
1021 // A legitimate UTF-16 surrogate pair; let it through.
1025 if (checkCharacters)
1026 throw ArgumentError (String.Format ("Character hexadecimal value {0:4x} is invalid.", (int) source [i]));
1027 invalid = source [i];
1035 if (cachedStringBuilder == null)
1036 cachedStringBuilder = new StringBuilder ();
1037 cachedStringBuilder.Append (source.Substring (start, i - start));
1039 cachedStringBuilder.Append ("&#x");
1040 // if (invalid < (char) 255)
1041 // cachedStringBuilder.Append (((int) invalid).ToString ("X02", CultureInfo.InvariantCulture));
1043 // cachedStringBuilder.Append (((int) invalid).ToString ("X04", CultureInfo.InvariantCulture));
1044 cachedStringBuilder.Append (((int) invalid).ToString ("X", CultureInfo.InvariantCulture));
1045 cachedStringBuilder.Append (";");
1048 else if (outsideAttribute && pos >= 5) {
1049 cachedStringBuilder.Append (newLineChars);
1050 // all \r,\n,\r\n are replaced with
1051 // NewLineChars, so \n after \r should
1052 // be consumed here.
1053 if (pos == 5 && i + 1 < count && source [i + 1] == '\n')
1058 cachedStringBuilder.Append (replacements [pos]);
1063 else if (start < count)
1064 cachedStringBuilder.Append (source.Substring (start, count - start));
1065 string s = cachedStringBuilder.ToString ();
1066 cachedStringBuilder.Length = 0;
1070 private void WriteStringInternal (string text, bool entitize)
1073 text = String.Empty;
1075 if (text != String.Empty) {
1079 text = EscapeString (text, !openAttribute);
1083 IndentingOverriden = true;
1084 CloseStartElement ();
1087 if (!openXmlLang && !openXmlSpace)
1098 xmlSpace = XmlSpace.Default;
1101 xmlSpace = XmlSpace.Preserve;
1104 throw ArgumentError ("'{0}' is an invalid xml:space value.");
1111 public override void WriteSurrogateCharEntity (char lowChar, char highChar)
1113 if (lowChar < '\uDC00' || lowChar > '\uDFFF' ||
1114 highChar < '\uD800' || highChar > '\uDBFF')
1115 throw ArgumentError ("Invalid (low, high) pair of characters was specified.");
1119 if (!openAttribute) {
1120 IndentingOverriden = true;
1121 CloseStartElement ();
1125 w.Write (((int) ((highChar - 0xD800) * 0x400 + (lowChar - 0xDC00) + 0x10000)).ToString ("X", CultureInfo.InvariantCulture));
1129 public override void WriteWhitespace (string ws)
1131 if (!XmlChar.IsWhitespace (ws))
1132 throw ArgumentError ("Invalid Whitespace");
1136 if (!openAttribute) {
1137 IndentingOverriden = true;
1138 CloseStartElement ();
1144 private Exception ArgumentError (string message)
1147 ws = WriteState.Error;
1149 return new ArgumentException (message);
1152 private Exception ArgumentError (string message, string name)
1155 ws = WriteState.Error;
1157 return new ArgumentException (message);
1160 private Exception InvalidOperationError (string message)
1163 ws = WriteState.Error;
1165 return new InvalidOperationException (message);
1168 private Exception XmlError (string message)
1171 ws = WriteState.Error;
1173 return new XmlException (message);