没看到.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 }