Страницы

Поиск по вопросам

понедельник, 9 декабря 2019 г.

Как правильно парсить json C#

#c_sharp #json


Есть json, в котором хранятся точки, из которых, в последствии, строятся определенные
3d объекты, по сути координаты вершин. Особенность в том что лежат они на неравномерной
глубине. 



Как видно в 31-ом "наборе" точек они лежат сразу после узла "coordinates" а в 32-ом
после этого узла они делятся еще на 2 группы, а внутри группы уже искомый набор точек.
Задача состоит в том что бы дойти по узлам до элементов составляющих наборы точек
(зеленые элементы являются координатами собственно x y), собрать точки принадлежащие
одному набору в список, отправить их на обработку и дальше двигаться по json'у. Сложность
в том, что там где они делятся на группы (32-ой), надо каждую группу элементов отправлять
отдельно, как если бы это была законченная (как в случае с 31-ой, прошлись по 0,1,2
собрали точки внутри отправили пошли дальше), то есть зайти 32-geometry->coordinates->0
все что внутри собрать и отправить затем в 32-geometry->coordinate->1 собрать отправить,
затем только дальше. Логично было бы предположить что там где type: MultiLineString
можно просто добавить еще один цикл прохода по элементам, но что то мне подсказывает
что я неверно рассуждаю. Как решить эту задачу правильно с точки зрения практик парсинга
json файлов?

Извините за сумбурное описание, пытался детализировать как мог.

update вот таким образом я пытался добраться до необходимых мне данных, но данные
из 32-ой группы сливались в один list и я так и не придумал как ПРАВИЛЬНО, мне их получить.
Сейчас я понимаю судя по комментариям и ответам что я подобрался к задаче с принципиально
не той стороны.

private void CreateRoads(JSONObject mapData)
    {
        int count = 0;
        foreach (var geo in mapData["features"].list)
        {
            count++;
            var l = new List();


            for (int i = 0; i < geo["geometry"]["coordinates"].list.Count; i++)
            {
                if (!geo["geometry"]["coordinates"][i][0].IsNumber)
                {

                    for (int j = 0; j < geo["geometry"]["coordinates"][i].list.Count; j++)
                    {
                        var c = geo["geometry"]["coordinates"][i][j];
                        var bm = GM.LatLonToMeters(c[1].f, c[0].f);
                        var pm = new Vector2(bm.x - Rect.center.x, bm.y - Rect.center.y);
                        l.Add(pm.ToVector3xz());
                    }
                }
                else
                {
                    var c = geo["geometry"]["coordinates"][i];
                    var bm = GM.LatLonToMeters(c[1].f, c[0].f);
                    var pm = new Vector2(bm.x - Rect.center.x, bm.y - Rect.center.y);
                    l.Add(pm.ToVector3xz());
                }
            }

            var m = new GameObject("road_" + count.ToString()).AddComponent();
            m.transform.localPosition = new Vector3(m.transform.localPosition.x,
m.transform.localPosition.y + 1f, m.transform.localPosition.z);
            m.transform.parent = this.transform;
            try
            {
                m.Initialize(geo["properties"]["id"].str, this, l, geo["properties"]["kind"].str);
            }
            catch (Exception ex)
            {
                Debug.Log(ex);
            }
        }
    }


с десериализацией я справился, спасибо @sp7, но как разрулить разные уровни глубины
у блоков пока не пойму. Что бы это было универсально, а не хардкодом. Есть мысли на
тему прохода в глубину до последнего узла (отличается тем что у него чайлдов видимо)
от него вверх на уровень, собираем искомые данные (списки с координатами), отправляем,
уровень вверх выходим, смотрим есть ли еще на это же уровне какие то списки, нету снова
вверх если вышли до блока coordinates, то переходим к следующему номеру (33,34,35)
и тд...вот беда только в том что я не знаю как такой проход в глубину сделать. И гугление
не помогло особо =/

        var root = JsonConvert.DeserializeObject(www.text);
        var features = root.roads.features;
        List coordinates = new List();
        for (int i = 0; i < features.Length; i++)
        {
            coordinates.Add(features[i].geometry.coordinates);
        }
        ConstructRoad(coordinates);

    


Ответы

Ответ 1



Позволю себе высказаться. Как ранее было замечено, для того что бы было удобно работать с Json данными, их нужно как минимум десериализовать в объектный вид. Поэтому: 1) Если у вас есть эти Json данные в текстовом виде (string) скопируйте их в буфер обмена. Если данных в текстовом виде нет, получите их откуда-то из вне, преобразуйте в строку (как вариант, JObject.Parse().ToString()) и скопируйте в буфер обмена. 2) Создайте пустой С# файл, в нем не должно быть ничего, кроме указания namespace. Курсор ставим внутрь namespace. 3) Затем в Visual Studio заходим в меню Edit -> Paste Special -> Paste JSON as Classes. 4) Вуаля!!! Visual Studio создала за вас классы, которые представляют указанные Json данные. 5) Теперь когда классы С# готовы, Вы можете ваши Json данные используя JsonSerializer десериализовать в ту объектную модель, что за вас создала студия. var root = JsonConvert.DeserializeObject(jsonStr); 6) Ну и в завершении, теперь Вы просто можете работать с данными в удобном виде.

Ответ 2



Взгляните вот тут, как десериализуются части JSON... Здесь делается общий парсинг, а затем можно переходить на уровни и десериализовать их вот так : JObject googleSearch = JObject.Parse(googleSearchText); // get JSON result objects into a list IList results = googleSearch["responseData"]["results"].Children().ToList(); // serialize JSON results into .NET objects IList searchResults = new List(); foreach (JToken result in results) { SearchResult searchResult = JsonConvert.DeserializeObject(result.ToString()); searchResults.Add(searchResult); }

Комментариев нет:

Отправить комментарий