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