Парсинг JSON с использованием Json.net
Я пытаюсь разобрать некоторые JSON с помощью JSon.Net библиотека. Документация кажется немного скудной, и я смущен тем, как выполнить то, что мне нужно. Вот формат для 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 будет знать, как сериализовать это.
Я думал, что могу написать свой собственный простой парсер, чтобы просто вытащить все, что мне нужно, в объект атрибутов, который я создал, но мне мало повезло.
надеюсь, это все имеет смысл, какие-то идеи?
5 ответов:
Я не знаю о JSON.NET, но он отлично работает с
JavaScriptSerializer
СSystem.Web.Extensions.dll
(.NET 3.5 С ПАКЕТОМ ОБНОВЛЕНИЯ 1):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); } }
Edit:
Json.NET работает с использованием тех же JSON и классов.
Foo foo = JsonConvert.DeserializeObject<Foo>(json);
ссылки: сериализация и десериализация JSON с помощью Json.NET
Edit: спасибо Марк, прочитайте о проблеме struct vs class, и вы правы, спасибо!
Я склонен использовать следующий метод для выполнения того, что вы описываете, используя статический метод JSon.Net:
MyObject deserializedObject = JsonConvert.DeserializeObject<MyObject>(json);
ссылки: сериализация и десериализация JSON с помощью Json.NET
для списка объектов я могу предложить использовать общие списки, сделанные из вашего собственного небольшого класса, содержащего
attributes
иposition
класса. Вы можете использоватьPoint
struct inSystem.Drawing
(System.Drawing.Point
илиSystem.Drawing.PointF
для чисел с плавающей запятой) для вас X и Y.после создания объекта много легче получить данные, которые вы ищете, по сравнению с разбором текста, на который вы иначе смотрите.
/* * 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.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));