首页 > 解决方案 > 如何创建反映嵌套 HTML 表单的嵌套 JSON 对象?

问题描述

我有一个与此类似的 HTML 表单(请注意,它是由选项卡、可选字段集和字段元素组织的):

每个div都是一个或多个input元素的容器,但对于这个问题,我将重点放在容器上。

我正在尝试编写一个 JavaScript 函数,该函数将“遍历”指定的 HTML 元素并以这种格式生成 JSON 对象(注意基于表单的选项卡、字段集和输入元素形成的嵌套):

   {
        "content": 
        [        
            {
                "type": "tab",
                "id": "left-defaults1",
                "order": 1,
                "content": 
                [
                    {
                        "id": "fieldset-3",
                        "order": 1,
                        "type": "fieldset",
                        "content": [
                            {
                                "id": "container308",
                                "order": 1,
                                "type": "field"
                            },
                            {
                                "id": "container314",
                                "order": 1,
                                "type": "field"
                            },        
                            {
                                "id": "fieldset-4",
                                "order": 1,
                                "type": "fieldset",
                                "content": [
                                    {
                                        "id": "container309",
                                        "order": 1,
                                        "type": "field"
                                    },
                                    {
                                        "id": "container310",
                                        "order": 1,
                                        "type": "field"
                                    }
                                ]
                            }
                        ]
                    },
                ]
            },        
            {
                "type": "tab",
                "id": "left-defaults2",
                "order": 2,
                "content": 
                [
                    {
                        "id": "fieldset-1",
                        "order": 1,
                        "type": "fieldset",
                        "content": [
                            {
                                "id": "container311",
                                "order": 1,
                                "type": "field"
                            },
                            {
                                "id": "fieldset-2",
                                "order": 1,
                                "type": "fieldset",
                                "content": [            
                                    {
                                        "id": "container313",
                                        "order": 1,
                                        "type": "field"
                                    },
                                    {
                                        "id": "container312",
                                        "order": 1,
                                        "type": "field"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            },        
            {
                "type": "tab",
                "id": "left-defaults3",
                "order": 3,
                "content": 
                [
                    {
                        "id": "container315",
                        "order": 1,
                        "type": "field"
                    },
                    {
                        "id": "container316",
                        "order": 1,
                        "type": "field"
                    }
                ]
            }
        ]
    }

我在通过第二个“层”时遇到了问题。我可以识别要“行走”的 HTML 元素,并且可以在 JSON 对象中建立“标签”级别。我还可以将下一层字段集或字段元素推入其中。但除此之外,我迷失了方向;我不知道如何在 JSON 对象中定位给定第三层的父级(或第四层或第五层等)。

这个 JavaScript 是该尝试的核心:

var createNestedJSON = function(){
    //establish JSON object
    var tab_order = 0,
        form_content_nested_and_ordered = {'content': []},
        element_ii_object = {};

    //so we can retrieve them in the order they exist in the page, class as "JSONMe" all the things we are going to want to represent in form_content_nested_and_ordered
    $('#fmWkflw').find('.tab-option-container').addClass('JSONMe').find('li').addClass('JSONMe');

    $('.JSONMe').each(function(element_index){
        var $this = $(this).data('JSON_id', element_index);
        console.log('tag:'+ this.tagName +', id:'+ this.id +', parentId: '+ $this.parent().prop('id') +', className: '+ this.className);

        if( this.tagName === 'UL' ){
            //this is a tab; add it
            form_content_nested_and_ordered["content"].push( {'type': 'tab', 'id': this.id, 'order': ++tab_order, 'content' : []} );
            console.log('added tab');
        }
        else {
            element_ii_object = {
                    'id': this.id,
                    'order': 1,
                    'type': 'field'
                };

            if( $this.hasClass('fieldset') ) {
                //this is a fieldset, so it has type "fieldset" and a "content" array
                element_ii_object.type = 'fieldset';
                element_ii_object.content = [];
            }

            console.log(element_ii_object);

            form_content_nested_and_ordered.content[ tab_order-1 ]['content'].push( element_ii_object );

            console.log('added '+ element_ii_object.type);
        };
    });

    /*
    form_content_nested_and_ordered["content"][getIndexIfObjWithOwnAttr(form_content_nested_and_ordered["content"], 'id', 2)]['content'].push( {'type': 'field', 'id': 14, 'order': 12} );
    form_content_nested_and_ordered["content"][getIndexIfObjWithOwnAttr(form_content_nested_and_ordered["content"], 'id', 1)]['content'].push( {'type': 'field', 'id': 23, 'order': 7} );
    form_content_nested_and_ordered["content"][getIndexIfObjWithOwnAttr(form_content_nested_and_ordered["content"], 'id', 1)]['content'].push( {'type': 'field', 'id': 24, 'order': 8} );
    */

    //tear down
    $('#fmWkflw').find('.JSONMe').data('JSON_id', 0).removeClass('.JSONMe');

    return form_content_nested_and_ordered;
};

我试着换档来使用serializeArray()reduce()但这就像一个铅气球一样起飞

标签: javascriptjqueryjson

解决方案


您好据我了解,您必须在那里进行递归,因为您不知道它的级别,所以这里有一个示例,希望对您有所帮助。

递归映射树

function copyTree(originalTree){
    return originalTree.map((elem, index) => ({
      id: 'div.'+elem.id,
      content: !elem.content ? [] : this.copyTree(elem.content),
    }));
  }

编辑: 我误解了你想要的东西,这是你期望得到的东西,我希望这可以帮助你。
对代码的一些解释:我使用 querySelectorAll 是因为它返回一个可以迭代的 NodeList,[...arr] 的原因是

如果对象是可迭代的,它将从对象中创建一个数组。有关更多示例,请转到过滤器或映射 NodeList

之后我要做的是创建一个递归调用的函数,以便推送内容直到找不到更多匹配项。

var getIndexIfObjWithOwnAttr = function(array, attr, value) {
    for(var i = 0; i < array.length; i++) {
        if(array[i].hasOwnProperty(attr) && array[i][attr] === value) {
            return i;
        }
    }
    return -1;
};

var createNestedJSON = function(){
	//establish JSON object
	var tab_order = 0,
		form_content_nested_and_ordered = {'content': []},
		element_ii_object = {};
	
	//so we can retrieve them in the order they exist in the page, class as "JSONMe" all the things we are going to want to represent in form_content_nested_and_ordered
	$('#fmWkflw').find('.tab-option-container').addClass('JSONMe').find('li').addClass('JSONMe')
	var htmltest = document.querySelectorAll('.JSONMe')

	form_content_nested_and_ordered = function (arr){
		return [...arr].map((elem, index) => ({
			type: elem.localName,
			id: elem.id,
			content: elem.children && elem.children.length>0 && (elem.localName ==='li' || elem.localName ==='ul' || elem.localName ==='fieldset') ? form_content_nested_and_ordered(elem.children) : [],
		  }));
	}
	//console.log(form_content_nested_and_ordered(htmltest))
	var filtered = form_content_nested_and_ordered(htmltest).filter((x)=>{
		return x.type == 'ul'
	})
	
	return filtered;
};

$('#formSubmit').click(function(){
	$('#resulting_JSON')[0].innerHTML = JSON.stringify(createNestedJSON());
});


推荐阅读