如何从JavaScript数据结构生成HTML列表结构?

如何从JavaScript数据结构生成HTML列表结构?,javascript,list,object,recursion,traversal,Javascript,List,Object,Recursion,Traversal,我需要遍历这个数据结构来呈现一组列表。对于嵌套数据与父数据具有相同结构的结构,这不会有问题,但这里所有的模型都不同。将有一个列表,其中每个项目包含此结构中每个级别的列表。像这样: 预期结果: 未选择 | Countries | Provinces | Cities | <--- Top ul --------------------------------------- |-China | | | <--- Sub uls

我需要遍历这个数据结构来呈现一组列表。对于嵌套数据与父数据具有相同结构的结构,这不会有问题,但这里所有的模型都不同。将有一个列表,其中每个项目包含此结构中每个级别的列表。像这样:

预期结果:

未选择

| Countries | Provinces | Cities      | <--- Top ul
---------------------------------------
|-China     |           |             | <--- Sub uls
|-Denmark   |           |             |
Xs表示一个选定的选项。如果选择了某个项目,则后续列表中只应显示该项目的信息。如上所述,由于选择了中国,以下列表中未显示来自丹麦的数据

数据结构:


我已经修补了两种不同的递归方法,但阻止我的始终是,我无法预测下一个级别可能被称为城市、城镇或matjii


我是否遗漏了一些简单明了的解决方案?伪代码很好,我正在寻找一种通用方法。

基本上,我认为关键在于规范化数据,无论是从后端还是前端

在这个回答中,我假设你别无选择,只能从前端开始

每个国家的地理位置都有不同的命名惯例,例如,一些国家将其命名为城市、县、镇、村等

尽管在命名上存在差异,但它们都遵循类似于树的层次结构。因此,这是你的攻击角度。根据层次结构级别对其进行规范化

下面的示例代码将在层次结构级别打印出您的示例数据。它们的水平与压痕的数量形成对比。复制并粘贴以下代码并在浏览器控制台中运行

数据:

var data = {
  countries: {
    china: {
      name: "China",
      provinces: {
        matjii: {
          name: "Matjii",
          cities: {
            goneng: {
              name: "Go Neng"
            },
            tsauPei: {
              name: "Tsau Pei"
            }
          }
        },
        pausiu: {
          name: "Pausiu",
        }
      }
    },
    denmark: {
      name: "Denmark",
      counties: {
        borjskada: {
          name: "Borjskada",
          towns: {
            fjollmaska: {
              name: "Fjollmaska"
            }
          }
        },
        larvmauda: {
          name: "Larvmauda",
          towns: {
            tarnaby: {
              name: "Taernaby"
            }
          }
        }
      }
    }
  }
}
职能:

function traverseDataStructure(rootNode, nodeLevel){

    if(!rootNode) return;

    if(nodeLevel > 3) return;  //just a secondary protection for infinite recursion

    if(!nodeLevel)
        nodeLevel = 0;

    var indentationForPrinting = '';
    for(var i=0;i<nodeLevel;i++){
        indentationForPrinting += '    ';
    }

    console.log(indentationForPrinting + 'Traversing level ' + nodeLevel);

    for(var prop in rootNode){

        //prop may either by countries (level 0) or provinces (level 1) or counties (level 1) or cities (level 2) or towns (level 2)
        var regionType = prop;
        var regionList = getRegionList(rootNode[prop]);
        console.log(indentationForPrinting + 'regionType: ' + regionType);
        console.log(indentationForPrinting + 'regionList: ' + regionList);

        if(regionList.length <= 0) return;

        //then iterate the list of regions
        for(var i=0;i<regionList.length; i++){

            for(var subRegion in regionList[i]){
                if (subRegion == 'name'){
                    var regionName = regionList[i][subRegion];
                    console.log(indentationForPrinting + 'regionName: ' + regionName);
                } else {
                    traverseDataStructure({subRegion: regionList[i][subRegion]}, nodeLevel+1);
                }
            }
        }
    }
}

function getRegionList(obj){
    var list = [];
    for(var location in obj){
        list.push(obj[location]);
    }
    return list;
}
预期产出:


希望这可以为您提供一个解决问题的替代方案

我无法预测下一个级别可能会被称为什么-听起来像是Object.Keys的情况您应该只输出其中的任何内容,而不考虑键名。这意味着您无法在顶层显示整个树,因为您根本不知道用户将选择哪条路径。@Jonathan我需要这些键来生成顶层列表的路径,但不是所有键。只是其中的一些国家、省、市和其他地方不会用于顶级,而是子列表matjii、pausiu中的内容。这就是为什么我不能假设密钥意味着什么。我建议要么修复您的数据结构,要么修复您的需求。。。在丹麦,只有县,没有省,从程序上来说,你不想触及这一点。补充乔纳森的建议。如果您无法确定后端代码返回的数据结构,那么您可以尝试将数据结构规范化为更递归的结构,然后再对其进行处理,这看起来是一种合理的方法!为了呈现菜单结构,我需要一些方法来确定应该使用哪些数据来创建顶级元素国家、省/县、市/镇。对我来说,似乎很难通过编程从这个结构中提取这些信息。你怎么说?无论是在数据库级别还是用户界面级别,你都应该使用相同的术语,例如:国家>省份>城市。县将被视为省,镇将被视为城市。我给你的代码片段迭代了当前数据结构的所有级别。你可以稍微修改它,以参考上面的数据变量重建数据结构/视图模型的净化版本。另一种欺骗方法是使用JSON.stringifydata和JSON.parsestringifiedJSON;当您从数据结构中获得json字符串时,您可以用字符串替换省的县的所有实例,同样地,用城市替换城镇的所有实例。然后将这个字符串解析回您的数据结构。这样,您就不需要处理任何命名差异。我明白您的意思,但我无法使标签正常化。城市必须有一个标签“cities”和城镇“towns”等等。这是我的问题的本质。然后,你可以像我在代码示例中所做的那样,创建一个递归数据结构,包含两个字段,RegionType country、city、county,不管它是什么,RegionList是子区域的数据结构。鉴于你的严格要求,不会有一条直截了当的出路。我想你只需要咬紧牙关,把事情做好,哈哈
var data = {
  countries: {
    china: {
      name: "China",
      provinces: {
        matjii: {
          name: "Matjii",
          cities: {
            goneng: {
              name: "Go Neng"
            },
            tsauPei: {
              name: "Tsau Pei"
            }
          }
        },
        pausiu: {
          name: "Pausiu",
        }
      }
    },
    denmark: {
      name: "Denmark",
      counties: {
        borjskada: {
          name: "Borjskada",
          towns: {
            fjollmaska: {
              name: "Fjollmaska"
            }
          }
        },
        larvmauda: {
          name: "Larvmauda",
          towns: {
            tarnaby: {
              name: "Taernaby"
            }
          }
        }
      }
    }
  }
}
function traverseDataStructure(rootNode, nodeLevel){

    if(!rootNode) return;

    if(nodeLevel > 3) return;  //just a secondary protection for infinite recursion

    if(!nodeLevel)
        nodeLevel = 0;

    var indentationForPrinting = '';
    for(var i=0;i<nodeLevel;i++){
        indentationForPrinting += '    ';
    }

    console.log(indentationForPrinting + 'Traversing level ' + nodeLevel);

    for(var prop in rootNode){

        //prop may either by countries (level 0) or provinces (level 1) or counties (level 1) or cities (level 2) or towns (level 2)
        var regionType = prop;
        var regionList = getRegionList(rootNode[prop]);
        console.log(indentationForPrinting + 'regionType: ' + regionType);
        console.log(indentationForPrinting + 'regionList: ' + regionList);

        if(regionList.length <= 0) return;

        //then iterate the list of regions
        for(var i=0;i<regionList.length; i++){

            for(var subRegion in regionList[i]){
                if (subRegion == 'name'){
                    var regionName = regionList[i][subRegion];
                    console.log(indentationForPrinting + 'regionName: ' + regionName);
                } else {
                    traverseDataStructure({subRegion: regionList[i][subRegion]}, nodeLevel+1);
                }
            }
        }
    }
}

function getRegionList(obj){
    var list = [];
    for(var location in obj){
        list.push(obj[location]);
    }
    return list;
}
traverseDataStructure(data);