2 //------------------------------------------------------------------------------
3 // <copyright file="XmlWriter.cs" company="Microsoft">
4 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <owner current="true" primary="true">Microsoft</owner>
7 //------------------------------------------------------------------------------
13 using System
.Xml
.XPath
;
15 using System
.Xml
.Schema
;
16 using System
.Diagnostics
;
17 using System
.Collections
.Generic
;
18 using System
.Globalization
;
19 using System
.Runtime
.Versioning
;
21 namespace System
.Xml
{
23 // Specifies the state of the XmlWriter.
24 public enum WriteState
{
25 // Nothing has been written yet.
28 // Writing the prolog.
31 // Writing a the start tag for an element.
34 // Writing an attribute value.
37 // Writing element content.
40 // XmlWriter is closed; Close has been called.
43 // Writer is in error state.
47 // Represents a writer that provides fast non-cached forward-only way of generating XML streams containing XML documents
48 // that conform to the W3C Extensible Markup Language (XML) 1.0 specification and the Namespaces in XML specification.
49 public abstract partial class XmlWriter
: IDisposable
{
51 // Helper buffer for WriteNode(XmlReader, bool)
52 char[] writeNodeBuffer
;
55 const int WriteNodeBufferSize
= 1024;
57 // Returns the settings describing the features of the the writer. Returns null for V1 XmlWriters (XmlTextWriter).
58 public virtual XmlWriterSettings Settings
{
65 // Writes out the XML declaration with the version "1.0".
67 public abstract void WriteStartDocument();
69 //Writes out the XML declaration with the version "1.0" and the speficied standalone attribute.
71 public abstract void WriteStartDocument(bool standalone
);
73 //Closes any open elements or attributes and puts the writer back in the Start state.
75 public abstract void WriteEndDocument();
77 // Writes out the DOCTYPE declaration with the specified name and optional attributes.
79 public abstract void WriteDocType(string name
, string pubid
, string sysid
, string subset
);
81 // Writes out the specified start tag and associates it with the given namespace.
82 public void WriteStartElement(string localName
, string ns
) {
83 WriteStartElement(null, localName
, ns
);
86 // Writes out the specified start tag and associates it with the given namespace and prefix.
88 public abstract void WriteStartElement(string prefix
, string localName
, string ns
);
90 // Writes out a start tag with the specified local name with no namespace.
91 public void WriteStartElement(string localName
) {
92 WriteStartElement(null, localName
, (string)null);
95 // Closes one element and pops the corresponding namespace scope.
97 public abstract void WriteEndElement();
99 // Closes one element and pops the corresponding namespace scope. Writes out a full end element tag, e.g. </element>.
101 public abstract void WriteFullEndElement();
103 // Writes out the attribute with the specified LocalName, value, and NamespaceURI.
106 public void WriteAttributeString(string localName
, string ns
, string value) {
107 WriteStartAttribute(null, localName
, ns
);
112 // Writes out the attribute with the specified LocalName and value.
113 public void WriteAttributeString(string localName
, string value) {
114 WriteStartAttribute(null, localName
, (string)null);
119 // Writes out the attribute with the specified prefix, LocalName, NamespaceURI and value.
120 public void WriteAttributeString(string prefix
, string localName
, string ns
, string value) {
121 WriteStartAttribute(prefix
, localName
, ns
);
126 // Writes the start of an attribute.
127 public void WriteStartAttribute(string localName
, string ns
) {
128 WriteStartAttribute(null, localName
, ns
);
131 // Writes the start of an attribute.
133 public abstract void WriteStartAttribute(string prefix
, string localName
, string ns
);
135 // Writes the start of an attribute.
136 public void WriteStartAttribute(string localName
) {
137 WriteStartAttribute(null, localName
, (string)null);
140 // Closes the attribute opened by WriteStartAttribute call.
142 public abstract void WriteEndAttribute();
144 // Writes out a <![CDATA[...]]>; block containing the specified text.
146 public abstract void WriteCData(string text
);
148 // Writes out a comment <!--...-->; containing the specified text.
150 public abstract void WriteComment(string text
);
152 // Writes out a processing instruction with a space between the name and text as follows: <?name text?>
154 public abstract void WriteProcessingInstruction(string name
, string text
);
156 // Writes out an entity reference as follows: "&"+name+";".
158 public abstract void WriteEntityRef(string name
);
160 // Forces the generation of a character entity for the specified Unicode character value.
162 public abstract void WriteCharEntity(char ch
);
164 // Writes out the given whitespace.
166 public abstract void WriteWhitespace(string ws
);
168 // Writes out the specified text content.
170 public abstract void WriteString(string text
);
172 // Write out the given surrogate pair as an entity reference.
174 public abstract void WriteSurrogateCharEntity(char lowChar
, char highChar
);
176 // Writes out the specified text content.
178 public abstract void WriteChars(char[] buffer
, int index
, int count
);
180 // Writes raw markup from the given character buffer.
182 public abstract void WriteRaw(char[] buffer
, int index
, int count
);
184 // Writes raw markup from the given string.
186 public abstract void WriteRaw(string data
);
188 // Encodes the specified binary bytes as base64 and writes out the resulting text.
190 public abstract void WriteBase64(byte[] buffer
, int index
, int count
);
192 // Encodes the specified binary bytes as binhex and writes out the resulting text.
193 public virtual void WriteBinHex(byte[] buffer
, int index
, int count
) {
194 BinHexEncoder
.Encode(buffer
, index
, count
, this);
197 // Returns the state of the XmlWriter.
198 public abstract WriteState WriteState { get; }
200 // Closes the XmlWriter and the underlying stream/TextReader (if Settings.CloseOutput is true).
201 public virtual void Close() { }
203 // Flushes data that is in the internal buffers into the underlying streams/TextReader and flushes the stream/TextReader.
205 public abstract void Flush();
207 // Returns the closest prefix defined in the current namespace scope for the specified namespace URI.
208 public abstract string LookupPrefix(string ns
);
210 // Gets an XmlSpace representing the current xml:space scope.
211 public virtual XmlSpace XmlSpace
{
213 return XmlSpace
.Default
;
217 // Gets the current xml:lang scope.
218 public virtual string XmlLang
{
224 // Scalar Value Methods
226 // Writes out the specified name, ensuring it is a valid NmToken according to the XML specification
227 // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
228 public virtual void WriteNmToken(string name
) {
229 if (name
== null || name
.Length
== 0) {
230 throw new ArgumentException(Res
.GetString(Res
.Xml_EmptyName
));
232 WriteString(XmlConvert
.VerifyNMTOKEN(name
, ExceptionType
.ArgumentException
));
235 // Writes out the specified name, ensuring it is a valid Name according to the XML specification
236 // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
237 public virtual void WriteName(string name
) {
238 WriteString(XmlConvert
.VerifyQName(name
, ExceptionType
.ArgumentException
));
241 // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace.
242 public virtual void WriteQualifiedName(string localName
, string ns
) {
243 if (ns
!= null && ns
.Length
> 0) {
244 string prefix
= LookupPrefix(ns
);
245 if (prefix
== null) {
246 throw new ArgumentException(Res
.GetString(Res
.Xml_UndefNamespace
, ns
));
251 WriteString(localName
);
254 // Writes out the specified value.
255 public virtual void WriteValue(object value) {
257 throw new ArgumentNullException("value");
260 WriteString(XmlUntypedStringConverter
.Instance
.ToString(value, null));
262 WriteString(XmlUntypedConverter
.Untyped
.ToString(value, null));
266 // Writes out the specified value.
267 public virtual void WriteValue(string value) {
276 // Writes out the specified value.
277 public virtual void WriteValue(bool value) {
278 WriteString(XmlConvert
.ToString(value));
281 // Writes out the specified value.
282 public virtual void WriteValue(DateTime
value) {
283 WriteString(XmlConvert
.ToString(value, XmlDateTimeSerializationMode
.RoundtripKind
));
286 // Writes out the specified value.
287 public virtual void WriteValue(DateTimeOffset
value) {
288 // Under Win8P, WriteValue(DateTime) will invoke this overload, but custom writers
289 // might not have implemented it. This base implementation should call WriteValue(DateTime).
290 // The following conversion results in the same string as calling ToString with DateTimeOffset.
291 if (value.Offset
!= TimeSpan
.Zero
) {
292 WriteValue(value.LocalDateTime
);
295 WriteValue(value.UtcDateTime
);
299 // Writes out the specified value.
300 public virtual void WriteValue(double value) {
301 WriteString(XmlConvert
.ToString(value));
304 // Writes out the specified value.
305 public virtual void WriteValue(float value) {
306 WriteString(XmlConvert
.ToString(value));
309 // Writes out the specified value.
310 public virtual void WriteValue(decimal value) {
311 WriteString(XmlConvert
.ToString(value));
314 // Writes out the specified value.
315 public virtual void WriteValue(int value) {
316 WriteString(XmlConvert
.ToString(value));
319 // Writes out the specified value.
320 public virtual void WriteValue(long value) {
321 WriteString(XmlConvert
.ToString(value));
324 // XmlReader Helper Methods
326 // Writes out all the attributes found at the current position in the specified XmlReader.
327 public virtual void WriteAttributes(XmlReader reader
, bool defattr
) {
328 if (null == reader
) {
329 throw new ArgumentNullException("reader");
332 if (reader
.NodeType
== XmlNodeType
.Element
|| reader
.NodeType
== XmlNodeType
.XmlDeclaration
) {
333 if (reader
.MoveToFirstAttribute()) {
334 WriteAttributes(reader
, defattr
);
335 reader
.MoveToElement();
338 else if (reader
.NodeType
!= XmlNodeType
.Attribute
) {
339 throw new XmlException(Res
.Xml_InvalidPosition
, string.Empty
);
343 // we need to check both XmlReader.IsDefault and XmlReader.SchemaInfo.IsDefault.
344 // If either of these is true and defattr=false, we should not write the attribute out
345 if (defattr
|| !reader
.IsDefaultInternal
) {
346 WriteStartAttribute(reader
.Prefix
, reader
.LocalName
, reader
.NamespaceURI
);
347 while (reader
.ReadAttributeValue()) {
348 if (reader
.NodeType
== XmlNodeType
.EntityReference
) {
349 WriteEntityRef(reader
.Name
);
352 WriteString(reader
.Value
);
358 while (reader
.MoveToNextAttribute());
362 // Copies the current node from the given reader to the writer (including child nodes), and if called on an element moves the XmlReader
363 // to the corresponding end element.
364 public virtual void WriteNode(XmlReader reader
, bool defattr
) {
365 if (null == reader
) {
366 throw new ArgumentNullException("reader");
369 bool canReadChunk
= reader
.CanReadValueChunk
;
370 int d
= reader
.NodeType
== XmlNodeType
.None
? -1 : reader
.Depth
;
372 switch (reader
.NodeType
) {
373 case XmlNodeType
.Element
:
374 WriteStartElement(reader
.Prefix
, reader
.LocalName
, reader
.NamespaceURI
);
375 WriteAttributes(reader
, defattr
);
376 if (reader
.IsEmptyElement
) {
381 case XmlNodeType
.Text
:
383 if (writeNodeBuffer
== null) {
384 writeNodeBuffer
= new char[WriteNodeBufferSize
];
387 while ((read
= reader
.ReadValueChunk(writeNodeBuffer
, 0, WriteNodeBufferSize
)) > 0) {
388 this.WriteChars(writeNodeBuffer
, 0, read
);
393 WriteString(reader
.Value
);
397 case XmlNodeType
.Whitespace
:
398 case XmlNodeType
.SignificantWhitespace
:
400 WriteWhitespace(reader
.Value
);
403 case XmlNodeType
.CDATA
:
404 WriteCData(reader
.Value
);
406 case XmlNodeType
.EntityReference
:
407 WriteEntityRef(reader
.Name
);
409 case XmlNodeType
.XmlDeclaration
:
410 case XmlNodeType
.ProcessingInstruction
:
411 WriteProcessingInstruction(reader
.Name
, reader
.Value
);
413 case XmlNodeType
.DocumentType
:
414 WriteDocType(reader
.Name
, reader
.GetAttribute("PUBLIC"), reader
.GetAttribute("SYSTEM"), reader
.Value
);
417 case XmlNodeType
.Comment
:
418 WriteComment(reader
.Value
);
420 case XmlNodeType
.EndElement
:
421 WriteFullEndElement();
424 } while (reader
.Read() && (d
< reader
.Depth
|| (d
== reader
.Depth
&& reader
.NodeType
== XmlNodeType
.EndElement
)));
427 #if !SILVERLIGHT // Removing dependency on XPathNavigator
428 // Copies the current node from the given XPathNavigator to the writer (including child nodes).
429 public virtual void WriteNode(XPathNavigator navigator
, bool defattr
) {
430 if (navigator
== null) {
431 throw new ArgumentNullException("navigator");
435 navigator
= navigator
.Clone();
438 bool mayHaveChildren
= false;
439 XPathNodeType nodeType
= navigator
.NodeType
;
442 case XPathNodeType
.Element
:
443 WriteStartElement(navigator
.Prefix
, navigator
.LocalName
, navigator
.NamespaceURI
);
446 if (navigator
.MoveToFirstAttribute()) {
448 IXmlSchemaInfo schemaInfo
= navigator
.SchemaInfo
;
449 if (defattr
|| (schemaInfo
== null || !schemaInfo
.IsDefault
)) {
450 WriteStartAttribute(navigator
.Prefix
, navigator
.LocalName
, navigator
.NamespaceURI
);
451 // copy string value to writer
452 WriteString(navigator
.Value
);
455 } while (navigator
.MoveToNextAttribute());
456 navigator
.MoveToParent();
460 if (navigator
.MoveToFirstNamespace(XPathNamespaceScope
.Local
)) {
461 WriteLocalNamespaces(navigator
);
462 navigator
.MoveToParent();
464 mayHaveChildren
= true;
466 case XPathNodeType
.Attribute
:
467 // do nothing on root level attribute
469 case XPathNodeType
.Text
:
470 WriteString(navigator
.Value
);
472 case XPathNodeType
.SignificantWhitespace
:
473 case XPathNodeType
.Whitespace
:
474 WriteWhitespace(navigator
.Value
);
476 case XPathNodeType
.Root
:
477 mayHaveChildren
= true;
479 case XPathNodeType
.Comment
:
480 WriteComment(navigator
.Value
);
482 case XPathNodeType
.ProcessingInstruction
:
483 WriteProcessingInstruction(navigator
.LocalName
, navigator
.Value
);
485 case XPathNodeType
.Namespace
:
486 // do nothing on root level namespace
493 if (mayHaveChildren
) {
494 // If children exist, move down to next level
495 if (navigator
.MoveToFirstChild()) {
501 if (navigator
.NodeType
== XPathNodeType
.Element
) {
502 if (navigator
.IsEmptyElement
) {
506 WriteFullEndElement();
515 // The entire subtree has been copied
519 if (navigator
.MoveToNext()) {
520 // Found a sibling, so break to outer loop
524 // No siblings, so move up to previous level
526 navigator
.MoveToParent();
529 if (navigator
.NodeType
== XPathNodeType
.Element
)
530 WriteFullEndElement();
536 // Element Helper Methods
538 // Writes out an element with the specified name containing the specified string value.
539 public void WriteElementString(string localName
, String
value) {
540 WriteElementString(localName
, null, value);
543 // Writes out an attribute with the specified name, namespace URI and string value.
544 public void WriteElementString(string localName
, String ns
, String
value) {
545 WriteStartElement(localName
, ns
);
546 if (null != value && 0 != value.Length
) {
552 // Writes out an attribute with the specified name, namespace URI, and string value.
553 public void WriteElementString(string prefix
, String localName
, String ns
, String
value) {
554 WriteStartElement(prefix
, localName
, ns
);
555 if (null != value && 0 != value.Length
) {
561 public void Dispose() {
565 // Dispose the underline stream objects (calls Close on the XmlWriter)
566 protected virtual void Dispose(bool disposing
) {
567 if (disposing
&& WriteState
!= WriteState
.Closed
) {
572 #if !SILVERLIGHT // Removing dependency on XPathNavigator
573 // Copy local namespaces on the navigator's current node to the raw writer. The namespaces are returned by the navigator in reversed order.
574 // The recursive call reverses them back.
575 private void WriteLocalNamespaces(XPathNavigator nsNav
) {
576 string prefix
= nsNav
.LocalName
;
577 string ns
= nsNav
.Value
;
579 if (nsNav
.MoveToNextNamespace(XPathNamespaceScope
.Local
)) {
580 WriteLocalNamespaces(nsNav
);
583 if (prefix
.Length
== 0) {
584 WriteAttributeString(string.Empty
, "xmlns", XmlReservedNs
.NsXmlNs
, ns
);
587 WriteAttributeString("xmlns", prefix
, XmlReservedNs
.NsXmlNs
, ns
);
593 // Static methods for creating writers
596 // Creates an XmlWriter for writing into the provided file.
597 [ResourceConsumption(ResourceScope
.Machine
)]
598 [ResourceExposure(ResourceScope
.Machine
)]
599 public static XmlWriter
Create(string outputFileName
) {
600 return Create(outputFileName
, null);
603 // Creates an XmlWriter for writing into the provided file with the specified settings.
604 [ResourceConsumption(ResourceScope
.Machine
)]
605 [ResourceExposure(ResourceScope
.Machine
)]
606 public static XmlWriter
Create(string outputFileName
, XmlWriterSettings settings
) {
607 if (settings
== null) {
608 settings
= new XmlWriterSettings();
610 return settings
.CreateWriter(outputFileName
);
614 // Creates an XmlWriter for writing into the provided stream.
615 public static XmlWriter
Create(Stream output
) {
616 return Create(output
, null);
619 // Creates an XmlWriter for writing into the provided stream with the specified settings.
620 public static XmlWriter
Create(Stream output
, XmlWriterSettings settings
) {
621 if (settings
== null) {
622 settings
= new XmlWriterSettings();
624 return settings
.CreateWriter(output
);
627 // Creates an XmlWriter for writing into the provided TextWriter.
628 public static XmlWriter
Create(TextWriter output
) {
629 return Create(output
, null);
632 // Creates an XmlWriter for writing into the provided TextWriter with the specified settings.
633 public static XmlWriter
Create(TextWriter output
, XmlWriterSettings settings
) {
634 if (settings
== null) {
635 settings
= new XmlWriterSettings();
637 return settings
.CreateWriter(output
);
640 // Creates an XmlWriter for writing into the provided StringBuilder.
641 public static XmlWriter
Create(StringBuilder output
) {
642 return Create(output
, null);
645 // Creates an XmlWriter for writing into the provided StringBuilder with the specified settings.
646 public static XmlWriter
Create(StringBuilder output
, XmlWriterSettings settings
) {
647 if (settings
== null) {
648 settings
= new XmlWriterSettings();
650 if (output
== null) {
651 throw new ArgumentNullException("output");
653 return settings
.CreateWriter(new StringWriter(output
, CultureInfo
.InvariantCulture
));
656 // Creates an XmlWriter wrapped around the provided XmlWriter with the default settings.
657 public static XmlWriter
Create(XmlWriter output
) {
658 return Create(output
, null);
661 // Creates an XmlWriter wrapped around the provided XmlWriter with the specified settings.
662 public static XmlWriter
Create(XmlWriter output
, XmlWriterSettings settings
) {
663 if (settings
== null) {
664 settings
= new XmlWriterSettings();
666 return settings
.CreateWriter(output
);