使用 Json.net 解析 JSON
Posted
技术标签:
【中文标题】使用 Json.net 解析 JSON【英文标题】:Parsing JSON using Json.net 【发布时间】: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 知道如何序列化它。
我以为我可以编写自己的简单解析器,将我需要的所有内容提取到我创建的属性对象中,但我运气不佳。
希望这一切都有意义,有什么想法吗?
【问题讨论】:
【参考方案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
对于对象列表,我可以建议使用由您自己的包含attributes
和position
类的小类组成的通用列表。您可以为 X 和 Y 使用 System.Drawing
中的 Point
结构(System.Drawing.Point
或 System.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);
【讨论】:
以上是关于使用 Json.net 解析 JSON的主要内容,如果未能解决你的问题,请参考以下文章