5 // Copyright 2007 Novell (http://www.novell.com)
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 namespace System.Xml.Linq
32 internal class XNodeWriter : XmlWriter
34 public XNodeWriter (XContainer fragment)
37 state = XmlNodeType.None;
43 // If it is not null, then we are now inside the element.
45 // If it is not null, then we are now inside the attribute.
48 // None: started or closed.
49 // XmlDeclaration: after xmldecl. Never allow xmldecl.
50 // DocumentType: after doctype. Never allow xmldecl and doctype.
51 // Element: inside document element.
57 public override WriteState WriteState {
60 return WriteState.Closed;
61 if (attribute != null)
62 return WriteState.Attribute;
65 case XmlNodeType.None:
66 return WriteState.Start;
67 case XmlNodeType.XmlDeclaration:
68 return WriteState.Prolog;
69 case XmlNodeType.DocumentType:
70 return WriteState.Element;
72 return WriteState.Content;
78 public override string XmlLang {
80 for (XElement n = current as XElement; n != null; n = n.Parent as XElement)
81 if (n.HasAttribute ("xml:lang"))
82 return n.GetAttribute ("xml:lang");
87 public override XmlSpace XmlSpace {
89 for (XElement n = current as XElement; n != null; n = n.Parent as XElement) {
90 string xs = n.GetAttribute ("xml:space");
93 return XmlSpace.Preserve;
95 return XmlSpace.Default;
99 throw new InvalidOperationException (String.Format ("Invalid xml:space {0}.", xs));
102 return XmlSpace.None;
112 throw new InvalidOperationException ();
116 void WritePossiblyTopLevelNode (XNode n, bool possiblyAttribute)
119 if (!possiblyAttribute && attribute != null)
120 throw new InvalidOperationException (String.Format ("Current state is not acceptable for {0}.", n.NodeType));
122 if (state != XmlNodeType.Element)
124 else if (attribute != null)
125 attribute.Value += XUtil.ToString (n);
128 if (state == XmlNodeType.None)
129 state = XmlNodeType.XmlDeclaration;
132 // unlike other XmlWriters the callers must set xmlns
133 // attribute to overwrite prefix.
134 void FillXmlns (XElement el, string prefix, XNamespace xns)
136 if (xns == XNamespace.Xmlns)
137 // do nothing for xmlns attributes
142 if (xns == XNamespace.None)
143 if (el.GetPrefixOfNamespace (xns) != prefix)
144 el.SetAttributeValue (prefix == String.Empty ? XNamespace.None.GetName ("xmlns") : XNamespace.Xmlns.GetName (prefix), xns.NamespaceName);
145 else if (el.GetDefaultNamespace () != XNamespace.None)
146 el.SetAttributeValue (XNamespace.None.GetName ("xmlns"), xns.NamespaceName);
151 public override void Close ()
157 public override void Flush ()
161 public override string LookupPrefix (string ns)
165 throw new InvalidOperationException ();
166 XElement el = (current as XElement) ?? current.Parent;
167 return el != null ? el.GetPrefixOfNamespace (XNamespace.Get (ns)) : null;
172 public override void WriteStartDocument ()
174 WriteStartDocument (null);
177 public override void WriteStartDocument (bool standalone)
179 WriteStartDocument (standalone ? "yes" : "no");
182 void WriteStartDocument (string sddecl)
185 if (state != XmlNodeType.None)
186 throw new InvalidOperationException ("Current state is not acceptable for xmldecl.");
187 XDocument doc = current as XDocument;
189 throw new InvalidOperationException ("Only document node can accept xml declaration");
191 doc.Declaration = new XDeclaration ("1.0", null, sddecl);
192 state = XmlNodeType.XmlDeclaration;
197 public override void WriteEndDocument ()
205 public override void WriteDocType (string name, string publicId, string systemId, string internalSubset)
209 case XmlNodeType.None:
210 case XmlNodeType.XmlDeclaration:
211 XDocument doc = current as XDocument;
213 throw new InvalidOperationException ("Only document node can accept doctype declaration");
214 doc.Add (new XDocumentType (name, publicId, systemId, internalSubset));
215 state = XmlNodeType.DocumentType;
218 throw new InvalidOperationException ("Current state is not acceptable for doctype.");
224 public override void WriteStartElement (string prefix, string name, string ns)
228 XNamespace xns = XNamespace.Get (ns ?? String.Empty);
229 XElement el = new XElement (xns.GetName (name));
230 if (current == null) {
232 state = XmlNodeType.Element;
235 state = XmlNodeType.Element;
238 FillXmlns (el, prefix, xns);
245 public override void WriteEndElement ()
247 WriteEndElementInternal (false);
250 public override void WriteFullEndElement ()
252 WriteEndElementInternal (true);
255 void WriteEndElementInternal (bool forceFull)
259 throw new InvalidOperationException ("Current state is not acceptable for endElement.");
261 XElement el = current as XElement;
265 current = current.Parent;
270 public override void WriteStartAttribute (string prefix, string name, string ns)
273 if (attribute != null)
274 throw new InvalidOperationException ("There is an open attribute.");
275 XElement el = current as XElement;
277 throw new InvalidOperationException ("Current state is not acceptable for startAttribute.");
279 prefix = String.Empty;
281 // special case: in XmlWriter context, xmlns="blah" is
282 // passeed as localName = "xmlns", ns = w3c_xmlns.
283 if (prefix.Length == 0 && name == "xmlns" && ns == XNamespace.Xmlns.NamespaceName)
286 XNamespace xns = ns == null ? XNamespace.None : XNamespace.Get (ns);
287 el.SetAttributeValue (xns.GetName (name), String.Empty);
288 attribute = el.LastAttribute;
289 FillXmlns (el, ns != null ? prefix : null, xns);
292 public override void WriteEndAttribute ()
295 if (attribute == null)
296 throw new InvalidOperationException ("Current state is not acceptable for startAttribute.");
301 public override void WriteCData (string data)
305 throw new InvalidOperationException ("Current state is not acceptable for CDATAsection.");
307 current.Add (new XCData (data));
310 public override void WriteComment (string comment)
312 WritePossiblyTopLevelNode (new XComment (comment), false);
315 public override void WriteProcessingInstruction (string name, string value)
317 WritePossiblyTopLevelNode (
318 new XProcessingInstruction (name, value), false);
321 public override void WriteEntityRef (string name)
323 throw new NotSupportedException ();
326 public override void WriteCharEntity (char c)
328 throw new NotSupportedException ();
331 public override void WriteWhitespace (string ws)
333 // FIXME: check whitespace
334 WritePossiblyTopLevelNode (new XText (ws), true);
337 public override void WriteString (string data)
341 throw new InvalidOperationException ("Current state is not acceptable for Text.");
343 if (attribute != null)
344 attribute.Value += data;
349 public override void WriteName (string name)
354 public override void WriteNmToken (string nmtoken)
356 WriteString (nmtoken);
359 public override void WriteQualifiedName (string name, string ns)
361 string prefix = LookupPrefix (ns);
363 throw new ArgumentException (String.Format ("Invalid namespace {0}", ns));
364 if (prefix != String.Empty)
367 WriteString (prefix + ":" + name);
370 public override void WriteChars (char [] chars, int start, int len)
372 WriteString (new string (chars, start, len));
375 public override void WriteRaw (string data)
377 // It never supports raw string.
381 public override void WriteRaw (char [] chars, int start, int len)
383 // It never supports raw string.
384 WriteChars (chars, start, len);
387 public override void WriteBase64 (byte [] data, int start, int len)
389 // It never supports raw string.
390 WriteString (Convert.ToBase64String (data, start, len));
393 public override void WriteBinHex (byte [] data, int start, int len)
395 throw new NotImplementedException ();
398 public override void WriteSurrogateCharEntity (char c1, char c2)
400 throw new NotImplementedException ();