2 // XmlDictionaryWriter.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 public abstract partial class XmlDictionaryWriter : XmlWriter
36 static readonly Encoding utf8_unmarked = new UTF8Encoding (false);
38 protected XmlDictionaryWriter ()
42 internal int Depth { get; set; }
44 internal int NSIndex { get; set; }
46 public virtual bool CanCanonicalize {
50 public static XmlDictionaryWriter CreateBinaryWriter (
53 return CreateBinaryWriter (stream, null, null, false);
56 public static XmlDictionaryWriter CreateBinaryWriter (
57 Stream stream, IXmlDictionary dictionary)
59 return CreateBinaryWriter (stream, dictionary, null, false);
62 public static XmlDictionaryWriter CreateBinaryWriter (
63 Stream stream, IXmlDictionary dictionary,
64 XmlBinaryWriterSession session)
66 return CreateBinaryWriter (stream, dictionary, session, false);
69 public static XmlDictionaryWriter CreateBinaryWriter (
70 Stream stream, IXmlDictionary dictionary,
71 XmlBinaryWriterSession session, bool ownsStream)
73 return new XmlBinaryDictionaryWriter (stream,
74 dictionary, session, ownsStream);
77 public static XmlDictionaryWriter CreateDictionaryWriter (XmlWriter writer)
79 return new XmlSimpleDictionaryWriter (writer);
82 public static XmlDictionaryWriter CreateMtomWriter (
83 Stream stream, Encoding encoding, int maxSizeInBytes,
86 return CreateMtomWriter (stream, encoding,
87 maxSizeInBytes, startInfo, Guid.NewGuid () + "id=1", "http://tempuri.org/0/" + DateTime.Now.Ticks, true, false);
90 public static XmlDictionaryWriter CreateMtomWriter (
91 Stream stream, Encoding encoding, int maxSizeInBytes,
92 string startInfo, string boundary, string startUri,
93 bool writeMessageHeaders, bool ownsStream)
95 return new XmlMtomDictionaryWriter (stream, encoding, maxSizeInBytes, startInfo, boundary, startUri, writeMessageHeaders, ownsStream);
98 public static XmlDictionaryWriter CreateTextWriter (
101 return CreateTextWriter (stream, Encoding.UTF8);
104 public static XmlDictionaryWriter CreateTextWriter (
105 Stream stream, Encoding encoding)
107 return CreateTextWriter (stream, encoding, false);
110 // BTW looks like it creates an instance of different
111 // implementation than those from XmlWriter.Create().
112 public static XmlDictionaryWriter CreateTextWriter (
113 Stream stream, Encoding encoding, bool ownsStream)
116 throw new ArgumentNullException ("stream");
117 if (encoding == null)
118 throw new ArgumentNullException ("encoding");
120 switch (encoding.CodePage) {
124 encoding = utf8_unmarked;
127 throw new XmlException (String.Format ("XML declaration is required for encoding code page {0} but this XmlWriter does not support XML declaration.", encoding.CodePage));
130 XmlWriterSettings s = new XmlWriterSettings ();
131 s.Encoding = encoding;
132 s.CloseOutput = ownsStream;
133 s.OmitXmlDeclaration = true;
134 return CreateDictionaryWriter (XmlWriter.Create (stream, s));
139 public virtual void EndCanonicalization ()
141 throw new NotSupportedException ();
144 public virtual void StartCanonicalization (
145 Stream stream, bool includeComments,
146 string [] inclusivePrefixes)
148 throw new NotSupportedException ();
151 public void WriteAttributeString (
152 XmlDictionaryString localName,
153 XmlDictionaryString namespaceUri,
156 WriteAttributeString (null, localName, namespaceUri, value);
159 public void WriteAttributeString (string prefix,
160 XmlDictionaryString localName,
161 XmlDictionaryString namespaceUri,
164 WriteStartAttribute (prefix, localName, namespaceUri);
166 WriteEndAttribute ();
169 public void WriteElementString (
170 XmlDictionaryString localName,
171 XmlDictionaryString namespaceUri,
174 WriteElementString (null, localName, namespaceUri, value);
177 public void WriteElementString (string prefix,
178 XmlDictionaryString localName,
179 XmlDictionaryString namespaceUri,
182 WriteStartElement (prefix, localName, namespaceUri);
187 public virtual void WriteNode (XmlDictionaryReader reader,
191 throw new ArgumentNullException ("reader");
193 if (reader.ReadState == ReadState.Initial)
196 switch (reader.NodeType) {
197 case XmlNodeType.Element:
198 // gratuitously copied from System.XML/System.Xml/XmlWriter.cs:WriteNode(XmlReader,bool)
199 // as there doesn't seem to be a way to hook into attribute writing w/o handling Element.
200 XmlDictionaryString ename, ens;
201 if (reader.TryGetLocalNameAsDictionaryString (out ename) && reader.TryGetLocalNameAsDictionaryString (out ens))
202 WriteStartElement (reader.Prefix, ename, ens);
204 WriteStartElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
205 // Well, I found that MS.NET took this way, since
206 // there was a error-prone SgmlReader that fails
207 // MoveToNextAttribute().
208 if (reader.HasAttributes) {
209 for (int i = 0; i < reader.AttributeCount; i++) {
210 reader.MoveToAttribute (i);
211 WriteAttribute (reader, defattr);
213 reader.MoveToElement ();
215 if (reader.IsEmptyElement)
218 int depth = reader.Depth;
220 if (reader.NodeType != XmlNodeType.EndElement) {
222 WriteNode (reader, defattr);
223 } while (depth < reader.Depth);
225 WriteFullEndElement ();
229 case XmlNodeType.Attribute:
230 case XmlNodeType.Text:
231 WriteTextNode (reader, defattr);
234 base.WriteNode (reader, defattr);
239 private void WriteAttribute (XmlDictionaryReader reader, bool defattr)
241 if (!defattr && reader.IsDefault)
244 XmlDictionaryString name, ns;
245 if (reader.TryGetLocalNameAsDictionaryString (out name) && reader.TryGetLocalNameAsDictionaryString (out ns))
246 WriteStartAttribute (reader.Prefix, name, ns);
248 WriteStartAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
250 // no ReadAttributeValue() in 2.1 profile.
251 WriteTextNode (reader, true);
253 while (reader.ReadAttributeValue ()) {
254 switch (reader.NodeType) {
255 case XmlNodeType.Text:
256 WriteTextNode (reader, true);
258 case XmlNodeType.EntityReference:
259 WriteEntityRef (reader.Name);
264 WriteEndAttribute ();
267 public override void WriteNode (XmlReader reader, bool defattr)
270 throw new ArgumentNullException ("reader");
272 XmlDictionaryReader dr = reader as XmlDictionaryReader;
274 WriteNode (dr, defattr);
276 base.WriteNode (reader, defattr);
279 public virtual void WriteQualifiedName (
280 XmlDictionaryString localName,
281 XmlDictionaryString namespaceUri)
283 WriteQualifiedName (localName.Value, namespaceUri.Value);
286 public void WriteStartAttribute (
287 XmlDictionaryString localName,
288 XmlDictionaryString namespaceUri)
290 WriteStartAttribute (localName.Value, namespaceUri.Value);
293 public virtual void WriteStartAttribute (string prefix,
294 XmlDictionaryString localName,
295 XmlDictionaryString namespaceUri)
297 WriteStartAttribute (prefix, localName.Value, namespaceUri.Value);
300 public void WriteStartElement (
301 XmlDictionaryString localName,
302 XmlDictionaryString namespaceUri)
304 WriteStartElement (null, localName, namespaceUri);
307 public virtual void WriteStartElement (string prefix,
308 XmlDictionaryString localName,
309 XmlDictionaryString namespaceUri)
311 if (localName == null)
312 throw new ArgumentException ("localName must not be null.", "localName");
313 WriteStartElement (prefix, localName.Value,
314 namespaceUri != null ? namespaceUri.Value : null);
317 public virtual void WriteString (XmlDictionaryString value)
319 WriteString (value.Value);
322 protected virtual void WriteTextNode (XmlDictionaryReader reader, bool isAttribute)
324 WriteString (reader.Value);
329 public virtual void WriteValue (Guid guid)
331 WriteString (guid.ToString ());
334 public virtual void WriteValue (IStreamProvider value)
337 throw new ArgumentNullException ("value");
339 Stream stream = value.GetStream ();
340 byte[] buf = new byte [Math.Min (2048, stream.CanSeek ? stream.Length : 2048)];
342 while ((read = stream.Read (buf, 0, buf.Length)) > 0) {
343 WriteBase64 (buf, 0, read);
345 value.ReleaseStream (stream);
348 public virtual void WriteValue (TimeSpan duration)
350 WriteString (XmlConvert.ToString (duration));
353 public virtual void WriteValue (UniqueId id)
356 throw new ArgumentNullException ("id");
357 WriteString (id.ToString ());
360 public virtual void WriteValue (XmlDictionaryString value)
362 WriteValue (value.Value);
365 public virtual void WriteXmlAttribute (string localName, string value)
367 WriteAttributeString ("xml", localName, "http://www.w3.org/XML/1998/namespace", value);
370 public virtual void WriteXmlAttribute (XmlDictionaryString localName,
371 XmlDictionaryString value)
373 WriteXmlAttribute (localName.Value, value.Value);
376 public virtual void WriteXmlnsAttribute (
377 string prefix, string namespaceUri)
379 // BTW .NET 2.0 those XmlWriters from XmlWrite.Create()
380 // rejects namespace overriding i.e.
382 // xw.WriteStartElement ("foo", "urn:foo");
383 // xw.WriteXmlnsAttribute ("foo", "urn:bar");
385 // causes an XmlException. We need fix in sys.xml.dll
387 // When the prefix is null, this writer must mock
388 // a dummy namespace up. It is then up to the actual
389 // writer how it is determined in the output. (When
390 // there is a duplicate, then it will be further
392 if (prefix == null && String.IsNullOrEmpty (namespaceUri))
393 prefix = String.Empty;
394 else if (prefix == null)
395 prefix = "d" + Depth + "p" + (++NSIndex);
397 if (prefix == String.Empty)
398 WriteAttributeString ("xmlns", namespaceUri);
400 WriteAttributeString ("xmlns", prefix, "http://www.w3.org/2000/xmlns/", namespaceUri);
403 public virtual void WriteXmlnsAttribute (string prefix,
404 XmlDictionaryString namespaceUri)
406 WriteXmlnsAttribute (prefix, namespaceUri.Value);