Проверьте, существуют ли ключи/узлы JSON

Я использую API карт Google для извлечения информации о городе и состоянии/регионе из поиска почтового кода. Проблема в том, что в некоторых случаях поиск почтового кода не будет получать название города. Пример: 92625 (U.S).

var g = new GClientGeocoder();
g.setBaseCountryCode('US');
g.getLocations('92625', function(response){
    if (response) {
        var place = response.Placemark[0];
        var state = place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName;
        var city  = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
        GLog.write("City = "+city+" : State/Region = "+state+" : Country = " + g.getBaseCountryCode());
    }
});

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

Я смог исправить это...

    if (place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality != null)
        var city  = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
    else
        var city = '';

... но у меня есть параноик по поводу аналогичной ошибки для других ключей. Например: если AdministrativeArea undefined, указанный выше оператор IF также вызывает ошибку undefined. Поэтому следует ли проверять, существует ли каждый ключ /Node? Кажется, это грязный подход, потому что некоторые из этих клавиш имеют глубину более 5 уровней... есть ли более простой способ сделать это, может быть, какой-то метод JQuery, с которым я не знаком?

Ответы

Ответ 1

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

function valueOrDefault(val, def) {
    if (def == undefined) def = "";
    return val == undefined ? def : val;
}

И затем используйте его следующим образом:

var place = response.Placemark[0];
var state = valueOrDefault(place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName);
var city  = valueOrDefault(place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName);

Лично я считаю, что это немного лучше писать, чем предложение p00ya, хотя это немного взломано, играя в объектах undefined... можно было бы изменить его на это:

function drill(p, a) {
 a = a.split(".");//add this
 for (i in a) {
  var key = a[i];
  if (p[key] == null)
    return '';
  p = p[key];
 }
 return p;
}
var obj = {foo:{bar:{baz:"quux"}}};
var s = drill(obj, "foo.bar.baz"));//and you can use a simple property chain

Ответ 2

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

function drill(p, a) {
 for (i in a) {
  var key = a[i];
  if (p[key] == null)
    return '';
  p = p[key];
 }
 return p;
}
var obj = {foo:{bar:{baz:"quux"}}};
var s = drill(obj, ["foo", "bar", "baz"]));

Ответ 3

Мне нравится подход back2dos, но я думаю, что его можно было бы улучшить, чтобы не сбой с ReferenceError s:

function jPath(obj, a) {
    a = a.split(".");
    var p = obj||{};
    for (var i in a) {
        if (p === null || typeof p[a[i]] === 'undefined') return null;
        p = p[a[i]];
    }
    return p;
}

// Tests
var a = {b:{c:'Hello World!'}, c:null};

console.log(jPath(a, 'b.c'));   // Hello World
console.log(jPath(a, 'b.d'));   // null
console.log(jPath(a, 'e.f.g')); // null
console.log(jPath(a, 'c'));     // null

var z;
console.log(jPath(z, 'c'));     // null

Эта функция отлично подходит для проверки глубинных структур возврата JSON из служб AJAX, таких как freebase или YQL.

Ответ 4

Вы смотрите только на первый результат, который дает геокодер:

var place = response.Placemark[0];

getLocations() возвращает список нескольких результатов. Если первый не имеет этого, один из следующих результатов почти наверняка будет.