Использовать jQuery's find() для объекта JSON

Подобно вопросу brnwdrng, я ищу способ поиска в JSON-подобном объекте.
Предположим, что структура моего объекта выглядит так:

TestObj = {
    "Categories": [{
        "Products": [{
            "id": "a01",
            "name": "Pine",
            "description": "Short description of pine."
        },
        {
            "id": "a02",
            "name": "Birch",
            "description": "Short description of birch."
        },
        {
            "id": "a03",
            "name": "Poplar",
            "description": "Short description of poplar."
        }],
        "id": "A",
        "title": "Cheap",
        "description": "Short description of category A."
    },
    {
        "Product": [{
            "id": "b01",
            "name": "Maple",
            "description": "Short description of maple."
        },
        {
            "id": "b02",
            "name": "Oak",
            "description": "Short description of oak."
        },
        {
            "id": "b03",
            "name": "Bamboo",
            "description": "Short description of bamboo."
        }],
        "id": "B",
        "title": "Moderate",
        "description": "Short description of category B."
    }]
};

Я хотел бы получить объект с id="A".

Я пробовал все виды вещей, таких как:

$(TestObj.find(":id='A'"))

но ничего не работает.

Может ли кто-нибудь придумать способ получения предмета по некоторым критериям без использования "каждого"?

6 ответов

Решение

JQuery не работает с обычными объектными литералами. Вы можете использовать следующую функцию аналогичным образом для поиска всех идентификаторов (или любого другого свойства), независимо от его глубины в объекте:

function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            objects.push(obj);
        }
    }
    return objects;
}

Используйте вот так:

getObjects(TestObj, 'id', 'A'); // Returns an array of matching objects

Чистое решение javascript лучше, но способ jQuery - использовать jQuery grep и / или map методы. Вероятно, не намного лучше, чем использование $.each

jQuery.grep(TestObj, function(obj) {
    return obj.id === "A";
});

или же

jQuery.map(TestObj, function(obj) {
    if(obj.id === "A")
         return obj; // or return obj.name, whatever.
});

Возвращает массив совпадающих объектов или искомых значений в случае карты. Может быть в состоянии сделать то, что вы хотите, просто используя их.

Но в этом примере вам придется выполнить некоторую рекурсию, потому что данные не являются плоским массивом, и мы принимаем произвольные структуры, ключи и значения, как это делают чистые решения javascript.

function getObjects(obj, key, val) {
    var retv = [];

    if(jQuery.isPlainObject(obj))
    {
        if(obj[key] === val) // may want to add obj.hasOwnProperty(key) here.
            retv.push(obj);

        var objects = jQuery.grep(obj, function(elem) {
            return (jQuery.isArray(elem) || jQuery.isPlainObject(elem));
        });

        retv.concat(jQuery.map(objects, function(elem){
            return getObjects(elem, key, val);
        }));
    }

    return retv;
}

По сути то же самое, что и ответ Box9, но там, где это полезно, используются функции утилит jQuery.

········

Это работает для меня [{"id":"data"},{"id":"data"}]

function getObjects(obj, key, val) 
{
    var newObj = false; 
    $.each(obj, function()
    {
        var testObject = this; 
        $.each(testObject, function(k,v)
        {
            //alert(k);
            if(val == v && k == key)
            {
                newObj = testObject;
            }
        });
    });

    return newObj;
}

Для одного измерения JSON вы можете использовать это:

function exist (json, modulid) {
    var ret = 0;
    $(json).each(function(index, data){
        if(data.modulId == modulid)
            ret++;
    })
    return ret > 0;
}

Вы можете использовать JSONPath

Делать что-то вроде этого:

results = JSONPath(null, TestObj, "$..[?(@.id=='A')]")

Обратите внимание, что JSONPath возвращает массив результатов

(Кстати, я не проверял выражение "$..[?(@. Id=='A')]". Возможно, его нужно настроить с помощью консоли браузера)

Еще один вариант, который я хотел упомянуть: вы можете конвертировать ваши данные в XML, а затем использовать jQuery.find(":id='A'") так, как вы хотели.

Для этого есть плагины jQuery, например json2xml.

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

Другие вопросы по тегам