2 // Mono.Xml.XmlNodeWriter
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
14 public class CopyXmlNodeWriter : XmlWriter
16 public CopyXmlNodeWriter () : this (true)
20 // It should be public after some tests are done :-)
21 public CopyXmlNodeWriter (bool isDocumentEntity)
23 doc = new XmlDocument ();
24 state = XmlNodeType.None;
25 this.isDocumentEntity = isDocumentEntity;
26 if (!isDocumentEntity)
27 current = fragment = doc.CreateDocumentFragment ();
32 // If it is not null, then we are now inside the element.
34 // If it is not null, then we are now inside the attribute.
35 XmlAttribute attribute;
36 // If it is false, then allow to contain multiple document elements.
37 bool isDocumentEntity;
38 XmlDocumentFragment fragment;
40 // None: started or closed.
41 // XmlDeclaration: after xmldecl. Never allow xmldecl.
42 // DocumentType: after doctype. Never allow xmldecl and doctype.
43 // Element: inside document element.
48 public XmlNode Document {
49 get { return isDocumentEntity ? (XmlNode)doc : (XmlNode)fragment; }
52 public override WriteState WriteState {
55 return WriteState.Closed;
56 if (attribute != null)
57 return WriteState.Attribute;
60 case XmlNodeType.None:
61 return WriteState.Start;
62 case XmlNodeType.XmlDeclaration:
63 return WriteState.Prolog;
64 case XmlNodeType.DocumentType:
65 return WriteState.Element;
67 return WriteState.Content;
72 public override string XmlLang {
74 for (XmlElement n = current as XmlElement; n != null; n = n.ParentNode as XmlElement)
75 if (n.HasAttribute ("xml:lang"))
76 return n.GetAttribute ("xml:lang");
81 public override XmlSpace XmlSpace {
83 for (XmlElement n = current as XmlElement; n != null; n = n.ParentNode as XmlElement) {
84 string xs = n.GetAttribute ("xml:space");
87 return XmlSpace.Preserve;
89 return XmlSpace.Default;
93 throw new InvalidOperationException (String.Format ("Invalid xml:space {0}.", xs));
102 private void CheckState ()
105 throw new InvalidOperationException ();
109 private void WritePossiblyTopLevelNode (XmlNode n, bool possiblyAttribute)
112 if (!possiblyAttribute && attribute != null)
113 throw new InvalidOperationException (String.Format ("Current state is not acceptable for {0}.", n.NodeType));
115 if (state != XmlNodeType.Element)
116 Document.AppendChild (n);
117 else if (attribute != null)
118 attribute.AppendChild (n);
120 current.AppendChild (n);
121 if (state == XmlNodeType.None)
122 state = XmlNodeType.XmlDeclaration;
127 public override void Close ()
133 public override void Flush ()
137 public override string LookupPrefix (string ns)
141 throw new InvalidOperationException ();
142 return current.GetPrefixOfNamespace (ns);
147 public override void WriteStartDocument ()
149 WriteStartDocument (null);
152 public override void WriteStartDocument (bool standalone)
154 WriteStartDocument (standalone ? "yes" : "no");
157 private void WriteStartDocument (string sddecl)
160 if (state != XmlNodeType.None)
161 throw new InvalidOperationException ("Current state is not acceptable for xmldecl.");
163 doc.AppendChild (doc.CreateXmlDeclaration ("1.0", null, sddecl));
164 state = XmlNodeType.XmlDeclaration;
169 public override void WriteEndDocument ()
177 public override void WriteDocType (string name, string publicId, string systemId, string internalSubset)
181 case XmlNodeType.None:
182 case XmlNodeType.XmlDeclaration:
183 doc.AppendChild (doc.CreateDocumentType (name, publicId, systemId, internalSubset));
184 state = XmlNodeType.DocumentType;
187 throw new InvalidOperationException ("Current state is not acceptable for doctype.");
193 public override void WriteStartElement (string prefix, string name, string ns)
196 if (isDocumentEntity && state == XmlNodeType.EndElement && doc.DocumentElement != null)
197 throw new InvalidOperationException ("Current state is not acceptable for startElement.");
199 XmlElement el = doc.CreateElement (prefix, name, ns);
200 if (current == null) {
201 Document.AppendChild (el);
202 state = XmlNodeType.Element;
204 current.AppendChild (el);
205 state = XmlNodeType.Element;
213 public override void WriteEndElement ()
215 WriteEndElementInternal (false);
218 public override void WriteFullEndElement ()
220 WriteEndElementInternal (true);
223 private void WriteEndElementInternal (bool forceFull)
227 throw new InvalidOperationException ("Current state is not acceptable for endElement.");
229 if (!forceFull && current.FirstChild == null)
230 ((XmlElement) current).IsEmpty = true;
232 if (isDocumentEntity && current.ParentNode == doc)
233 state = XmlNodeType.EndElement;
235 current = current.ParentNode;
240 public override void WriteStartAttribute (string prefix, string name, string ns)
243 if (attribute != null)
244 throw new InvalidOperationException ("There is an open attribute.");
245 if (!(current is XmlElement))
246 throw new InvalidOperationException ("Current state is not acceptable for startAttribute.");
248 attribute = doc.CreateAttribute (prefix, name, ns);
249 ((XmlElement)current).SetAttributeNode (attribute);
252 public override void WriteEndAttribute ()
255 if (attribute == null)
256 throw new InvalidOperationException ("Current state is not acceptable for startAttribute.");
261 public override void WriteCData (string data)
265 throw new InvalidOperationException ("Current state is not acceptable for CDATAsection.");
267 current.AppendChild (doc.CreateCDataSection (data));
270 public override void WriteComment (string comment)
272 WritePossiblyTopLevelNode (doc.CreateComment (comment), false);
275 public override void WriteProcessingInstruction (string name, string value)
277 WritePossiblyTopLevelNode (
278 doc.CreateProcessingInstruction (name, value), false);
281 public override void WriteEntityRef (string name)
283 WritePossiblyTopLevelNode (doc.CreateEntityReference (name), true);
286 public override void WriteCharEntity (char c)
288 WritePossiblyTopLevelNode (doc.CreateTextNode (new string (new char [] {c}, 0, 1)), true);
291 public override void WriteWhitespace (string ws)
293 WritePossiblyTopLevelNode (doc.CreateWhitespace (ws), true);
296 public override void WriteString (string data)
300 throw new InvalidOperationException ("Current state is not acceptable for Text.");
302 if (attribute != null)
303 attribute.AppendChild (doc.CreateTextNode (data));
305 XmlText last = current.LastChild as XmlText;
307 current.AppendChild(doc.CreateTextNode(data));
309 last.AppendData(data);
313 public override void WriteName (string name)
318 public override void WriteNmToken (string nmtoken)
320 WriteString (nmtoken);
323 public override void WriteQualifiedName (string name, string ns)
325 string prefix = LookupPrefix (ns);
327 throw new ArgumentException (String.Format ("Invalid namespace {0}", ns));
328 if (prefix != String.Empty)
331 WriteString (prefix + ":" + name);
334 public override void WriteChars (char [] chars, int start, int len)
336 WriteString (new string (chars, start, len));
339 public override void WriteRaw (string data)
341 // It never supports raw string.
345 public override void WriteRaw (char [] chars, int start, int len)
347 // It never supports raw string.
348 WriteChars (chars, start, len);
351 public override void WriteBase64 (byte [] data, int start, int len)
353 // It never supports raw string.
354 WriteString (Convert.ToBase64String (data, start, len));
357 public override void WriteBinHex (byte [] data, int start, int len)
359 throw new NotImplementedException ();
362 public override void WriteSurrogateCharEntity (char c1, char c2)
364 throw new NotImplementedException ();