【问题标题】:Parsing JSON using Json.net使用 Json.net 解析 JSON
【发布时间】:2010-09-28 22:36:03
【问题描述】:

我正在尝试使用 JSon.Net 库解析一些 JSON。文档似乎有点稀疏,我对如何完成我需要的东西感到困惑。这是我需要解析的 JSON 格式。

{
    "displayFieldName" : "OBJECT_NAME", 
    "fieldAliases" : {
        "OBJECT_NAME" : "OBJECT_NAME", 
        "OBJECT_TYPE" : "OBJECT_TYPE"
    }, 
    "positionType" : "point", 
    "reference" : {
        "id" : 1111
    }, 
    "objects" : [ {
        "attributes" : {
            "OBJECT_NAME" : "test name", 
            "OBJECT_TYPE" : "test type"
        }, 
        "position" : {
            "x" : 5, 
            "y" : 7
        }
    } ]
}

我真正需要的唯一数据是对象数组中的内容。我是否有可能用 JSonTextReader 之类的东西来解析它,然后取出我想要的东西,比如 OBJECT_TYPE 和 x 和 y 位置?我似乎无法让JSonTextReader 以我想要的方式工作,而且我几乎没有找到它的使用示例。

似乎先进行序列化,然后对我的对象使用 LINQ 是理想的,我发现的每个示例都首先讨论了序列化 JSON,但我不确定如何为这种结构构建对象。特别是对象数组,它需要像一对属性和位置对象的列表。我不知道如何编码我的对象,以便 JSon.Net 知道如何序列化它。

我以为我可以编写自己的简单解析器,将我需要的所有内容提取到我创建的属性对象中,但我运气不佳。

希望这一切都有意义,有什么想法吗?

【问题讨论】:

    标签: c# parsing serialization json.net


    【解决方案1】:

    我不了解 JSON.NET,但它适用于来自 System.Web.Extensions.dll (.NET 3.5 SP1) 的 JavaScriptSerializer

    using System.Collections.Generic;
    using System.Web.Script.Serialization;
    public class NameTypePair
    {
        public string OBJECT_NAME { get; set; }
        public string OBJECT_TYPE { get; set; }
    }
    public enum PositionType { none, point }
    public class Ref
    {
        public int id { get; set; }
    }
    public class SubObject
    {
        public NameTypePair attributes { get; set; }
        public Position position { get; set; }
    }
    public class Position
    {
        public int x { get; set; }
        public int y { get; set; }
    }
    public class Foo
    {
        public Foo() { objects = new List<SubObject>(); }
        public string displayFieldName { get; set; }
        public NameTypePair fieldAliases { get; set; }
        public PositionType positionType { get; set; }
        public Ref reference { get; set; }
        public List<SubObject> objects { get; set; }
    }
    static class Program
    {
    
        const string json = @"{
      ""displayFieldName"" : ""OBJECT_NAME"", 
      ""fieldAliases"" : {
        ""OBJECT_NAME"" : ""OBJECT_NAME"", 
        ""OBJECT_TYPE"" : ""OBJECT_TYPE""
      }, 
      ""positionType"" : ""point"", 
      ""reference"" : {
        ""id"" : 1111
      }, 
      ""objects"" : [
        {
          ""attributes"" : {
            ""OBJECT_NAME"" : ""test name"", 
            ""OBJECT_TYPE"" : ""test type""
          }, 
          ""position"" : 
          {
            ""x"" : 5, 
            ""y"" : 7
          }
        }
      ]
    }";
    
    
        static void Main()
        {
            JavaScriptSerializer ser = new JavaScriptSerializer();
            Foo foo = ser.Deserialize<Foo>(json);
        }
    
    
    }
    

    编辑:

    Json.NET 使用相同的 JSON 和类工作。

    Foo foo = JsonConvert.DeserializeObject<Foo>(json);
    

    链接:Serializing and Deserializing JSON with Json.NET

    【讨论】:

    • 有没有办法将 JSON 字符串中的名称值对转换为现有的 C# 变量类型(例如数组或字典?),这样就不必创建特定/自定义类?在我的例子中,JSON 字符串将在 Ruby/Rails 中生成...
    • 我不想构建大量类来反序列化 - 是否有等效于 XElement 的方法可以让我在 JSON 对象上使用 LINQ?
    • @Marc Gravell:非常感谢!我对 JSON 一无所知。但是这个例子让我可以轻松地为我的应用程序创建配置文件(具有层次结构)。
    • @Peter17:您不应该使用 JSON 进行配置; .NET 框架中有一个基础结构,它允许在配置文件中进行分层配置部分;使用您的自定义解决方案,人们现在不得不担心 .config 文件您的自定义配置部分。
    • 如何从内部 "Object_name" 和 "Object_Type" 即 ""test name"" 和 ""test type"" 中获取值?您能否为此编辑您的解决方案?
    【解决方案2】:

    编辑:感谢 Marc,阅读 struct vs class 问题,你是对的,谢谢!

    我倾向于使用以下方法来做你描述的事情,使用 JSon.Net 的静态方法:

    MyObject deserializedObject = JsonConvert.DeserializeObject<MyObject>(json);
    

    链接:Serializing and Deserializing JSON with Json.NET

    对于对象列表,我可以建议使用由您自己的包含attributesposition 类的小类组成的通用列表。您可以为 X 和 Y 使用 System.Drawing 中的 Point 结构(System.Drawing.PointSystem.Drawing.PointF 用于浮点数)。

    在创建对象后,与您正在查看的文本解析相比,获取所需的数据要容易得多

    【讨论】:

    • 结构在这里很少(如果有的话)是一个不错的选择;坚持对象(类)。
    【解决方案3】:

    (这个问题在搜索引擎结果中排名靠前,但我最终使用了不同的方法。为这个老问题添加一个答案,以防其他有类似问题的人读到这个)

    你可以用 Json.Net 解决这个问题,并制作一个扩展方法来处理你想要循环的项目:

    public static Tuple<string, int, int> ToTuple(this JToken token)
    {
        var type = token["attributes"]["OBJECT_TYPE"].ToString();
        var x = token["position"]["x"].Value<int>();
        var y = token["position"]["y"].Value<int>();
        return new Tuple<string, int, int>(type, x, y);
    }
    

    然后像这样访问数据:(场景:写入控制台):

    var tuples = JObject.Parse(myJsonString)["objects"].Select(item => item.ToTuple()).ToList();
    tuples.ForEach(t => Console.WriteLine("{0}: ({1},{2})", t.Item1, t.Item2, t.Item3));
    

    【讨论】:

      【解决方案4】:
      /*
           * This method takes in JSON in the form returned by javascript's
           * JSON.stringify(Object) and returns a string->string dictionary.
           * This method may be of use when the format of the json is unknown.
           * You can modify the delimiters, etc pretty easily in the source
           * (sorry I didn't abstract it--I have a very specific use).
           */ 
          public static Dictionary<string, string> jsonParse(string rawjson)
          {
              Dictionary<string, string> outdict = new Dictionary<string, string>();
              StringBuilder keybufferbuilder = new StringBuilder();
              StringBuilder valuebufferbuilder = new StringBuilder();
              StringReader bufferreader = new StringReader(rawjson);
      
              int s = 0;
              bool reading = false;
              bool inside_string = false;
              bool reading_value = false;
              //break at end (returns -1)
              while (s >= 0)
              {
                  s = bufferreader.Read();
                  //opening of json
                  if (!reading)
                  {
                      if ((char)s == '{' && !inside_string && !reading) reading = true;
                      continue;
                  }
                  else
                  {
                      //if we find a quote and we are not yet inside a string, advance and get inside
                      if (!inside_string)
                      {
                          //read past the quote
                          if ((char)s == '\"') inside_string = true;
                          continue;
                      }
                      if (inside_string)
                      {
                          //if we reached the end of the string
                          if ((char)s == '\"')
                          {
                              inside_string = false;
                              s = bufferreader.Read(); //advance pointer
                              if ((char)s == ':')
                              {
                                  reading_value = true;
                                  continue;
                              }
                              if (reading_value && (char)s == ',')
                              {
                                  //we know we just ended the line, so put itin our dictionary
                                  if (!outdict.ContainsKey(keybufferbuilder.ToString())) outdict.Add(keybufferbuilder.ToString(), valuebufferbuilder.ToString());
                                  //and clear the buffers
                                  keybufferbuilder.Clear();
                                  valuebufferbuilder.Clear();
                                  reading_value = false;
                              }
                              if (reading_value && (char)s == '}')
                              {
                                  //we know we just ended the line, so put itin our dictionary
                                  if (!outdict.ContainsKey(keybufferbuilder.ToString())) outdict.Add(keybufferbuilder.ToString(), valuebufferbuilder.ToString());
                                  //and clear the buffers
                                  keybufferbuilder.Clear();
                                  valuebufferbuilder.Clear();
                                  reading_value = false;
                                  reading = false;
                                  break;
                              }
                          }
                          else
                          {
                              if (reading_value)
                              {
                                  valuebufferbuilder.Append((char)s);
                                  continue;
                              }
                              else
                              {
                                  keybufferbuilder.Append((char)s);
                                  continue;
                              }
                          }
                      }
                      else
                      {
                          switch ((char)s)
                          {
                              case ':':
                                  reading_value = true;
                                  break;
                              default:
                                  if (reading_value)
                                  {
                                      valuebufferbuilder.Append((char)s);
                                  }
                                  else
                                  {
                                      keybufferbuilder.Append((char)s);
                                  }
                                  break;
                          }
                      }
                  }
              }
              return outdict;
          }
      

      【讨论】:

      • 虽然这个答案似乎适用于没有数组/列表的 JSON,但它根本无法处理 [] 字符(分隔数组或列表结构)的存在。
      • 您似乎在这里重新实现了 JSON 反序列化。由于许多不同的原因,我认为这是一个非常糟糕的问题解决方案。查看最受好评的答案以获得更好的方法。
      【解决方案5】:

      您使用JSON 类,然后调用GetData() 函数。

      /// <summary>
      /// This class encodes and decodes JSON strings.
      /// Spec. details, see http://www.json.org/
      ///
      /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable.
      /// All numbers are parsed to doubles.
      /// </summary>
          using System;
          using System.Collections;
          using System.Globalization;
          using System.Text;
      
      public class JSON
      {
          public const int TOKEN_NONE = 0;
          public const int TOKEN_CURLY_OPEN = 1;
          public const int TOKEN_CURLY_CLOSE = 2;
          public const int TOKEN_SQUARED_OPEN = 3;
          public const int TOKEN_SQUARED_CLOSE = 4;
          public const int TOKEN_COLON = 5;
          public const int TOKEN_COMMA = 6;
          public const int TOKEN_STRING = 7;
          public const int TOKEN_NUMBER = 8;
          public const int TOKEN_TRUE = 9;
          public const int TOKEN_FALSE = 10;
          public const int TOKEN_NULL = 11;
      
          private const int BUILDER_CAPACITY = 2000;
      
          /// <summary>
          /// Parses the string json into a value
          /// </summary>
          /// <param name="json">A JSON string.</param>
          /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns>
          public static object JsonDecode(string json)
          {
              bool success = true;
      
              return JsonDecode(json, ref success);
          }
      
          /// <summary>
          /// Parses the string json into a value; and fills 'success' with the successfullness of the parse.
          /// </summary>
          /// <param name="json">A JSON string.</param>
          /// <param name="success">Successful parse?</param>
          /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns>
          public static object JsonDecode(string json, ref bool success)
          {
              success = true;
              if (json != null) {
                  char[] charArray = json.ToCharArray();
                  int index = 0;
                  object value = ParseValue(charArray, ref index, ref success);
                  return value;
              } else {
                  return null;
              }
          }
      
          /// <summary>
          /// Converts a Hashtable / ArrayList object into a JSON string
          /// </summary>
          /// <param name="json">A Hashtable / ArrayList</param>
          /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
          public static string JsonEncode(object json)
          {
              StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);
              bool success = SerializeValue(json, builder);
              return (success ? builder.ToString() : null);
          }
      
          protected static Hashtable ParseObject(char[] json, ref int index, ref bool success)
          {
              Hashtable table = new Hashtable();
              int token;
      
              // {
              NextToken(json, ref index);
      
              bool done = false;
              while (!done) {
                  token = LookAhead(json, index);
                  if (token == JSON.TOKEN_NONE) {
                      success = false;
                      return null;
                  } else if (token == JSON.TOKEN_COMMA) {
                      NextToken(json, ref index);
                  } else if (token == JSON.TOKEN_CURLY_CLOSE) {
                      NextToken(json, ref index);
                      return table;
                  } else {
      
                      // name
                      string name = ParseString(json, ref index, ref success);
                      if (!success) {
                          success = false;
                          return null;
                      }
      
                      // :
                      token = NextToken(json, ref index);
                      if (token != JSON.TOKEN_COLON) {
                          success = false;
                          return null;
                      }
      
                      // value
                      object value = ParseValue(json, ref index, ref success);
                      if (!success) {
                          success = false;
                          return null;
                      }
      
                      table[name] = value;
                  }
              }
      
              return table;
          }
      
          protected static ArrayList ParseArray(char[] json, ref int index, ref bool success)
          {
              ArrayList array = new ArrayList();
      
              // [
              NextToken(json, ref index);
      
              bool done = false;
              while (!done) {
                  int token = LookAhead(json, index);
                  if (token == JSON.TOKEN_NONE) {
                      success = false;
                      return null;
                  } else if (token == JSON.TOKEN_COMMA) {
                      NextToken(json, ref index);
                  } else if (token == JSON.TOKEN_SQUARED_CLOSE) {
                      NextToken(json, ref index);
                      break;
                  } else {
                      object value = ParseValue(json, ref index, ref success);
                      if (!success) {
                          return null;
                      }
      
                      array.Add(value);
                  }
              }
      
              return array;
          }
      
          protected static object ParseValue(char[] json, ref int index, ref bool success)
          {
              switch (LookAhead(json, index)) {
                  case JSON.TOKEN_STRING:
                      return ParseString(json, ref index, ref success);
                  case JSON.TOKEN_NUMBER:
                      return ParseNumber(json, ref index, ref success);
                  case JSON.TOKEN_CURLY_OPEN:
                      return ParseObject(json, ref index, ref success);
                  case JSON.TOKEN_SQUARED_OPEN:
                      return ParseArray(json, ref index, ref success);
                  case JSON.TOKEN_TRUE:
                      NextToken(json, ref index);
                      return true;
                  case JSON.TOKEN_FALSE:
                      NextToken(json, ref index);
                      return false;
                  case JSON.TOKEN_NULL:
                      NextToken(json, ref index);
                      return null;
                  case JSON.TOKEN_NONE:
                      break;
              }
      
              success = false;
              return null;
          }
      
          protected static string ParseString(char[] json, ref int index, ref bool success)
          {
              StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
              char c;
      
              EatWhitespace(json, ref index);
      
              // "
              c = json[index++];
      
              bool complete = false;
              while (!complete) {
      
                  if (index == json.Length) {
                      break;
                  }
      
                  c = json[index++];
                  if (c == '"') {
                      complete = true;
                      break;
                  } else if (c == '\\') {
      
                      if (index == json.Length) {
                          break;
                      }
                      c = json[index++];
                      if (c == '"') {
                          s.Append('"');
                      } else if (c == '\\') {
                          s.Append('\\');
                      } else if (c == '/') {
                          s.Append('/');
                      } else if (c == 'b') {
                          s.Append('\b');
                      } else if (c == 'f') {
                          s.Append('\f');
                      } else if (c == 'n') {
                          s.Append('\n');
                      } else if (c == 'r') {
                          s.Append('\r');
                      } else if (c == 't') {
                          s.Append('\t');
                      } else if (c == 'u') {
                          int remainingLength = json.Length - index;
                          if (remainingLength >= 4) {
                              // parse the 32 bit hex into an integer codepoint
                              uint codePoint;
                              if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) {
                                  return "";
                              }
                              // convert the integer codepoint to a unicode char and add to string
                              s.Append(Char.ConvertFromUtf32((int)codePoint));
                              // skip 4 chars
                              index += 4;
                          } else {
                              break;
                          }
                      }
      
                  } else {
                      s.Append(c);
                  }
      
              }
      
              if (!complete) {
                  success = false;
                  return null;
              }
      
              return s.ToString();
          }
      
          protected static double ParseNumber(char[] json, ref int index, ref bool success)
          {
              EatWhitespace(json, ref index);
      
              int lastIndex = GetLastIndexOfNumber(json, index);
              int charLength = (lastIndex - index) + 1;
      
              double number;
              success = Double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
      
              index = lastIndex + 1;
              return number;
          }
      
          protected static int GetLastIndexOfNumber(char[] json, int index)
          {
              int lastIndex;
      
              for (lastIndex = index; lastIndex < json.Length; lastIndex++) {
                  if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) {
                      break;
                  }
              }
              return lastIndex - 1;
          }
      
          protected static void EatWhitespace(char[] json, ref int index)
          {
              for (; index < json.Length; index++) {
                  if (" \t\n\r".IndexOf(json[index]) == -1) {
                      break;
                  }
              }
          }
      
          protected static int LookAhead(char[] json, int index)
          {
              int saveIndex = index;
              return NextToken(json, ref saveIndex);
          }
      
          protected static int NextToken(char[] json, ref int index)
          {
              EatWhitespace(json, ref index);
      
              if (index == json.Length) {
                  return JSON.TOKEN_NONE;
              }
      
              char c = json[index];
              index++;
              switch (c) {
                  case '{':
                      return JSON.TOKEN_CURLY_OPEN;
                  case '}':
                      return JSON.TOKEN_CURLY_CLOSE;
                  case '[':
                      return JSON.TOKEN_SQUARED_OPEN;
                  case ']':
                      return JSON.TOKEN_SQUARED_CLOSE;
                  case ',':
                      return JSON.TOKEN_COMMA;
                  case '"':
                      return JSON.TOKEN_STRING;
                  case '0': case '1': case '2': case '3': case '4':
                  case '5': case '6': case '7': case '8': case '9':
                  case '-':
                      return JSON.TOKEN_NUMBER;
                  case ':':
                      return JSON.TOKEN_COLON;
              }
              index--;
      
              int remainingLength = json.Length - index;
      
              // false
              if (remainingLength >= 5) {
                  if (json[index] == 'f' &&
                      json[index + 1] == 'a' &&
                      json[index + 2] == 'l' &&
                      json[index + 3] == 's' &&
                      json[index + 4] == 'e') {
                      index += 5;
                      return JSON.TOKEN_FALSE;
                  }
              }
      
              // true
              if (remainingLength >= 4) {
                  if (json[index] == 't' &&
                      json[index + 1] == 'r' &&
                      json[index + 2] == 'u' &&
                      json[index + 3] == 'e') {
                      index += 4;
                      return JSON.TOKEN_TRUE;
                  }
              }
      
              // null
              if (remainingLength >= 4) {
                  if (json[index] == 'n' &&
                      json[index + 1] == 'u' &&
                      json[index + 2] == 'l' &&
                      json[index + 3] == 'l') {
                      index += 4;
                      return JSON.TOKEN_NULL;
                  }
              }
      
              return JSON.TOKEN_NONE;
          }
      
          protected static bool SerializeValue(object value, StringBuilder builder)
          {
              bool success = true;
      
              if (value is string) {
                  success = SerializeString((string)value, builder);
              } else if (value is Hashtable) {
                  success = SerializeObject((Hashtable)value, builder);
              } else if (value is ArrayList) {
                  success = SerializeArray((ArrayList)value, builder);
              } else if ((value is Boolean) && ((Boolean)value == true)) {
                  builder.Append("true");
              } else if ((value is Boolean) && ((Boolean)value == false)) {
                  builder.Append("false");
              } else if (value is ValueType) {
                  // thanks to ritchie for pointing out ValueType to me
                  success = SerializeNumber(Convert.ToDouble(value), builder);
              } else if (value == null) {
                  builder.Append("null");
              } else {
                  success = false;
              }
              return success;
          }
      
          protected static bool SerializeObject(Hashtable anObject, StringBuilder builder)
          {
              builder.Append("{");
      
              IDictionaryEnumerator e = anObject.GetEnumerator();
              bool first = true;
              while (e.MoveNext()) {
                  string key = e.Key.ToString();
                  object value = e.Value;
      
                  if (!first) {
                      builder.Append(", ");
                  }
      
                  SerializeString(key, builder);
                  builder.Append(":");
                  if (!SerializeValue(value, builder)) {
                      return false;
                  }
      
                  first = false;
              }
      
              builder.Append("}");
              return true;
          }
      
          protected static bool SerializeArray(ArrayList anArray, StringBuilder builder)
          {
              builder.Append("[");
      
              bool first = true;
              for (int i = 0; i < anArray.Count; i++) {
                  object value = anArray[i];
      
                  if (!first) {
                      builder.Append(", ");
                  }
      
                  if (!SerializeValue(value, builder)) {
                      return false;
                  }
      
                  first = false;
              }
      
              builder.Append("]");
              return true;
          }
      
          protected static bool SerializeString(string aString, StringBuilder builder)
          {
              builder.Append("\"");
      
              char[] charArray = aString.ToCharArray();
              for (int i = 0; i < charArray.Length; i++) {
                  char c = charArray[i];
                  if (c == '"') {
                      builder.Append("\\\"");
                  } else if (c == '\\') {
                      builder.Append("\\\\");
                  } else if (c == '\b') {
                      builder.Append("\\b");
                  } else if (c == '\f') {
                      builder.Append("\\f");
                  } else if (c == '\n') {
                      builder.Append("\\n");
                  } else if (c == '\r') {
                      builder.Append("\\r");
                  } else if (c == '\t') {
                      builder.Append("\\t");
                  } else {
                      int codepoint = Convert.ToInt32(c);
                      if ((codepoint >= 32) && (codepoint <= 126)) {
                          builder.Append(c);
                      } else {
                          builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0'));
                      }
                  }
              }
      
              builder.Append("\"");
              return true;
          }
      
          protected static bool SerializeNumber(double number, StringBuilder builder)
          {
              builder.Append(Convert.ToString(number, CultureInfo.InvariantCulture));
              return true;
          }
      }
      
      //parse and show entire json in key-value pair
          Hashtable HTList = (Hashtable)JSON.JsonDecode("completejsonstring");
              public void GetData(Hashtable HT)
              {           
                  IDictionaryEnumerator ienum = HT.GetEnumerator();
                  while (ienum.MoveNext())
                  {
                      if (ienum.Value is ArrayList)
                      {
                          ArrayList arnew = (ArrayList)ienum.Value;
                          foreach (object obj in arnew)                    
                          {
                              Hashtable hstemp = (Hashtable)obj;
                              GetData(hstemp);
                          }
                      }
                      else
                      {
                          Console.WriteLine(ienum.Key + "=" + ienum.Value);
                      }
                  }
              }
      

      【讨论】:

        猜你喜欢
        • 2014-03-05
        • 2014-11-19
        • 2013-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多