Как найти токен json по значению, а затем удалить токен

2

У меня, например, такой Json, как в С#:

{
"Harry.firstName": "Harry",
"Harry.lastName": "Birimirski",
"Harry.recordTitle": "My title",
"Harry.SomeRepeatable": [{
        "GUID": "9dd8c7bb-64e1-452b-90d5-db2b6e505492",
        "NestedRepetable": [{
                "GUID": "05aa2161-fcc2-45a6-b0b7-8749d94a2e61",
                "nestedText": "Nested first"
            },
            {
                "GUID": "dfd67eeb-703b-4cc4-9321-b6a39084e687",
                "nestedText": "Nested first 2"
            }
        ],
        "name": "First"
    },
    {
        "GUID": "3318e544-1be8-4795-9bab-fa05de79cf46",
        "NestedRepetable": [{
            "GUID": "c1b60869-7c75-4af4-8037-be26aeca7939",
            "nestedText": "Nested second"
        }],
        "name": "Second"
    }
]
}

И я хотел бы удалить элемент из массива NestedRepetable по значению. Например, удалите элемент, содержащий GUID: 05aa2161-fcc2-45a6-b0b7-8749d94a2e61, желаемый результат будет выглядеть так:

{
"Harry.firstName": "Harry",
"Harry.lastName": "Birimirski",
"Harry.recordTitle": "My title",
"Harry.SomeRepeatable": [{
        "GUID": "9dd8c7bb-64e1-452b-90d5-db2b6e505492",
        "NestedRepetable": [
            {
                "GUID": "dfd67eeb-703b-4cc4-9321-b6a39084e687",
                "nestedText": "Nested first 2"
            }
        ],
        "name": "First"
    },
    {
        "GUID": "3318e544-1be8-4795-9bab-fa05de79cf46",
        "NestedRepetable": [{
            "GUID": "c1b60869-7c75-4af4-8037-be26aeca7939",
            "nestedText": "Nested second"
        }],
        "name": "Second"
    }
]
}

Я пробовал пару вещей с помощью Json.NET, но я не могу этого сделать. Имейте в виду, что вся структура JSON динамична. Единственное, что я знаю, это имя поля (GUID) в этом случае и значение в поле, которое должно быть удалено.

Я попытался сделать это так, как описано в этом вопросе, но они используют hardcoded путь json. Это не мое дело.

Я использовал следующий код:

        private JToken RemoveFields(JToken token, string fieldValue)
    {
        JContainer container = token as JContainer;
        if (container == null)
        {
            return token;
        }

        List<JToken> removeList = new List<JToken>();
        foreach (JToken el in container.Children())
        {
            JProperty p = el as JProperty;
            if (p != null)// && fields.Contains(p.Name))
            {
                if (p.Value.ToString() == fieldValue)
                {
                    removeList.Add(el);

                    //try to remove the whole thing, not only GUID field ..
                    //removeList.Add(el.Parent);

                }
            }

            RemoveFields(el, fieldValue);
        }

        foreach (JToken el in removeList)
        {
            el.Parent.Remove();
            return token;
        }

        return token;
    }

Но я получаю следующую ошибку:

Коллекция была изменена; операция перечисления не может выполняться "

Вероятно, потому что я пытаюсь удалить родительский элемент.

  • 0
    Если это всего лишь один удар, вы можете вернуться после удаления объекта. Поскольку вы используете итератор (foreach делает это), вы не можете добавлять или удалять элементы во время итерации, и это вызывает проблемы. Так что бы просто вернуться после удаления работы?
  • 0
    Пример, на который вы указываете, выполняет удаление после завершения итерации. Поскольку вы вызываете функцию рекурсивно, наиболее вероятно, что происходит то, что она завершает внутреннюю итерацию и пытается удалить некоторые элементы, в то время как внешняя итерация все еще выполняется. Попробуйте создать список элементов для удаления, а затем убедитесь, что вы удалили их вне любого обхода JSON
Показать ещё 3 комментария
Теги:
json.net

1 ответ

1
Лучший ответ

Вы пытаетесь найти и удалить объекты, которые соответствуют следующим критериям:

  1. Все объекты, содержащиеся в свойстве массива с именем "NestedRepetable"
  2. которые имеют свойство с именем "GUID" с определенным значением.

Самый простой способ сделать это - использовать JToken.SelectTokens() с запросом JSONPath:

var value = "05aa2161-fcc2-45a6-b0b7-8749d94a2e61";

var queryStringTemplate = "..NestedRepetable[?(@.GUID == '{0}')]";
var query = root.SelectTokens(string.Format(queryStringTemplate, value));

foreach (var obj in query.ToList())
    obj.Remove();

Если вам действительно "NestedRepetable" вложены ли объекты внутри "NestedRepetable" (на данный момент ваш вопрос неясно), вы можете просто сделать

var queryStringTemplate = "..[?(@.GUID == '{0}')]";

Заметки:

  • .. является рекурсивным спускающим оператором. Он опускает иерархию JToken возвращая все значения.

  • NestedRepetable сопоставляет значения свойств с требуемым именем.

  • [?(@.GUID == '{0}')] сопоставляет объекты, принадлежащие массиву NestedRepetable с свойством с именем GUID с указанным значением.

  • При удалении токенов, соответствующих запросу, необходимо выполнить запрос, вызвав ToList() чтобы избежать Collection was modified вы видели в Collection was modified.

  • Подробнее о синтаксисе JSONPath см. JSONPath - XPath для JSON.

Пример работы.Net скрипку здесь для сложного запроса и здесь для более простого запроса.

  • 0
    Это делает трюк, большое спасибо! Другой подход, но гораздо более четкое решение. Похоже, мне нужно потратить некоторое время, чтобы лучше понять JSONPath.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню