遍历子节点并查找属性(最多n个级别)

时间:2017-02-03 10:58:52

标签: javascript json recursion

我们有一个JSON文件:

var response = {
  "Status": "Met",
  "Text": "Text1",
  "Id": "AAA",
  "ContentItems": [
    {
      "Selected": true,
      "Text": "Text2",
      "Id": "BBB"
    },
    {
      "Status": "Met",
      "Text": "Text3",
      "Id": "CCC",          
      "ContentItems": [
        {
          "Selected": true,
          "Text": "Text5",
          "Id": "DDD"
        },
        {
          "Status": "Met",
          "Text": "Text6",
          "Id": "EEE",
          "ContentItems": [
            {
              "Selected": true,
              "Text": "Text7",
              "Id": "FFF"
            },
            {
              "Selected": true,
              "Text": "Text8",
              "Id": "GGG"
            },
            {
              "Status": "Met",
              "Text": "Text9",
              "Id": "III",
              "ContentItems": [
                {
                  "Status": "Met",
                  "Text": "Text11",
                  "Id": "JJJ",
                  "ContentItems": [
                    {
                      "Text": "Text12",
                      "Id": "77"
                    },
                    {
                      "Status": "Met",
                      "Text": "Text13",
                      "Id": "10",
                      "ContentItems": [
                        {
                          "Text": "Text14",
                          "Id": "45"
                        },
                        {
                          "Selected": true,
                          "Text": "Text15",
                          "Id": "87"
                        },
                        {
                          "Selected": true,
                          "Text": "Text16",
                          "Id": "80"
                        }
                      ]
                    }                            
                  ]
                },
                {
                  "Status": "Met",
                  "Text": "Text17",
                  "Id": "KKK",
                  "ContentItems": [
                    {
                      "Text": "Text18",
                      "Id": "12"
                    },
                    {
                      "Status": "NotMet",
                      "Text": "Text19",
                      "Id": "14",
                      "ContentItems": [
                        {
                          "Text": "Text20",
                          "Id": "55"
                        },
                        {
                          "Selected": true,
                          "Text": "Text21",
                          "Id": "98"
                        }
                      ]
                    }                            
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
};

从JSON文件中我们需要以下内容:

1.如果所有“状态”都是“遇到”,则返回true。

2.如果任何“状态”为“NotMet”,则返回false。

由于子节点可以是任何级别的深度;我使用递归函数遍历每个节点,然后从那里循环遍历子节点并递归调用该函数。

我尝试了这段代码,但它没有按预期工作。

function isStatusMet(response) {
  if (response.Status == 'NotMet') {
    return false;
  } else {
    if (response.ContentItems) {
      if(Array.isArray(response.ContentItems)) {
        for(var i = 0; i < response.ContentItems.length;i++) {
          if (response.ContentItems[i].ContentItems) {
            return isStatusMet(response.ContentItems[i]);
          } else {
            if (response.ContentItems[i].Status == 'NotMet') {
              return false;
            } else {
              continue;
            }
          }
        }
        return true;
      }
    } 
  }
}

3 个答案:

答案 0 :(得分:1)

声明return isStatusMet(response.ContentItems[i]);将在任何状态下提前退出。如果递归调用回答false,它应该只返回false,否则循环需要继续。

将其更改为:

if (response.ContentItems[i].ContentItems) {
    if (!isStatusMet(response.ContentItems[i])) return false;
}

答案 1 :(得分:1)

如果ContentItems是一个数组,您可以使用Array#every并递归使用它。

var data = { Status: "Met", Text: "Text1", Id: "AAA", ContentItems: [{ Selected: true, Text: "Text2", Id: "BBB" }, { Status: "Met", Text: "Text3", Id: "CCC", ContentItems: [{ Selected: true, Text: "Text5", Id: "DDD" }, { Status: "Met", Text: "Text6", Id: "EEE", ContentItems: [{ Selected: true, Text: "Text7", Id: "FFF" }, { Selected: true, Text: "Text8", Id: "GGG" }, { Status: "Met", Text: "Text9", Id: "III", ContentItems: [{ Status: "Met", Text: "Text11", Id: "JJJ", ContentItems: [{ Text: "Text12", Id: 77 }, { Status: "Met", Text: "Text13", Id: 10, ContentItems: [{ Text: "Text14", Id: 45 }, { Selected: true, Text: "Text15", Id: 87 }, { Selected: true, Text: "Text16", Id: 80 }] }] }, { Status: "Met", Text: "Text17", Id: "KKK", ContentItems: [{ Text: "Text18", Id: 12 }, { Status: "NotMet", Text: "Text19", Id: 14, ContentItems: [{ Text: "Text20", Id: 55 }, { Selected: true, Text: "Text21", Id: 98 }] }] }] }] }] }] },
    result = [data].every(function iter(a) {
        return a.Status !== 'NotMet' && (!Array.isArray(a.ContentItems) || a.ContentItems.every(iter));
    });

console.log(result);

答案 2 :(得分:1)

var isStatusMet = function isStatusMet( data ) {
    // If the status is NotMet, we finish immediately
    if (data.Status === 'NotMet') return false;
    // Since only nodes with ContentItems have a status, we check if the node has children and recursively check if every child has no Status of NotMet
    else if (data.hasOwnProperty('ContentItems')) return data.ContentItems.every(isStatusMet);
    // We're dealing with a child without Status or Childnodes, so we just return true.
    // Since the status in not met and the parent node of this node expects in its 'every' loop that we only return false for nodes that have Status NotMet, this makes the recusion work.
    else return true;
};

var met = isStatusMet(response);

console.log(met);