c#: 解析json, 转成xml, 简单方便

没看到.net framework中有这样的功能, 懒得到处找了, 索性花点时间自己写一个

  1 /*
  2  * Created by SharpDevelop.
  3  * Date: 2013/6/24
  4  * User: sliencer
  5  * Time: 21:54
  6  * 
  7  * To change this template use Tools | Options | Coding | Edit Standard Headers.
  8  */
  9 using System;
 10 using System.Collections.Generic;
 11 using System.Globalization;
 12 using System.Linq;
 13 using System.Text;
 14 using System.Text.RegularExpressions;
 15 using System.Xml;
 16 
 17 namespace JsonDecoder
 18 {
 19     class Program
 20     {
 21         public static void Main(string[] args)
 22         {
 23             int i=0;
 24             foreach (String element in inputs) {
 25                 JS_Value v=JsonDecoder.Decode(element);
 26                 if (v == null)
 27                     throw Error.InvalidJsonStream;
 28                 String s=v.ToString();
 29                 XmlWriterSettings settings =new XmlWriterSettings();
 30                 settings.Indent = true;
 31                 settings.Encoding = Encoding.UTF8;
 32                 XmlWriter wri = XmlWriter.Create("Output" + (i++) + ".xml", settings);
 33                 v.ToXml(wri, true, "JSon");
 34                 wri.Close();
 35             }
 36         }
 37         static String[] inputs=new string[]{
 38         /*自己找几个json测试一下, 我的是从网站随便找来的, 担心版权问题, 就去掉了*/
 39         @"""test1""", @"""test2""", @"""test3"""
 40         };
 41     }
 42     public abstract class JS_Value
 43     {
 44         public abstract void ToXml(XmlWriter p_wri, bool p_bCreateElement, String p_strElementName);
 45     }
 46     public static class XmlHelper
 47     {
 48         public static String ToValidXmlName(String p_name)
 49         {
 50             /*
 51              * http://www.w3.org/TR/REC-xml/#NT-Name
 52                 NameStartChar       ::=       ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
 53                 NameChar       ::=       NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
 54              */
 55             string patNameStartChar = @":|[A-Z]|_|[a-z]|[\xC0-\xD6]|[\xD8-\xF6]|[\xF8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]";
 56             string patNameChar = patNameStartChar +"|" + @"-|\.|[0-9]|\xB7|[\u0300-\u036F]|[\u203F-\u2040]";
 57             String pat=@"^(" + patNameStartChar + ")" + "(" + patNameChar + ")*$";
 58             if (Regex.Match(p_name, pat, RegexOptions.Singleline).Success)
 59                 return p_name;
 60             else
 61             {
 62                 StringBuilder bld=new StringBuilder();
 63                 for (int i=0;i<p_name.Length;i++)
 64                 {
 65                     bool bMatch=false;
 66                     if (i==0)
 67                         bMatch = Regex.Match(p_name[i].ToString(), patNameStartChar,  RegexOptions.Singleline).Success;
 68                     else
 69                         bMatch = Regex.Match(p_name[i].ToString(), patNameChar,  RegexOptions.Singleline).Success;
 70                     if(bMatch)
 71                         bld.Append(p_name[i]);
 72                     else
 73                         bld.AppendFormat("_x{0:x}_", (int)p_name[i]);
 74                 }
 75                 return bld.ToString();
 76             }
 77         }
 78         public static void WriteStartElement_auto(this XmlWriter wri, String p_strName)
 79         {
 80             if (p_strName.Contains(":"))
 81             {
 82                 String prefix=p_strName.Substring(0, p_strName.LastIndexOf(':'));
 83                 string localName=p_strName.Substring(p_strName.LastIndexOf(':')+1);
 84                 if(String.IsNullOrEmpty(localName))
 85                 {
 86                     localName = p_strName.Substring(0, p_strName.Length-1);
 87                     prefix = "";
 88                 }                
 89                 wri.WriteStartElement(localName, prefix);
 90             } else
 91                 wri.WriteStartElement(p_strName);
 92         }
 93     }
 94     public class JS_String : JS_Value
 95     {
 96         public String RawValue{get;set;}
 97         public String Value{get;set;}
 98         public override string ToString()
 99         {
100             return RawValue;
101         }
102         public override void ToXml(XmlWriter p_wri, bool p_bCreateElement, String p_strElementName)
103         {
104             String strEleName=XmlHelper.ToValidXmlName(String.IsNullOrEmpty(p_strElementName)? "Value" : p_strElementName);
105             if (p_bCreateElement)
106             {
107                 p_wri.WriteStartElement_auto(strEleName);
108             }
109             p_wri.WriteAttributeString("type", "string");
110             p_wri.WriteString(Value);
111             if (p_bCreateElement)
112             {
113                 p_wri.WriteEndElement();
114             }
115         }//ToXml()
116     }//class
117     public class JS_Number: JS_Value
118     {
119         public String Number{get;set;}
120         public override string ToString()
121         {
122             return Number;
123         }
124         
125         public override void ToXml(XmlWriter p_wri, bool p_bCreateElement, String p_strElementName)
126         {
127             String strEleName=XmlHelper.ToValidXmlName(String.IsNullOrEmpty(p_strElementName)? "Value" : p_strElementName);
128             if (p_bCreateElement)
129             {
130                 p_wri.WriteStartElement_auto(strEleName);
131             }
132             p_wri.WriteAttributeString("type", "number");
133             p_wri.WriteString(Number);
134             if (p_bCreateElement)
135             {
136                 p_wri.WriteEndElement();
137             }
138         }
139     }
140     public class JS_Object: JS_Value
141     {
142         private Dictionary<String, JS_Value> m_properties=new Dictionary<String, JS_Value> ();
143         public Dictionary<String, JS_Value> Properties{
144             get{
145                 return m_properties;
146             }
147         }
148         public override string ToString()
149         {
150             if(m_properties.Count<=0)
151                 return "{}";
152             else
153                 return "{" + m_properties.Select(x=>"\"" + x.Key + "\":" + x.Value.ToString())
154                     .Aggregate((x,y)=> x + ",\r\n" +y ) +"}";
155         }
156         
157         public override void ToXml(XmlWriter p_wri, bool p_bCreateElement, String p_strElementName)
158         {
159             String strEleName=XmlHelper.ToValidXmlName(String.IsNullOrEmpty(p_strElementName)? "Value" : p_strElementName);
160             if (p_bCreateElement)
161             {
162                 p_wri.WriteStartElement_auto(strEleName);
163             }
164             p_wri.WriteAttributeString("type", "object");
165             foreach (String properName in m_properties.Keys) {
166                 m_properties[properName].ToXml(p_wri, true, properName);
167             }
168             if (p_bCreateElement)
169             {
170                 p_wri.WriteEndElement();
171             }
172         }
173     }//class JS_Obj
174     public class JS_Array : JS_Value
175     {
176         private List<JS_Value> m_elements=new List<JS_Value>();
177         public List<JS_Value> Elements{
178             get{
179                 return m_elements;
180             }
181         }
182         public override string ToString()
183         {
184             if(m_elements.Count<=0)
185                 return "[]";
186             else
187                 return "[" + m_elements.Select(x=>x.ToString()).Aggregate((x,y)=> x + ",\r\n" +y ) +"]";
188         }
189 
190         
191         public override void ToXml(XmlWriter p_wri, bool p_bCreateElement, String p_strElementName)
192         {
193             String strEleName="Value";
194             if (p_bCreateElement)
195             {
196                 p_wri.WriteStartElement_auto(strEleName);
197             }
198             p_wri.WriteAttributeString("type", "array");
199             foreach (JS_Value element in m_elements) {
200                 element.ToXml(p_wri, true, p_strElementName);
201             }
202             if (p_bCreateElement)
203             {
204                 p_wri.WriteEndElement();
205             }
206         }
207     }
208     public enum enumJSConst{
209         eTrue, eFalse,eNull
210     }
211     public class JS_Const : JS_Value
212     {
213         public JS_Const(enumJSConst val){ m_value = val;}
214         private enumJSConst m_value;
215         public enumJSConst Value{get{return m_value;}}
216         
217         public override string ToString()
218         {
219             return m_value.ToString().Substring(1).ToLower();
220         }
221         public override void ToXml(XmlWriter p_wri, bool p_bCreateElement, String p_strElementName)
222         {
223             String strEleName=XmlHelper.ToValidXmlName(String.IsNullOrEmpty(p_strElementName)? "Value" : p_strElementName);
224             if (p_bCreateElement)
225             {
226                 p_wri.WriteStartElement_auto(strEleName);
227             }
228             p_wri.WriteAttributeString("type", "const");
229             p_wri.WriteString(ToString());
230             if (p_bCreateElement)
231             {
232                 p_wri.WriteEndElement();
233             }
234         }
235 
236         
237         public static JS_Const True = new JS_Const(enumJSConst.eTrue);
238         public static JS_Const False = new JS_Const(enumJSConst.eFalse);
239         public static JS_Const Null = new JS_Const(enumJSConst.eNull);
240         
241     }
242     public class JsonDecoder
243     {
244         public static JS_Value Decode(String p_stream)
245         {
246             if (String.IsNullOrWhiteSpace(p_stream))
247                 return null;
248             else
249             {
250                 String s=p_stream.Trim();
251                 int nPos=0;
252                 JS_Value v= GetValue(s, ref nPos);
253                 if (nPos == s.Length)
254                     return v;
255                 else
256                     throw Error.InvalidJsonStream;
257             }
258         }
259         private static char NextChar(String p_stream, ref int p_currentPos)
260         {
261             if (p_currentPos>=p_stream.Length)
262                 throw Error.InvalidJsonStream;
263             return p_stream[p_currentPos++];
264         }
265         private static void SkipSpaces(String p_stream, ref int p_currentPos)
266         {
267             while (p_currentPos<p_stream.Length
268                    && (Char.IsWhiteSpace(p_stream[p_currentPos])
269                       /* || Char.IsControl(p_stream[p_currentPos])*/
270                       )
271                   )
272             {
273                 p_currentPos++;
274             }//while
275             
276         }
277         private static char PeekChar(String p_stream, int p_currentPos)
278         {
279             if (p_currentPos>=p_stream.Length)
280                 throw Error.InvalidJsonStream;
281             return p_stream[p_currentPos];
282         }
283         public static JS_Value GetValue(String p_stream, ref int p_currentPos)
284         {
285             JS_Value newValue=GetConst(p_stream, ref p_currentPos);
286             if (null == newValue)
287                 newValue = GetString(p_stream, ref p_currentPos);
288             if (null == newValue)
289                 newValue = GetNumber(p_stream, ref p_currentPos);
290             if (null == newValue)
291                 newValue = GetObject(p_stream, ref p_currentPos);
292             if (null == newValue)
293                 newValue = GetArray(p_stream, ref p_currentPos);
294             
295             if(null == newValue)
296                 throw Error.InvalidJsonStream;
297             return newValue;
298         }
299         public static JS_Number GetNumber(String p_stream, ref int p_currentPos)
300         {
301               int nLen = p_stream.Length;
302               if (p_currentPos>=nLen)
303                   return null;
304             String strFraction=@"\.[0-9]+";
305             String strExposion=@"[eE][+-]?[0-9]+";
306             String strPattern=@"^(\-)?[1-9][0-9]*(" + strFraction +")?(" + strExposion + ")?";
307 //            if(p_stream.Substring(p_currentPos).StartsWith("500"))
308 //                Console.WriteLine("Here");
309             Regex rex=new Regex(strPattern);
310             Match m= rex.Match(p_stream.Substring(p_currentPos));
311             if (!m.Success) {
312                 /*m = Regex.Match(p_stream.Substring(p_currentPos), strPattern);
313                 m = Regex.Match(p_stream.Substring(p_currentPos), @"^-?[1-9][0-9]*");
314                 m = Regex.Match(p_stream.Substring(p_currentPos), @"^\-?[1-9][0-9]*");
315                 m = Regex.Match(p_stream.Substring(p_currentPos), @"^(-)?[1-9][0-9]*");
316                 m = Regex.Match(p_stream.Substring(p_currentPos), @"^(\-)?[1-9][0-9]*");
317                 */
318                 return null;
319             }
320             JS_Number result=new JS_Number();
321             result.Number = p_stream.Substring(p_currentPos, m.Groups[0].Length);
322             p_currentPos += m.Groups[0].Length;
323             return result;
324         }
325         public static JS_Const GetConst(String p_stream, ref int p_currentPos)
326         {
327               int nLen = p_stream.Length;
328               if (p_currentPos>=nLen)
329                   return null;
330               string temp=p_stream.Substring(p_currentPos);
331               if (temp.StartsWith("true",    StringComparison.CurrentCultureIgnoreCase))
332               {
333                   p_currentPos+=4;
334                   return JS_Const.True;
335               }
336               if (temp.StartsWith("false",    StringComparison.CurrentCultureIgnoreCase))
337               {
338                   p_currentPos+=5;
339                   return JS_Const.False;
340               }
341               if (temp.StartsWith("null",    StringComparison.CurrentCultureIgnoreCase))
342               {
343                   p_currentPos+=4;
344                   return JS_Const.Null;
345               }
346               return null;
347         }
348         public static JS_Array GetArray(String p_stream, ref int p_currentPos)
349         {
350               int nLen = p_stream.Length;
351               if (p_currentPos>=nLen)
352                   return null;
353               int nCurrent=p_currentPos;
354               if (PeekChar(p_stream, nCurrent) != '[')
355                   return null;
356               nCurrent++;
357               JS_Array result=new JS_Array();
358               SkipSpaces(p_stream, ref nCurrent);
359               while(nCurrent<=nLen)
360               {
361                   int c=PeekChar(p_stream,nCurrent);
362                   if (c==']')
363                   {
364                       nCurrent++;
365                       break;
366                   }
367                   bool noMorePairs=false;
368                   while(!noMorePairs)
369                   {
370                       JS_Value propertyValue=GetValue(p_stream, ref nCurrent);
371                       result.Elements.Add(propertyValue);
372                       SkipSpaces(p_stream, ref nCurrent);
373                       if (PeekChar(p_stream, nCurrent) != ',')
374                           noMorePairs=true;
375                       else
376                       {
377                           nCurrent++;
378                           SkipSpaces(p_stream, ref nCurrent);
379                       }
380                   }//inner while
381               }//outter while
382             p_currentPos=nCurrent;
383             return result;
384         }
385         public static JS_Object GetObject(String p_stream, ref int p_currentPos)
386         {
387               int nLen = p_stream.Length;
388               if (p_currentPos>=nLen)
389                   return null;
390               int nCurrent=p_currentPos;
391               if (PeekChar(p_stream, nCurrent) != '{')
392                   return null;
393               nCurrent++;
394               JS_Object result=new JS_Object();
395               SkipSpaces(p_stream, ref nCurrent);
396               while(nCurrent<=nLen)
397               {
398                   int c=PeekChar(p_stream,nCurrent);
399                   if (c=='}')
400                   {
401                       nCurrent++;
402                       break;
403                   }
404                   bool noMorePairs=false;
405                   while(!noMorePairs)
406                   {
407                       JS_String propertyName=GetString(p_stream, ref nCurrent);
408                       SkipSpaces(p_stream, ref nCurrent);
409                       Char c1 =NextChar(p_stream,ref nCurrent);
410                       if (c1!=':')
411                           throw Error.InvalidJsonStream;
412                       SkipSpaces(p_stream, ref nCurrent);
413                       JS_Value propertyValue=GetValue(p_stream, ref nCurrent);
414                       result.Properties.Add(propertyName.Value, propertyValue);
415                       SkipSpaces(p_stream, ref nCurrent);
416                       if (PeekChar(p_stream, nCurrent) != ',')
417                           noMorePairs=true;
418                       else
419                       {
420                           nCurrent++;
421                           SkipSpaces(p_stream, ref nCurrent);
422                       }
423                   }//inner while
424               }//outter while
425             p_currentPos=nCurrent;  
426             return result;
427         }
428         public static JS_String GetString(String p_stream, ref int p_currentPos)
429         {
430           int nLen = p_stream.Length;
431           if (p_currentPos>=nLen)
432               return null;
433           JS_String result=new JS_String();
434           int nCurrent=p_currentPos;
435           if (PeekChar(p_stream, nCurrent) != '"')
436               return null;
437           nCurrent++;
438           StringBuilder bld=new StringBuilder();
439           while(nCurrent<=nLen)
440           {
441               Char c=p_stream[nCurrent++];
442               if (c=='"')
443                   break;
444               if (c != '\\')
445               {
446                   bld.Append(c);
447                   continue;
448               }
449               c = NextChar(p_stream, ref nCurrent);
450               if (c=='"')
451                   bld.Append('"');
452               else if (c == '\\')
453                   bld.Append('\\');
454               else if (c == '/')
455                   bld.Append('/');
456               else if (c == 'b')
457                   bld.Append('\b');
458               else if (c == 't')
459                   bld.Append('\t');
460               else if (c == 'r')
461                   bld.Append('\r');
462               else if (c == 'n')
463                   bld.Append('\n');
464               else if (c == 'f')
465                   bld.Append('\f');
466               else if (c == 'u')
467               {
468                   char[] code=new Char[4];
469                   code[0]=NextChar(p_stream, ref nCurrent);
470                   code[1]=NextChar(p_stream, ref nCurrent);
471                   code[2]=NextChar(p_stream, ref nCurrent);
472                   code[3]=NextChar(p_stream, ref nCurrent);
473                   int nCodePoint=Int32.Parse(code.ToString(), NumberStyles.HexNumber);
474                   bld.Append((char)nCodePoint);
475               }
476           }//while()
477           result.Value = bld.ToString();
478           result.RawValue = p_stream.Substring(p_currentPos, nCurrent-p_currentPos);
479           p_currentPos=nCurrent;
480           return result;
481         }
482         
483     } //class JsonDecoder
484     public static class Error{
485         public static Exception InvalidJsonStream
486         {
487             get
488             {
489                 return new Exception("Invalid Json Stream");
490             }
491         }
492     }//class Error
493 }