У меня есть следующая структура:
var content = {
"id": "RkktMTA1OC0wNTE3QElNQi82NTAwNC9YLzAwSDc",
"name": "FI-1058-0517",
"category": "FTTH",
"place": {
"id": "SU1CLzY1MDA0L1gvMDBINw",
"href": "/geographicSite/SU1CLzY1MDA0L1gvMDBINw",
"name": "IMB/65004/X/00H7",
"isSiteInfoAvailable": true,
"place": [
{
"geographicSubAddress": [
{
"internalBuildingReference": "SSS0100000000000198332600",
"internalFloorReference": "",
"buildingName": "_NA_",
"levelNumber": "0",
"levelType": "floor",
"subUnit": [
{
"subUnitNumber": "_NA_",
"subUnitType": "staircase",
"internalReference": "SSS0100000000000198332601",
"@type": "GeographicSubAddressUnitExtended",
"@baseType": "GeographicSubAddressUnit"
}
],
"@type": "GeographicSubAddressBuilding"
}
],
"@type": "GeographicAddress"
}
],
"relatedParty": [
{
"id": "FI",
"@referredType": "OI"
}
],
"@type": "GeographicSiteBuilding",
"@baseType": "GeographicSite"
},
"resourceStatus": "En service",
"usageState": "Actif",
"developerOutletReference": "",
"toBeTicketed": false,
"resourceRelationship": [
{
"id": "PT 000629",
"relationshipType": "Connected PBO",
"href": "/resource/pbo/UFQgMDAwNjI5QEZJLTY1MDU2LTAwMDM",
"@referredType": "ResourcePbo"
},
{
"id": "FI-65056-0003",
"relationshipType": "Connected PM",
"href": "/resource/pm/RkktNjUwNTYtMDAwMw",
"@referredType": "ResourcePm"
}
],
"nonOapcInfo": {
"startOperatingDate": "2023-04-01",
"endOperatingDate": null,
"predecessorIAR": ""
},
"hasFiberOpticDrawer": "",
"description": "",
"@baseType": "Resource",
"@type": "ResourcePto",
"FTTHLineStatus": [
"existant",
"actif",
"raccordable",
"commercialisable"
],
"href": "/resource/pto/RkktMTA1OC0wNTE3QElNQi82NTAwNC9YLzAwSDc"
}
Мне нужно найти значения нескольких узлов в этой структуре. Для этого я использую следующую функцию:
PropertyExists: function (obj, Field){
var DataField = Field.split('.');
if (DataField.length == 1){
if (typeof obj === 'object' && obj !== null) {
if (obj.hasOwnProperty(Field) && typeof obj[Field] === 'string') { // if this object already contains the property, we are done
return obj[Field].toLowerCase();
}
for (var p in obj) { // otherwise iterate on all the properties of this object.
console.info(p)
if ($S.PropertyExists(obj[p], Field)) {
console.info(obj[p])
console.info(Field)
return obj[p][Field].toLowerCase(); // Error line
}
}
}
return false;
} else {
if (typeof obj === 'object' && obj !== null) {
if (obj.hasOwnProperty(DataField[0]) && obj[DataField[0]].hasOwnProperty(DataField[1]) && typeof obj[DataField[0]][DataField[1]] === 'string') {
return obj[DataField[0]][DataField[1]].toLowerCase();
}
for (var p in obj) {
if ($S.PropertyExists(obj[p], Field)) {
return obj[p][DataField[0]][DataField[1]].toLowerCase();
}
}
}
return false;
}
}
При попытке использовать этот код функция работает как положено:
console.info(PropertyExists(content, 'name'))
Выходы IMB/65004/X/00H7
Но при попытке использовать этот код я получаю сообщение об ошибке: obj[p][Field] не определено в строке // Строка ошибки
console.info(PropertyExists(content, 'buildingName'))
Чего я не понимаю, так это того, что консоль показывает это, указывая, что узел был найден, но при попытке вернуть его идентификатор не существует. Журнал также показывает, что до обнаружения узел является объектом, но после этого он представляет собой массив, который должен быть источником проблемы.
Любая подсказка приветствуется, заранее спасибо!
Также обратите внимание, что в приведенном примере выводится fi-1058-0517
, а не IMB/65004/X/00H7
.
Некоторые свойства контента являются массивами или содержат массивы. Вы говорите «узнайте название здания». Что делать, если в контенте есть 4 названия зданий?
Это правда, что ваш код правильно находит свойство строкового типа, а затем возвращает соответствующее значение. Но это происходит на более глубоком уровне рекурсии, и вызывающая сторона этого рекурсивного вызова игнорирует возвращаемое значение и вместо этого ожидает найти свойство на текущем уровне вложенности. Это не верно. Если свойство существует на уровне 3, то вам не следует искать его снова, и тем более на уровне 2.
Так что просто верните то, что получили. Измените это:
if ($S.PropertyExists(obj[p], Field)) {
console.info(obj[p])
console.info(Field)
return obj[p][Field].toLowerCase(); // Error line
}
к этому:
const result = $S.PropertyExists(obj[p], Field);
if (result !== false) {
return result; // We already got the result, so just bubble it up.
}
И последнее замечание: обязательно сравнивайте с false
явно, поскольку найденное значение свойства строки может быть пустой строкой, которая является ложным значением. По этой причине вам также следует изменить следующее:
if ($S.PropertyExists(obj[p], Field)) {
к:
if ($S.PropertyExists(obj[p], Field) !== false) {
Можете ли вы описать ожидаемый результат? В вашем вопросе подробно описан формат данных и попытка кода, но неточно указано, какова цель.