2012-01-26 16 views
11

Я пытаюсь последовательно анализировать JSON, т. Е. На основе условия.Инкрементный JSON-анализ в C#

Ниже приведено мое сообщение json, и в настоящее время я использую JavaScriptSerializer для десериализации сообщения.

string json = @"{"id":2, 
"method":"add", 
"params": 
    {"object": 
     {"name":"test" 
     "id":"1"}, 
     "position":"1"} 
    }"; 

JavaScriptSerializer js = new JavaScriptSerializer(); 
Message m = js.Deserialize<Message>(json); 

класс сообщений показан ниже:

public class Message 
{ 
     public string id { get; set; } 
     public string method { get; set; } 
     public Params @params { get; set; } 
     public string position { get; set; } 
} 
public class Params 
{ 
     public string name { get; set; } 
     public string id{ get; set; 
} 

Приведенный выше код разбирает сообщение без проблем. Но он анализирует весь JSON сразу. Я хочу, чтобы он продолжал синтаксический анализ только в том случае, если значение параметра «method» равно «add». Если это не «добавить», я не хочу, чтобы он продолжал разбирать остальную часть сообщения. Есть ли способ сделать инкрементный синтаксический анализ на основе условия в C#? (Окружающая среда: VS 2008 с .Net 3.5)

+2

Разбор Json - это критическая для вас производительность? – CodesInChaos

+0

Почему именно вы хотите это сделать? Разве анализируемый объект занимает слишком много памяти? Или это слишком медленно (вы это измерили?)? Или у вас есть другая причина? – svick

ответ

14

Должен признать, что я не так хорошо знаком с JavaScriptSerializer, но если вы открыты для использования JSON.net, у него есть JsonReader, который действует как DataReader.

using(var jsonReader = new JsonTextReader(myTextReader)){ 
    while(jsonReader.Read()){ 
    //evaluate the current node and whether it's the name you want 
    if(jsonReader.TokenType.PropertyName=="add"){ 
     //do what you want 
    } else { 
     //break out of loop. 
    } 
    } 
} 
+0

Это сработало! Большой! Спасибо .. – user591410

+0

Рад, что я мог помочь! –

+0

Проверяет ли синтаксис? Или он оставляет структуру JSON на усмотрение разработчика? – SerG

0

В чем причина такого подхода? Если речь идет о производительности, то это, скорее всего, «преждевременная оптимизация», или, другими словами, беспокоиться о проблеме, которая может не существовать.

Я настоятельно призываю вас не беспокоиться об этой детали. Создайте свое приложение, а затем, если оно недостаточно быстро, используйте инструменты профилирования для определения фактических узких мест - они, вероятно, не будут там, где вы ожидаете.

Сосредоточение внимания на производительности, прежде чем знать, что это проблема, почти всегда приводит к потере времени и чрезмерному коду.

+3

Определенно действительная точка, и у меня возникает ощущение, что вы правы, но это не отвечает на вопрос OP. –

+0

Спасибо за ваши данные. Вы правы, но сообщение json, которое было проиллюстрировано в моем вопросе, не является фактическим сообщением, оно выглядит так (показано ниже). Поэтому я хочу анализировать только то, что необходимо на основе условия. '{" id ": 2, " method ":" add ", " params ": {" object ": {" name ":" test ", " key2 ":" value2 ".... «key100»: «значение: 100»}, «позиция»: «1»} } »; – user591410

+0

@ user591410, если вы полностью разобрали ненужное сообщение, сколько секунд вы потеряете? –

1

Вы бы желая SAX типа парсер JSON

http://en.wikipedia.org/wiki/Simple_API_for_XML

http://www.saxproject.org/event.html

SAX вызывает событие, как он разбирает каждую часть документа.

Выполнение чего-то подобного в JSON было бы довольно простым, учитывая, насколько прост синтаксис JSON.

Этот вопрос может быть помощь: Is there a streaming API for JSON?

И еще одно звено: https://www.p6r.com/articles/2008/05/22/a-sax-like-parser-for-json/

+0

Спасибо за ссылки .. будет исследовать его. – user591410

5

Если вы посмотрите на Json.NET, она обеспечивает не кэширование, только вперед JSON парсер, который будет отвечать вашим потребностям ,

См. JsonReader и JsonTextReader класс в documentation.

+0

Получил это ... Спасибо за указатели .. – user591410

+0

[Дезабилизация частичных фрагментов JSON] (http: //www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm) –

8

Вот общие и простые методы, которые я использую для синтаксического анализа, загрузки и создания очень больших файлов JSON. В этом коде используется довольно стандартная библиотека JSON.Net. К сожалению, документация не очень понятна в отношении того, как это сделать, но также не очень сложно это понять.

Ниже приведен код сценария, в котором у вас есть большое количество объектов, которые вы хотите сериализовать как массив JSON, и наоборот.Мы хотим поддерживать очень большие размеры файлов, размер которых ограничен только вашим устройством хранения (а не памятью). Поэтому при сериализации метод принимает IEnumerable<T>, а при десериализации он возвращает то же самое. Таким образом, вы можете обрабатывать весь файл, не ограничиваясь памятью.

У меня есть used this code размер файлов в несколько ГБ с разумной производительностью.

//Serialize sequence of objects as JSON array in to a specified file 
public static void SerializeSequenceToJson<T>(this IEnumerable<T> sequence, string fileName) 
{ 
    using (var fileStream = File.CreateText(fileName)) 
     SerializeSequenceToJson(sequence, fileStream); 
} 

//Deserialize specified file in to IEnumerable assuming it has array of JSON objects 
public static IEnumerable<T> DeserializeSequenceFromJson<T>(string fileName) 
{ 
    using (var fileStream = File.OpenText(fileName)) 
     foreach (var responseJson in DeserializeSequenceFromJson<T>(fileStream)) 
      yield return responseJson; 
} 

//Utility methods to operate on streams instead of file 
public static void SerializeSequenceToJson<T>(this IEnumerable<T> sequence, TextWriter writeStream, Action<T, long> progress = null) 
{ 
    using (var writer = new JsonTextWriter(writeStream)) 
    { 
     var serializer = new JsonSerializer(); 
     writer.WriteStartArray(); 
     long index = 0; 
     foreach (var item in sequence) 
     { 
      if (progress != null) 
       progress(item, index++); 

      serializer.Serialize(writer, item); 
     } 
     writer.WriteEnd(); 
    } 
} 
public static IEnumerable<T> DeserializeSequenceFromJson<T>(TextReader readerStream) 
{ 
    using (var reader = new JsonTextReader(readerStream)) 
    { 
     var serializer = new JsonSerializer(); 
     if (!reader.Read() || reader.TokenType != JsonToken.StartArray) 
      throw new Exception("Expected start of array in the deserialized json string"); 

     while (reader.Read()) 
     { 
      if (reader.TokenType == JsonToken.EndArray) break; 
      var item = serializer.Deserialize<T>(reader); 
      yield return item; 
     } 
    } 
} 
2

Я нахожусь в часе 3 неизвестного времени, наблюдая за 160 ГБ JSON, получая десериализацию в объекты класса. Мое использование памяти сильно зависало при ~ 350 МБ, и когда я проверяю объекты памяти, все это может помочь GC. Вот что я сделал:

FileStream fs = File.Open("F:\\Data\\mysuperbig150GB.json", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 
    StreamReader sr = new StreamReader(fs); 

    using (JsonReader reader = new JsonTextReader(sr)) 
    { 
     JsonSerializer serializer = new JsonSerializer(); 

     MyJsonToClass result = serializer.Deserialize<MyJsonToClass>(reader); 
    } 

Проблема заключается в десериализации. Это 160 ГБ данных намного больше, чем мой компьютер может обрабатывать сразу.

  1. Я использовал небольшой фрагмент кода (который является жестким, даже просто открыть файл 160GB) и получил классовую структуру с помощью jsontochsarp.

  2. Я создал специальный класс для большой коллекции в структуре класса с автогенератором через json-tool и подклассифицировал System.Collection.ObjectModel.ObservableCollection вместо списка. Они оба реализуют IEnumberable, и я думаю, что это все, что касается десериализатора Newtsonsoft JSON.

  3. Я вошел и отменяю InsertItem, как это:

    protected override void InsertItem(int index, Feature item) 
    { 
        //do something with the item that just got deserialized 
        //stick it in a database, etc. 
        RemoveItem(0); 
    } 
    

Опять же, мои проблемы, где частично о скорости десериализации JSON, но кроме этого я не мог вместить ~ 160 данных JSON в коллекцию , Даже затянулось, это было бы в десятках концертных площадок, намного больше, чем .net будет доволен.

InsertItem on ObservableCollection - единственный метод, который я знаю о том, что вы можете справиться, когда происходит десериализация. List.Add() нет. Я знаю, что это решение не «элегантно», но оно работает, когда я печатаю это.

Смежные вопросы