2 // System.Xml.XmlWriter
5 // Kral Ferch <kral_ferch@hotmail.com>
6 // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
9 // (C) 2002-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.
37 using System.Xml.XPath;
43 public abstract class XmlWriter : IDisposable
45 public abstract class XmlWriter
49 XmlWriterSettings settings;
54 protected XmlWriter () { }
61 public virtual XmlWriterSettings Settings {
64 settings = new XmlWriterSettings ();
70 public abstract WriteState WriteState { get; }
74 public virtual string XmlLang {
78 public virtual XmlSpace XmlSpace {
79 get { return XmlSpace.None; }
82 public abstract string XmlLang { get; }
84 public abstract XmlSpace XmlSpace { get; }
91 public abstract void Close ();
94 public static XmlWriter Create (Stream stream)
96 return Create (stream, null);
99 public static XmlWriter Create (string file)
101 return Create (file, null);
104 public static XmlWriter Create (TextWriter writer)
106 return Create (writer, null);
109 public static XmlWriter Create (XmlWriter writer)
111 return Create (writer, null);
114 public static XmlWriter Create (StringBuilder builder)
116 return Create (builder, null);
119 public static XmlWriter Create (Stream stream, XmlWriterSettings settings)
121 Encoding enc = settings != null ? settings.Encoding : Encoding.UTF8;
122 return Create (new StreamWriter (stream, enc), settings);
125 public static XmlWriter Create (string file, XmlWriterSettings settings)
127 Encoding enc = settings != null ? settings.Encoding : Encoding.UTF8;
128 return CreateTextWriter (new StreamWriter (file, false, enc), settings, true);
131 public static XmlWriter Create (StringBuilder builder, XmlWriterSettings settings)
133 return Create (new StringWriter (builder), settings);
136 public static XmlWriter Create (TextWriter writer, XmlWriterSettings settings)
138 if (settings == null)
139 settings = new XmlWriterSettings ();
140 return CreateTextWriter (writer, settings, settings.CloseOutput);
143 public static XmlWriter Create (XmlWriter writer, XmlWriterSettings settings)
145 if (settings == null)
146 settings = new XmlWriterSettings ();
147 writer.settings = settings;
151 private static XmlWriter CreateTextWriter (TextWriter writer, XmlWriterSettings settings, bool closeOutput)
153 if (settings == null)
154 settings = new XmlWriterSettings ();
155 XmlTextWriter xtw = new XmlTextWriter (writer, settings, closeOutput);
156 return Create (xtw, settings);
159 protected virtual void Dispose (bool disposing)
164 void IDisposable.Dispose ()
170 public abstract void Flush ();
172 public abstract string LookupPrefix (string ns);
174 private void WriteAttribute (XmlReader reader, bool defattr)
176 if (!defattr && reader.IsDefault)
179 WriteStartAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
180 while (reader.ReadAttributeValue ()) {
181 switch (reader.NodeType) {
182 case XmlNodeType.Text:
183 WriteString (reader.Value);
185 case XmlNodeType.EntityReference:
186 WriteEntityRef (reader.Name);
190 WriteEndAttribute ();
193 public virtual void WriteAttributes (XmlReader reader, bool defattr)
196 throw new ArgumentException("null XmlReader specified.", "reader");
198 switch (reader.NodeType) {
199 case XmlNodeType.XmlDeclaration:
200 WriteAttributeString ("version", reader ["version"]);
201 if (reader ["encoding"] != null)
202 WriteAttributeString ("encoding", reader ["encoding"]);
203 if (reader ["standalone"] != null)
204 WriteAttributeString ("standalone", reader ["standalone"]);
206 case XmlNodeType.Element:
207 if (reader.MoveToFirstAttribute ())
208 goto case XmlNodeType.Attribute;
210 case XmlNodeType.Attribute:
212 WriteAttribute (reader, defattr);
213 } while (reader.MoveToNextAttribute ());
214 reader.MoveToElement ();
217 throw new XmlException("NodeType is not one of Element, Attribute, nor XmlDeclaration.");
221 public void WriteAttributeString (string localName, string value)
223 WriteAttributeString ("", localName, null, value);
226 public void WriteAttributeString (string localName, string ns, string value)
228 WriteAttributeString ("", localName, ns, value);
231 public void WriteAttributeString (string prefix, string localName, string ns, string value)
233 // In MS.NET (1.0), this check is done *here*, not at WriteStartAttribute.
234 // (XmlTextWriter.WriteStartAttribute("xmlns", "anyname", null) throws an exception.
236 WriteStartAttribute (prefix, localName, ns);
237 if (value != null && value.Length > 0)
239 WriteEndAttribute ();
242 public abstract void WriteBase64 (byte[] buffer, int index, int count);
245 public virtual void WriteBinHex (byte [] buffer, int index, int count)
247 StringWriter sw = new StringWriter ();
248 XmlConvert.WriteBinHex (buffer, index, count, sw);
249 WriteString (sw.ToString ());
252 public abstract void WriteBinHex (byte[] buffer, int index, int count);
255 public abstract void WriteCData (string text);
257 public abstract void WriteCharEntity (char ch);
259 public abstract void WriteChars (char[] buffer, int index, int count);
261 public abstract void WriteComment (string text);
263 public abstract void WriteDocType (string name, string pubid, string sysid, string subset);
265 public void WriteElementString (string localName, string value)
267 WriteStartElement(localName);
268 if (value != null && value.Length > 0)
273 public void WriteElementString (string localName, string ns, string value)
275 WriteStartElement(localName, ns);
276 if (value != null && value.Length > 0)
282 public void WriteElementString (string prefix, string localName, string ns, string value)
284 WriteStartElement(prefix, localName, ns);
285 if (value != null && value.Length > 0)
291 public abstract void WriteEndAttribute ();
293 public abstract void WriteEndDocument ();
295 public abstract void WriteEndElement ();
297 public abstract void WriteEntityRef (string name);
299 public abstract void WriteFullEndElement ();
302 public virtual void WriteName (string name)
304 WriteNameInternal (name);
307 public virtual void WriteNmToken (string name)
309 WriteNmTokenInternal (name);
312 public virtual void WriteQualifiedName (string localName, string ns)
314 WriteQualifiedNameInternal (localName, ns);
317 public abstract void WriteName (string name);
319 public abstract void WriteNmToken (string name);
321 public abstract void WriteQualifiedName (string localName, string ns);
324 internal void WriteNameInternal (string name)
327 switch (Settings.ConformanceLevel) {
328 case ConformanceLevel.Document:
329 case ConformanceLevel.Fragment:
330 XmlConvert.VerifyName (name);
334 XmlConvert.VerifyName (name);
339 internal virtual void WriteNmTokenInternal (string name)
343 switch (Settings.ConformanceLevel) {
344 case ConformanceLevel.Document:
345 case ConformanceLevel.Fragment:
346 valid = XmlChar.IsNmToken (name);
350 valid = XmlChar.IsNmToken (name);
353 throw new ArgumentException ("Argument name is not a valid NMTOKEN.");
357 internal void WriteQualifiedNameInternal (string localName, string ns)
359 if (localName == null || localName == String.Empty)
360 throw new ArgumentException ();
365 switch (Settings.ConformanceLevel) {
366 case ConformanceLevel.Document:
367 case ConformanceLevel.Fragment:
368 XmlConvert.VerifyNCName (localName);
372 XmlConvert.VerifyNCName (localName);
375 string prefix = ns.Length > 0 ? LookupPrefix (ns) : String.Empty;
377 throw new ArgumentException (String.Format ("Namespace '{0}' is not declared.", ns));
379 if (prefix != String.Empty) {
380 WriteString (prefix);
382 WriteString (localName);
385 WriteString (localName);
389 [MonoTODO] // FIXME: test defattr handling
390 public virtual void WriteNode (XPathNavigator navigator, bool defattr)
392 if (navigator == null)
393 throw new ArgumentNullException ("navigator");
394 switch (navigator.NodeType) {
395 case XPathNodeType.Attribute:
396 case XPathNodeType.Namespace:
397 if (defattr || navigator.SchemaInfo == null ||
398 !navigator.SchemaInfo.IsDefault)
399 WriteAttributeString (navigator.Prefix,
401 navigator.NamespaceURI,
404 case XPathNodeType.Text:
405 WriteString (navigator.Value);
407 case XPathNodeType.SignificantWhitespace:
408 WriteWhitespace (navigator.Value);
410 case XPathNodeType.Whitespace:
411 WriteWhitespace (navigator.Value);
413 case XPathNodeType.Comment:
414 WriteComment (navigator.Value);
416 case XPathNodeType.ProcessingInstruction:
417 WriteProcessingInstruction (navigator.Name, navigator.Value);
419 case XPathNodeType.Root:
420 if (navigator.MoveToFirstChild ()) {
422 WriteNode (navigator, defattr);
423 } while (navigator.MoveToNext ());
424 navigator.MoveToParent ();
427 case XPathNodeType.Element:
428 WriteStartElement (navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
429 if (navigator.MoveToFirstNamespace (XPathNamespaceScope.Local)) {
431 WriteNode (navigator, defattr);
432 } while (navigator.MoveToNextNamespace (XPathNamespaceScope.Local));
433 navigator.MoveToParent ();
435 if (navigator.MoveToFirstAttribute ()) {
437 WriteNode (navigator, defattr);
438 } while (navigator.MoveToNextAttribute ());
439 navigator.MoveToParent ();
441 if (navigator.MoveToFirstChild ()) {
443 WriteNode (navigator, defattr);
444 } while (navigator.MoveToNext ());
445 navigator.MoveToParent ();
447 if (navigator.IsEmptyElement)
450 WriteFullEndElement ();
453 throw new NotSupportedException ();
458 public virtual void WriteNode (XmlReader reader, bool defattr)
461 throw new ArgumentException ();
463 if (reader.ReadState == ReadState.Initial) {
466 WriteNode (reader, defattr);
467 } while (!reader.EOF);
471 switch (reader.NodeType) {
472 case XmlNodeType.Element:
473 WriteStartElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
475 WriteAttributes (reader, defattr);
476 reader.MoveToElement ();
478 // Well, I found that MS.NET took this way, since
479 // there was a error-prone SgmlReader that fails
480 // MoveToNextAttribute().
481 if (reader.HasAttributes) {
482 for (int i = 0; i < reader.AttributeCount; i++) {
483 reader.MoveToAttribute (i);
484 WriteAttribute (reader, defattr);
486 reader.MoveToElement ();
489 if (reader.IsEmptyElement)
492 int depth = reader.Depth;
494 if (reader.NodeType != XmlNodeType.EndElement) {
496 WriteNode (reader, defattr);
497 } while (depth < reader.Depth);
499 WriteFullEndElement ();
502 // In case of XmlAttribute, don't proceed reader, and it will never be written.
503 case XmlNodeType.Attribute:
505 case XmlNodeType.Text:
506 WriteString (reader.Value);
508 case XmlNodeType.CDATA:
509 WriteCData (reader.Value);
511 case XmlNodeType.EntityReference:
512 WriteEntityRef (reader.Name);
514 case XmlNodeType.XmlDeclaration:
515 // LAMESPEC: It means that XmlWriter implementation _must not_ check
516 // whether PI name is "xml" (it is XML error) or not.
517 case XmlNodeType.ProcessingInstruction:
518 WriteProcessingInstruction (reader.Name, reader.Value);
520 case XmlNodeType.Comment:
521 WriteComment (reader.Value);
523 case XmlNodeType.DocumentType:
524 WriteDocType (reader.Name,
525 reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
527 case XmlNodeType.SignificantWhitespace:
528 goto case XmlNodeType.Whitespace;
529 case XmlNodeType.Whitespace:
530 WriteWhitespace (reader.Value);
532 case XmlNodeType.EndElement:
533 WriteFullEndElement ();
535 case XmlNodeType.EndEntity:
537 case XmlNodeType.None:
538 break; // Do nothing, nor reporting errors.
540 throw new XmlException ("Unexpected node " + reader.Name + " of type " + reader.NodeType);
545 public abstract void WriteProcessingInstruction (string name, string text);
547 public abstract void WriteRaw (string data);
549 public abstract void WriteRaw (char[] buffer, int index, int count);
552 public void WriteStartAttribute (string localName)
554 WriteStartAttribute (null, localName, null);
558 public void WriteStartAttribute (string localName, string ns)
560 WriteStartAttribute (null, localName, ns);
563 public abstract void WriteStartAttribute (string prefix, string localName, string ns);
565 public abstract void WriteStartDocument ();
567 public abstract void WriteStartDocument (bool standalone);
569 public void WriteStartElement (string localName)
571 WriteStartElement (null, localName, null);
574 public void WriteStartElement (string localName, string ns)
576 WriteStartElement (null, localName, ns);
579 public abstract void WriteStartElement (string prefix, string localName, string ns);
581 public abstract void WriteString (string text);
583 public abstract void WriteSurrogateCharEntity (char lowChar, char highChar);
585 public abstract void WriteWhitespace (string ws);
589 public virtual void WriteValue (bool value)
591 WriteString (XQueryConvert.BooleanToString (value));
595 public virtual void WriteValue (DateTime value)
597 WriteString (XmlConvert.ToString (value));
601 public virtual void WriteValue (decimal value)
603 WriteString (XQueryConvert.DecimalToString (value));
607 public virtual void WriteValue (double value)
609 WriteString (XQueryConvert.DoubleToString (value));
613 public virtual void WriteValue (int value)
615 WriteString (XQueryConvert.IntToString (value));
619 public virtual void WriteValue (long value)
621 WriteString (XQueryConvert.IntegerToString (value));
625 public virtual void WriteValue (object value)
628 WriteString ((string) value);
629 else if (value is bool)
630 WriteValue ((bool) value);
631 else if (value is DateTime)
632 WriteValue ((DateTime) value);
633 else if (value is decimal)
634 WriteValue ((decimal) value);
635 else if (value is double)
636 WriteValue ((double) value);
637 else if (value is int)
638 WriteValue ((int) value);
639 else if (value is long)
640 WriteValue ((long) value);
641 else if (value is XmlQualifiedName) {
642 XmlQualifiedName qname = (XmlQualifiedName) value;
643 WriteQualifiedName (qname.Name, qname.Namespace);
646 throw new NotImplementedException ("Argument value is " + value);
650 public virtual void WriteValue (float value)
652 WriteString (XQueryConvert.FloatToString (value));
656 public virtual void WriteValue (string value)