1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.IO; 8 using System.Text; 9 10 namespace CoreXml.Test.XLinq 11 { 12 public class ManagedNodeWriter 13 { 14 public static bool DEBUG = false; 15 16 private const string XML_DECL = "<?xml version='1.0' ?>\n"; 17 private const string S_ROOT = "<root>"; 18 private const string E_ROOT = "</root>"; 19 private const string E_NAME = "ELEMENT_"; 20 private const string A_NAME = "ATTRIB_"; 21 private const string A_VALUE = "VALUE_"; 22 private const string CDATA = "CDATA_"; 23 private const string TEXT = "TEXT_"; 24 private const string PI = "PI_"; 25 private const string COMMENT = "COMMENT_"; 26 27 private long _eCount = 0; //element indexer 28 private long _aCount = 0; //attribute indexer 29 private long _cCount = 0; //Cdata indexer 30 private long _tCount = 0; //Text indexer 31 private long _pCount = 0; //PI Indexer 32 private long _mCount = 0; //Comment Indexer 33 34 private StreamWriter _textWriter = null; 35 private Stack<string> _elementStack = new Stack<string>(); 36 private StringBuilder _nodeQueue = new StringBuilder(); 37 38 private const string LT = "<"; 39 private const string GT = ">"; 40 private const string MT = "/>"; 41 private const string ET = "</"; 42 private const string SPACE = " "; 43 private const string S_QUOTE = "'"; 44 private const string D_QUOTE = "\""; 45 private const string EQ = "="; 46 private const string LF = "\n"; 47 ManagedNodeWriter()48 public ManagedNodeWriter() 49 { } 50 ManagedNodeWriter(Stream myStream, Encoding enc)51 public ManagedNodeWriter(Stream myStream, Encoding enc) 52 { 53 _textWriter = new StreamWriter(myStream, enc); 54 } 55 56 /// <summary> 57 /// GetNodes returns the existing XML string thats been written so far. 58 /// </summary> 59 /// <returns>String of XML</returns> GetNodes()60 public string GetNodes() 61 { 62 return _nodeQueue.ToString(); 63 } 64 65 /// Closing the NodeWriter Close()66 public void Close() 67 { 68 if (_textWriter != null) 69 { 70 _textWriter.Write(_nodeQueue.ToString()); 71 _textWriter.Dispose(); 72 _textWriter = null; 73 } 74 } 75 76 /// Writing XML Decl PutDecl()77 public void PutDecl() 78 { 79 _nodeQueue.Append(XML_DECL); 80 } 81 82 83 /// Writing a Root Element. PutRoot()84 public void PutRoot() 85 { 86 _nodeQueue.Append(S_ROOT); 87 } 88 89 90 /// Writing End Root Element. PutEndRoot()91 public void PutEndRoot() 92 { 93 _nodeQueue.Append(E_ROOT); 94 } 95 96 97 /// Writing a start of open element. OpenElement()98 public void OpenElement() 99 { 100 string elem = LT + E_NAME + _eCount + SPACE; 101 102 _nodeQueue.Append(elem); 103 _elementStack.Push(E_NAME + _eCount); 104 ++_eCount; 105 } 106 107 /// Writing a start of open element with user supplied name. OpenElement(string myName)108 public void OpenElement(string myName) 109 { 110 string elem = LT + myName + SPACE; 111 _elementStack.Push(myName); 112 _nodeQueue.Append(elem); 113 } 114 115 /// Closing the open element. CloseElement()116 public void CloseElement() 117 { 118 _nodeQueue.Append(GT); 119 } 120 121 // Closing the open element as empty element CloseEmptyElement()122 public void CloseEmptyElement() 123 { 124 _nodeQueue.Append(MT); 125 } 126 127 /// Writing an attribute. PutAttribute()128 public void PutAttribute() 129 { 130 string attr = A_NAME + _aCount + EQ + S_QUOTE + A_VALUE + _aCount + S_QUOTE + SPACE; 131 132 _nodeQueue.Append(attr); 133 ++_aCount; 134 } 135 136 137 /// Overloaded PutAttribute which takes user values. PutAttribute(string myAttrName, string myAttrValue)138 public void PutAttribute(string myAttrName, string myAttrValue) 139 { 140 string attr = SPACE + myAttrName + EQ + S_QUOTE + myAttrValue + S_QUOTE; 141 142 _nodeQueue.Append(attr); 143 } 144 145 146 /// Writing empty element. PutEmptyElement()147 public void PutEmptyElement() 148 { 149 string elem = LT + E_NAME + _eCount + MT; 150 151 _nodeQueue.Append(elem); 152 ++_eCount; 153 } 154 155 /// Writing an end element from the stack. PutEndElement()156 public void PutEndElement() 157 { 158 string elem = _elementStack.Pop(); 159 _nodeQueue.Append(ET + elem + GT); 160 } 161 162 /// Writing an end element for a given name. PutEndElement(string myName)163 public void PutEndElement(string myName) 164 { 165 if (DEBUG) 166 { 167 string elem = _elementStack.Pop(); 168 } 169 _nodeQueue.Append(ET + myName + GT); 170 } 171 172 /// <summary> 173 /// Finish allows user to complete xml file with the end element tags that were so far open. 174 /// </summary> Finish()175 public void Finish() 176 { 177 while (_elementStack.Count > 0) 178 { 179 string elem = _elementStack.Pop(); 180 _nodeQueue.Append(ET + elem + GT); 181 } 182 } 183 184 /// Writing text. 185 /// Note : This is basically equivalent to WriteRaw and the string may contain any number of embedded tags. 186 /// No checking is performed on them either. PutText(string myStr)187 public void PutText(string myStr) 188 { 189 _nodeQueue.Append(myStr); 190 } 191 192 /// <summary> 193 /// AutoGenerated Text 194 /// </summary> PutText()195 public void PutText() 196 { 197 _nodeQueue.Append(TEXT + _tCount++); 198 } 199 200 /// <summary> 201 /// Writing a Byte Array. 202 /// </summary> 203 /// <param name="bArr"></param> PutBytes(byte[] bArr)204 public void PutBytes(byte[] bArr) 205 { 206 foreach (byte b in bArr) 207 { 208 _nodeQueue.Append(b); 209 } 210 } 211 PutByte()212 public void PutByte() 213 { 214 _nodeQueue.Append(Convert.ToByte("a")); 215 } 216 217 /// <summary> 218 /// Writes out CDATA Node. 219 /// </summary> PutCData()220 public void PutCData() 221 { 222 _nodeQueue.Append("<![CDATA[" + CDATA + _cCount++ + "]]>"); 223 } 224 225 /// <summary> 226 /// Writes out a PI Node. 227 /// </summary> PutPI()228 public void PutPI() 229 { 230 _nodeQueue.Append("<?" + PI + _pCount++ + "?>"); 231 } 232 233 /// <summary> 234 /// Writes out a Comment Node. 235 /// </summary> PutComment()236 public void PutComment() 237 { 238 _nodeQueue.Append("<!--" + COMMENT + _mCount++ + " -->"); 239 } 240 241 /// <summary> 242 /// Writes out a single whitespace 243 /// </summary> PutWhiteSpace()244 public void PutWhiteSpace() 245 { 246 _nodeQueue.Append(" "); 247 } 248 249 /// <summary> 250 /// This method is a convenience method and a shortcut to create an XML string. Each character in the pattern 251 /// maps to a particular Put/Open function and calls it for you. For e.g. XEAA/ will call PutDecl, OpenElement, 252 /// PutAttribute, PutAttribute and CloseElement for you. 253 /// The following is the list of all allowed characters and their function mappings : 254 /// 255 ///'X' : PutDecl() 256 ///'E' : OpenElement() 257 ///'M' : CloseEmptyElement() 258 ///'/' : CloseElement() 259 ///'e' : PutEndElement() 260 ///'A' : PutAttribute() 261 ///'P' : PutPI() 262 ///'T' : PutText() 263 ///'C' : PutComment() 264 ///'R' : PutRoot() 265 ///'r' : PutEndRoot() 266 ///'B' : PutEndRoot() 267 ///'W' : PutWhiteSpace() 268 /// 269 /// </summary> 270 /// <param name="pattern">String containing the pattern which you want to use to create 271 /// the XML string. Refer to table above for supported chars.</param> 272 PutPattern(string pattern)273 public void PutPattern(string pattern) 274 { 275 char[] patternArr = pattern.ToCharArray(); 276 foreach (char ch in patternArr) 277 { 278 switch (ch) 279 { 280 case 'X': 281 PutDecl(); 282 break; 283 case 'E': 284 OpenElement(); 285 break; 286 case 'M': 287 CloseEmptyElement(); 288 break; 289 case '/': 290 CloseElement(); 291 break; 292 case 'e': 293 PutEndElement(); 294 break; 295 case 'A': 296 PutAttribute(); 297 break; 298 case 'P': 299 PutPI(); 300 break; 301 case 'T': 302 PutText(); 303 break; 304 case 'C': 305 PutComment(); 306 break; 307 case 'R': 308 PutRoot(); 309 break; 310 case 'r': 311 PutEndRoot(); 312 break; 313 case 'B': 314 PutEndRoot(); 315 break; 316 case 'W': 317 PutWhiteSpace(); 318 break; 319 default: 320 break; 321 } 322 } 323 } 324 } 325 } 326