* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.XML / Test / System.Xml.Xsl / standalone_tests / XmlNormalizer.cs
1 using System;\r
2 using System.IO;\r
3 using System.Xml;\r
4 using System.Xml.XPath;\r
5 using System.Collections;\r
6 using System.Reflection;\r
7 using System.ComponentModel;\r
8 using System.Text;\r
9 \r
10 namespace XmlNormalizer {\r
11         /// <summary>\r
12         /// Summary description for Class1.\r
13         /// </summary>\r
14         class XmlNormalizer {\r
15                 class OptionLetterAttribute:Attribute{\r
16                         char _c;\r
17                         public OptionLetterAttribute(char c):base(){\r
18                                 _c = c;\r
19                         }\r
20                         public override string ToString() {\r
21                                 return _c.ToString();\r
22                         }\r
23                 }\r
24 \r
25                 XmlDocument doc;\r
26                 bool _removeWhiteSpace;\r
27                 bool _sortAttributes;\r
28                 bool _removeAttributes;\r
29                 bool _removeNamespacesAndPrefixes;\r
30                 bool _removeText;\r
31                 bool _removeAll;\r
32                 bool _newLines;\r
33 \r
34                 [OptionLetter('w')]\r
35                 [Description("remove white space")]\r
36                 public bool RemoveWhiteSpace {\r
37                         get {return _removeWhiteSpace;}\r
38                         set {_removeWhiteSpace=value;}\r
39                 }\r
40                 [OptionLetter('s')]\r
41                 [Description("sort attributes")]\r
42                 public bool SortAttributes {\r
43                         get {return _sortAttributes;}\r
44                         set {_sortAttributes=value;}\r
45                 }\r
46                 [OptionLetter('a')]\r
47                 [Description("remove attributes")]\r
48                 public bool RemoveAttributes {\r
49                         get {return _removeAttributes;}\r
50                         set {_removeAttributes=value;}\r
51                 }\r
52                 [OptionLetter('p')]\r
53                 [Description("remove namespaces and prefixes")]\r
54                 public bool RemoveNamespacesAndPrefixes {\r
55                         get {return _removeNamespacesAndPrefixes;}\r
56                         set {_removeNamespacesAndPrefixes=value;}\r
57                 }\r
58                 [OptionLetter('t')]\r
59                 [Description("remove text nodes")]\r
60                 public bool RemoveText {\r
61                         get {return _removeText;}\r
62                         set {_removeText=value;}\r
63                 }\r
64                 [OptionLetter('n')]\r
65                 [Description("remove all except element nodes")]\r
66                 public bool RemoveAll {\r
67                         get {return _removeAll;}\r
68                         set {_removeAll=value;}\r
69                 }\r
70                 [OptionLetter('x')]\r
71                 [Description("insert newlines before elements")]\r
72                 public bool NewLines {\r
73                         get {return _newLines;}\r
74                         set {_newLines=value;}\r
75                 }\r
76                 [OptionLetter('m')]\r
77                 [Description("minimal normalizing")]\r
78                 public bool MinimalNormalizing {\r
79                         get {return false;}\r
80                 }\r
81 \r
82                 public XmlNormalizer ()\r
83                         :this ("") {\r
84                 }\r
85 \r
86                 public XmlNormalizer (string options) {\r
87                         ParseOptions(options);\r
88                 }\r
89 \r
90                 public void Process(TextReader rd) {\r
91                         doc=new XmlDocument();\r
92                         doc.PreserveWhitespace = true;\r
93 \r
94                         string fileContents = rd.ReadToEnd();\r
95                         \r
96                         try {\r
97                                 doc.LoadXml (fileContents);\r
98                         }\r
99                         catch (Exception x) {\r
100                                 StringBuilder sb = new StringBuilder ();\r
101                                 sb.Append ("<NormalizerRoot>");\r
102                                 sb.Append (fileContents);\r
103                                 sb.Append ("</NormalizerRoot>");\r
104                                 doc.LoadXml (sb.ToString ());\r
105                         }\r
106 \r
107                 \r
108                         if (RemoveText)\r
109                                 RemoveWhiteSpace = true;\r
110 \r
111                         if (RemoveAll)\r
112                                 RemoveNamespacesAndPrefixes = true;\r
113 \r
114                         XmlDocument newDoc = new XmlDocument();\r
115 \r
116                         CopyNodes(newDoc, doc, newDoc);\r
117 \r
118                         doc=newDoc;\r
119                 }\r
120 \r
121                 void CopyNodes (XmlDocument newDoc, XmlNode fromParent, XmlNode toParent) {\r
122                         if (fromParent.HasChildNodes)\r
123                                 foreach (XmlNode c in fromParent.ChildNodes)\r
124                                         CopyNode (newDoc, c, toParent);\r
125 \r
126                         if (fromParent.Attributes != null) {\r
127                                 string [] keys = new string [fromParent.Attributes.Count];\r
128 \r
129                                 for (int i=0; i<fromParent.Attributes.Count; i++) {\r
130                                         keys[i] = fromParent.Attributes[i].Name;\r
131                                 }\r
132                                 if (SortAttributes){ \r
133                                         Array.Sort(keys);\r
134                                 }\r
135                                 for (int i=0; i<keys.Length; i++) {\r
136                                         CopyNode (newDoc, fromParent.Attributes[keys[i]], toParent);\r
137                                 }\r
138                         }\r
139                 }\r
140 \r
141                 void CopyNode (XmlDocument newDoc, XmlNode from, XmlNode toParent) {\r
142                         if (RemoveAll && from.NodeType != XmlNodeType.Element)\r
143                                 return;\r
144 \r
145                         XmlNode child = null;\r
146                         bool newLineNode = false;\r
147                         \r
148                         switch (from.NodeType) {\r
149                                 case XmlNodeType.Element: \r
150                                         newLineNode = true;\r
151                                         if (RemoveNamespacesAndPrefixes)\r
152                                                 child = newDoc.CreateElement (from.LocalName);\r
153                                         else {\r
154                                                 XmlElement e = from as XmlElement;\r
155                                                 child = newDoc.CreateElement (e.Prefix, e.LocalName, e.NamespaceURI);\r
156                                         }\r
157                                         break;\r
158                                 case XmlNodeType.Attribute: {\r
159                                         if (RemoveAttributes)\r
160                                                 return;\r
161 \r
162                                         XmlAttribute fromAttr = from as XmlAttribute;\r
163                                         if (!fromAttr.Specified)\r
164                                                 return;\r
165 \r
166                                         XmlAttribute a;\r
167 \r
168                                         if (RemoveNamespacesAndPrefixes)\r
169                                                 a = newDoc.CreateAttribute (fromAttr.LocalName);\r
170                                         else\r
171                                                 a = newDoc.CreateAttribute (fromAttr.Prefix, fromAttr.LocalName, fromAttr.NamespaceURI);\r
172                                         \r
173                                         toParent.Attributes.Append(a);\r
174                                         CopyNodes (newDoc, from, a);\r
175                                         return;\r
176                                 }\r
177                                 case XmlNodeType.CDATA:\r
178                                         newLineNode = true;\r
179                                         child = newDoc.CreateCDataSection ((from as XmlCDataSection).Data);\r
180                                         break;\r
181                                 case XmlNodeType.Comment:\r
182                                         if (RemoveWhiteSpace)\r
183                                                 return;\r
184                                         newLineNode = true;\r
185                                         child = newDoc.CreateComment ((from as XmlComment).Data);\r
186                                         break;\r
187                                 case XmlNodeType.ProcessingInstruction:\r
188                                         newLineNode = true;\r
189                                         XmlProcessingInstruction pi = from as XmlProcessingInstruction;\r
190                                         child = newDoc.CreateProcessingInstruction (pi.Target, pi.Data);\r
191                                         break;\r
192                                 case XmlNodeType.DocumentType:\r
193                                         newLineNode = true;\r
194                                         toParent.AppendChild (from.CloneNode (true));\r
195                                         return;\r
196                                 case XmlNodeType.EntityReference:\r
197                                         child = newDoc.CreateEntityReference ((from as XmlEntityReference).Name);\r
198                                         break;\r
199                                 case XmlNodeType.SignificantWhitespace:\r
200                                         if (RemoveWhiteSpace)\r
201                                                 return;\r
202                                         child = newDoc.CreateSignificantWhitespace (from.Value);\r
203                                         break;\r
204                                 case XmlNodeType.Text:\r
205                                         if (RemoveText)\r
206                                                 return;\r
207                                         newLineNode = true;\r
208                                         child = newDoc.CreateTextNode (from.Value);\r
209                                         break;\r
210                                 case XmlNodeType.Whitespace:\r
211                                         if (RemoveWhiteSpace)\r
212                                                 return;\r
213                                         child = newDoc.CreateWhitespace (from.Value);\r
214                                         break;\r
215                                 case XmlNodeType.XmlDeclaration:\r
216                                         newLineNode = true;\r
217                                         XmlDeclaration d = from as XmlDeclaration;\r
218                                         XmlDeclaration d1 = newDoc.CreateXmlDeclaration (d.Version, d.Encoding, d.Standalone);\r
219                                         newDoc.InsertBefore(d1, newDoc.DocumentElement);\r
220                                         return;\r
221                         }\r
222                         if (NewLines && newLineNode && toParent.NodeType != XmlNodeType.Attribute) {\r
223                                 XmlSignificantWhitespace s = newDoc.CreateSignificantWhitespace("\r\n");\r
224                                 toParent.AppendChild (s);\r
225                         }\r
226                         toParent.AppendChild(child);\r
227                         CopyNodes (newDoc, from, child);\r
228                 }\r
229 \r
230                 public void ParseOptions (string options) {\r
231                         _removeWhiteSpace = false;\r
232                         _sortAttributes = false;\r
233                         _removeAttributes = false;\r
234                         _removeNamespacesAndPrefixes = false;\r
235                         _removeText = false;\r
236                         _removeAll = false;\r
237                         _newLines = false;\r
238                         foreach (PropertyInfo pi in typeof (XmlNormalizer).GetProperties()) {\r
239                                 string option = pi.GetCustomAttributes(typeof(OptionLetterAttribute),true)[0].ToString();\r
240                                 if (options.IndexOf(option) == -1)\r
241                                         continue;\r
242                                 pi.GetSetMethod().Invoke (this, new object [] {true});\r
243                         }\r
244                 }\r
245 \r
246                 public static Hashtable GetOptions() {\r
247                         Hashtable h = new Hashtable();\r
248 \r
249                         foreach (PropertyInfo pi in typeof (XmlNormalizer).GetProperties()) {\r
250                                 string option = pi.GetCustomAttributes(typeof(OptionLetterAttribute),true)[0].ToString();\r
251                                 string descr = (pi.GetCustomAttributes(typeof(DescriptionAttribute), true)[0] as DescriptionAttribute).Description;\r
252                                 h[option] = descr;\r
253                         }\r
254                         return h;\r
255                 }\r
256 \r
257                 public void Output(XmlWriter wr) {\r
258                         doc.WriteTo(wr);\r
259                 }\r
260 \r
261                 public void Output(TextWriter wr) {\r
262                         Output (new XmlTextWriter (wr));\r
263                 }\r
264                 \r
265                 void ProcessFile (string inputfile, string outputfile) {\r
266                         StreamWriter wr = null;\r
267                         StreamReader rd = null;\r
268                         try {\r
269                                 wr = new StreamWriter (outputfile);\r
270                                 rd = new StreamReader (inputfile);\r
271                                 ProcessFile (rd, wr);\r
272                         } catch (Exception) {\r
273                                 if (wr != null)\r
274                                         wr.Close ();\r
275                                 if (rd != null)\r
276                                         rd.Close ();\r
277                                 wr = null;\r
278                                 rd = null;\r
279                                 File.Copy (inputfile, outputfile, true);\r
280                         } finally {\r
281                                 if (wr != null)\r
282                                         wr.Close ();\r
283                                 if (rd != null)\r
284                                         rd.Close ();\r
285                         }\r
286                 }\r
287 \r
288                 void ProcessFile (TextReader input, TextWriter output) {\r
289                         XmlTextWriter xwr = new XmlTextWriter (output);\r
290                         \r
291                         Process (input);\r
292                         Output (xwr);\r
293                 }\r
294                 \r
295                 void ProcessDirectory (string inputdir, string outputdir) {\r
296                         if (!Directory.Exists (outputdir))\r
297                                 Directory.CreateDirectory (outputdir);\r
298                         DirectoryInfo idi = new DirectoryInfo(inputdir);\r
299                         foreach (FileInfo fi in idi.GetFiles()) {\r
300                                 string outputfile = Path.Combine(outputdir, fi.Name);\r
301                                 ProcessFile (fi.FullName, outputfile);\r
302                         }\r
303                         foreach (DirectoryInfo di in idi.GetDirectories())\r
304                                 ProcessDirectory (di.FullName, Path.Combine(outputdir, di.Name));\r
305                 }\r
306 #if !XML_NORMALIZER_NO_MAIN\r
307                 /// <summary>\r
308                 /// The main entry point for the application.\r
309                 /// </summary>\r
310                 [STAThread]\r
311                 static int Main(string[] args) {\r
312                         if (args.Length < 2 || args[0].Length < 2 || args[0][0] != '-') {\r
313                                 PrintUsage();\r
314                                 return 1;\r
315                         }\r
316                         XmlNormalizer norm = new XmlNormalizer (args[0].Substring(1));\r
317                         if (File.Exists(args[1])) {\r
318                                 if (args.Length != 2) {\r
319                                         PrintUsage();\r
320                                         return 1;\r
321                                 }\r
322                                 norm.ProcessFile(new StreamReader (args[1]), Console.Out);\r
323                         }\r
324                         else if (Directory.Exists (args[1])) {\r
325                                 if (args.Length != 3) {\r
326                                         PrintUsage();\r
327                                         return 1;\r
328                                 }\r
329                                 norm.ProcessDirectory (args[1], args[2]);\r
330                         }\r
331                         else {\r
332                                 Console.Error.WriteLine("Path not found: {0}", args[1]);\r
333                                 return 2;\r
334                         }\r
335                         return 0;\r
336                 }\r
337                 static void PrintUsage () {\r
338                         Console.Error.WriteLine("Usage: xmlnorm -<flags> <inputfile>");\r
339                         Console.Error.WriteLine("Or: xmlnorm -<flags> <inputdir> <outputdir>");\r
340                         Console.Error.WriteLine("\tFlags:");\r
341                         foreach (DictionaryEntry de in XmlNormalizer.GetOptions())\r
342                                 Console.Error.WriteLine ("\t{0}\t{1}", de.Key, de.Value);\r
343                 }\r
344 #endif\r
345         }\r
346 \r
347 }\r