简体   繁体   English

解析JavaScript中的JSON对象(键/值对)

[英]Parsing a JSON object in javascript (key/value pairs)

I'm trying to get my head around NodeJS by writing a few test apps. 我试图通过编写一些测试应用程序来了解NodeJS。 I've managed okay so far but the one thing that's tripping me up is the following. 到目前为止,我的工作还不错,但以下是令我绊倒的一件事。

I've got it reading a directory for folders, and then parsing the settings.json files within each folder (so I can build a UI on the fly based on the folder contents). 我已经读取了文件夹的目录,然后解析每个文件夹中的settings.json文件(这样我就可以基于文件夹内容动态地构建UI)。 The problem is, I can't seem to "step down a level" with the JSON object. 问题是,我似乎无法使用JSON对象“降级”。

For example, coming from a background in php where you could do something like the following to 'step' through the array: 例如,来自php的背景,您可以执行以下操作来“逐步”遍历数组:

<?php
    $arr = [
        'folder1' => 
            [ 'name' => 'test',
              'icon' => 'icon-test'
            ],
        'folder2' => 
            [ 'name' => 'test-2',
              'icon' => 'icon-test-2'
            ]
    ];

    foreach($arr as $k => $v){
        // folder1 level
        foreach($v as $k2 => $v2){
                // name / icon level.
                echo $k2 . ' is ' . $v2;
        }
    }
?>

Is there an equivalent in JS? JS中有等效的东西吗? I can do the first "level" by doing this: 我可以通过执行以下操作来执行第一个“级别”:

function getDirectories (srcpath) {
  return fs.readdirSync(srcpath)
    .filter(file => fs.lstatSync(path.join(srcpath, file)).isDirectory())
}
var d = getDirectories('modules');
var modules = {};

// the following reads the json in each dir into an object like:
// { 'dirname': { 'key1': 'val1', 'key2': 'val2' }, 'dirname2'... }
for(var p in d){
    modules[d[p]] = JSON.parse(fs.readFileSync('./modules/'+d[p]+'/config.json', 'utf8'));
}

for(var k in modules){
    console.log(k);
}

But ideally I need to extract "name" and "icon" from the JSON. 但理想情况下,我需要从JSON中提取“名称”和“图标”。 I can't seem to find any way of doing this. 我似乎找不到任何办法。

I understand this is probably messy but I'm just getting my head around NodeJS. 我知道这可能很麻烦,但是我只是想着NodeJS。 For full clarity, directory structure and my simple JSON files below: 为了清楚起见,下面是目录结构和我的简单JSON文件:

modules directory structure 模块目录结构

modules
|____ test
      |____ config.json
|____ test-2
      |____ config.json

config.json (example) config.json(示例)

{
  "name": "test",
  "icon": "test-icon"
}
for(var module of modules){
   console.log(module.name,module.icon);
   //or over all
   for(var value of module) console.log(value);
}

The for...of loops over values. for ... of循环遍历值。 With for..in (looping over keys) : 与for..in(循环键):

for(var name in modules){
  var module=modules[name];
  for(key in module){
    console.log(name+"/"+key+":"+module[key]);
  }
}

You're currently using a for in loop, and while that works, when iterating over arrays you ideally want to use for next loops. 您当前正在使用for in循环,并且在可行的同时,当遍历数组时,理想情况下希望for next循环。

Here is an example: 这是一个例子:

for (var i = 0; i < folders.length; i++) {
    var folder = folders[i]

    /* work with directory .. */

    for (var j = 0; j < folder.items.length; j++){
        var item = folder.items[j]

        /* work with item.. */
    }
}

The reason for not using for in when iterating over array is because an array can contain objects that aren't actually part of the array, ie a function. 遍历数组时不使用for in的原因是因为数组可以包含实际上不是数组一部分的对象,即函数。

Using a for in loop, you will iterate over the array contains, and then any object/function attached to that array. 使用for in循环,您将遍历包含的数组,然后遍历该数组的任何对象/函数。

for next loops will only iterate over the array contents. for next循环,将仅遍历数组内容。

I don't know do you have only 1 subdirectory or can that be multiple? 我不知道您只有1个子目录,还是可以多个? If it can be any depth use a recursive function like: 如果可以是任何深度,请使用递归函数,例如:

function iterateFolder(array) {
  for (var i = 0; i < array.length; i++) {
    if ($.isArray(array[i]))
      iterateFolder(array[i]);
    else
      //Add to global variable for example or parse just the values
  }
}

try doing a for of loop and not a for in loop 尝试做一个for循环而不是for循环

            // example from a old proj
            // your code has in 
            // if you are using es6 syntax, you should use let instead of var
            for (let element of section.elements) {
                let $element;
                $element = $parent.find(`label[for=${element._data_text}]`);                    
                $element.html(`<span>${element[lang]}</span>`);
            }

here is a working example with my json 这是我的json的工作示例

import lang_data from "../data/languages.json";
$(function () {
    console.log("onload hit");
    $("[data-language]").on("click", function () {
        let $this = $(this);
        let data = $this.data();
        let lang = data.language;
        $("[data-language]").removeClass("active");
        $this.addClass("active");
        switchLanguage(lang);
        return true;
    });
})

function switchLanguage(lang) {
    for (let section of lang_data.sections) {
        // the form is loaded by JS. I could not add a data-text to it.
        if (section.id === "form1_handle_after") {
            let $parent = $("#form1");
            for (let element of section.elements) {
                let $element;
                if (element._data_text == "c-submit-button") {                    
                    $element = $parent.find(`#${element._data_text}`);                    
                } else {
                    $element = $parent.find(`label[for=${element._data_text}]`);                    
                }
                $element.html(`<span>${element[lang]}</span>`);
            }
        } else {
            let $parent = $(`#${section.id}`);
            for (let element of section.elements) {
                let $element = $parent.find(`[data-text=${element._data_text}]`);
                // text needs to be highlighted
                if(element.mark !== null){                    
                    let string = element[lang];                    
                    let find = element.mark[lang];
                    let new_string = string.replace(find, `<mark>${find}</mark>`)
                    // I assume it is wrapped in quotes
                    $element.html(`<span>&ldquo;${new_string}&rdquo;</span>`);
                }else{
                    $element.html(`<span>${element[lang]}</span>`);
                }

            }
        }

    }
}

Here is a sample of my data 这是我的数据样本

{
"sections": [
    {
        "id": "navbar_main",
        "elements": [
            {
                "_data_text": "question",
                "eng": "Have a Question?",
                "chi": "有个问题?",
                "mark": null
            }
        ]
    }
  ]
}

You can view the html and markup at http://professional.ongeo.msu.edu/ 您可以在http://professional.ongeo.msu.edu/查看html和标记。

I know you are starting with node, but i guess you should use "reduce" instead of those "for loops" for this case (it's just my personal opinion xd). 我知道您是从节点开始的,但在这种情况下,您应该使用“减少”而不是那些“循环”(这只是我个人的观点xd)。 You can find many guides of how to use this function, you variable "d" is an array and all arrays has the "reduce" function. 您可以找到许多有关如何使用此功能的指南,变量“ d”是一个数组,所有数组都具有“ reduce”功能。

Something like this: 像这样:

const modules = d.reduce((all, current) => {
  all[current] = current || {}
  all[current] = JSON.parse(fs.readFileSync(__dirname + '/modules/'+ current +'/config.json', 'utf8'))
  return all;
}, {})

I test it creating some folders and gave me this: 我测试它创建了一些文件夹,并给了我这个:

​​​​​{ test: { name: 'test', icon: 'test-icon' },​​​​​ ​​​tes_2: { name: 'test-2', icon: 'test-icon-2' } }​​​​​

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM