我有基于XML文件生成的表单输入。
我们通过data-*
属性在XML文件中保留嵌套元素的引用,这些属性稍后可用于构建对象。例如:
<parent>
<child>
<grandchild1>first</grandchild1>
<grandchild2>second</grandchild2>
</child>
</parent>
变为
<input type="text" data-nest="parent.child.grandchild1" value="first"/>
<input type="text" data-nest="parent.child.grandchild2" value="second"/>
当我们提交表单时,我会根据data-nest
属性创建一个对象(带有嵌套对象)。以上将成为
parent:{
child:{
grandchild1: first,
grandchild2: second
}
}
我遇到的问题是在XML文件中找到多个相同的标记,例如
<child>
<grandchild>first</grandchild>
<grandchildFriend>firstFriend</grandchildFriend>
</child>
<child>
<grandchild>second</grandchild>
<grandchildFriend>secondFriend</grandchildFriend>
</child>
当我创建我的对象时,我希望如果找到多次出现相同的data-nest
值,它们会嵌套在数组中以保持不同的值。
使用当前设置,第二次出现的标签可以理解地覆盖第一个。
这是我想要的最终对象结构:
parent:{
child:[
{
grandchild: first,
grandchildFriend: firstFriend
},
{
grandchild: second,
grandchildFriend: secondFriend
}
]
}
TL; DR
如果对象具有相同的data-*
属性,我想将对象更改为嵌套对象数组
以下是fiddle当前代码的工作原理,以帮助您更好地理解。
答案 0 :(得分:0)
将currentObj[lastKey] = value;
替换为:
if(typeof currentObj[lastKey] === 'undefined') {
currentObj[lastKey] = value;
} else {
if(typeof currentObj[lastKey] !== 'array')
currentObj[lastKey] = [currentObj[lastKey]];
currentObj[lastKey].push(value);
}
代码将执行以下操作:如果未设置currentObj [lastKey],您将一如既往地创建一个元素,否则,如果它已经设置并且是一个字符串,代码将把它转换为一个数组然后推入数组后续(尽可能多)元素 最终的结果将类似于:
parent:{
...
grandchild:[
"first", "second"
]
...
}
修改强> 为了得到您所请求格式的结果,您需要进行更多编辑,如下所示:
var json = {};
config = {
set: function(keyValueString) {
var pair = keyValueString.split('=');
// left of the = is the key path
var keyPath = pair[0];
// right of the = is the value to set
var value = pair[1];
// split keyPath into an array of keys
var keys = keyPath.split('.');
var key;
var currentObj = json;
// loop through all keys in the key path, except the last one.
// this creates the object structure implied by the key path.
// we want to do something different on the last iteration.
for (var i=0; i < keys.length-1; i++) {
// Get the current key we are looping
key = keys[i];
// if the requested level on the current object doesn't exist,
// make a blank object.
if (typeof currentObj[key] === 'undefined') {
currentObj[key] = i === keys.length-2 ? []: {};
}
currentObj = currentObj[key];
}
// our loop doesn't handle the last key, because that's when we
// want to set the actual value.
var lastKey = keys[keys.length-1]
// set the property of the deepest object to the value.
var child = {};
child[lastKey] = value;
currentObj.push(child);
}
};
// iterate through all of our inputs, and nest them based off their data-* attribute
$('input').each(function(){
// set nest = value setup, e.g. parent.child.grandchild = first
// we then break this
var key = $(this).attr('data-nest') + '=' + $(this).val();
config.set(key);
});
// as a bonus - this is how I went about breaking multiple values within a single input into an array
function traverseObject(object){
// iterate through the object
for (var i in object){
// if the next key exists, run again
if(object[i] !== null && typeof(object[i])=="object"){
traverseObject(object[i]);
} else {
var value = [object[i]];
// if the value contains a comma
if(value.toString().indexOf(',') > -1){
// set the *nested* key to the
// value as an array by splitting at the commas
object[i] =value.toString().split(',').filter(function(el){
// remove the extra entry after splitting
return el.length != 0;
});
}
}
}
}
traverseObject(json);
$('#test').on('click', function(){
console.log(json)
});
答案 1 :(得分:0)
试试这个https://jsfiddle.net/ado7eLL9/19/
通过像这样更新配置的方法
if (typeof currentObj[lastKey] === 'undefined') {
currentObj[lastKey] = value;
} else if(!Array.isArray(currentObj[lastKey])) {
currentObj[lastKey] = [currentObj[lastKey], value];
} else if(Array.isArray(currentObj[key])){
currentObj[lastKey].push(value);
}
答案 2 :(得分:0)
按如下方式更新您的config.set()
:
var json = {};
config = {
set: function(keyValueString) {
var pair = keyValueString.split('=');
// left of the = is the key path
var keyPath = pair[0];
// right of the = is the value to set
var value = pair[1];
// split keyPath into an array of keys
var keys = keyPath.split('.');
var key;
var currentObj = json;
// loop through all keys in the key path, except the last one.
// this creates the object structure implied by the key path.
// we want to do something different on the last iteration.
for (var i=0; i < keys.length-1; i++) {
// Get the current key we are looping
key = keys[i];
// if the requested level on the current object doesn't exist,
// make a blank object.
if (typeof currentObj[key] === 'undefined') {
currentObj[key] = {};
}
currentObj = currentObj[key];
}
// our loop doesn't handle the last key, because that's when we
// want to set the actual value.
var lastKey = keys[keys.length-1]
if (typeof currentObj[lastKey] === 'undefined') {
// set string if nothing exists
currentObj[lastKey] = value;
} else if(!Array.isArray(currentObj[lastKey])) {
// if exists and is not an array,
// create an array with two items
// previously stored value (string) with lastKey key
// current value
var previous = { [lastKey]: currentObj[lastKey] };
var current = { [lastKey]: value };
currentObj[lastKey] = [previous, current];
} else if(Array.isArray(currentObj[key])){
// if exists and is an array
// push the new object to it
var current = { [lastKey]: value }
currentObj[lastKey].push(current);
}
}
};
// iterate through all of our inputs, and nest them based off their data-* attribute
$('input').each(function(){
// set nest = value setup, e.g. parent.child.grandchild = first
// we then break this
var key = $(this).attr('data-nest') + '=' + $(this).val();
config.set(key);
});
// as a bonus - this is how I went about breaking multiple values within a single input into an array
function traverseObject(object){
// iterate through the object
for (var i in object){
var value = [object[i]];
// EDIT: continue only if value is not an array
if(!Array.isArray(object[i])) {
// if the value contains a comma
if(value.toString().indexOf(',') > -1){
// set the *nested* key to the
// value as an array by splitting at the commas
object[i] = value.toString().split(',').filter(function(el){
// remove the extra entry after splitting
return el.length != 0;
});
}
// if the next key exists, run again
if(object[i] !== null && typeof(object[i])=="object"){
traverseObject(object[i]);
}
}
}
}
traverseObject(json);
$('#test').on('click', function(){
console.log(json)
});
&#13;
#test{
padding: 5px;
border: 1px solid black;
font-size: 15px;
cursor: pointer;
width: 150px;
margin: 5px;
text-align: center;
}
input{
display: block;
margin: 5px;
padding: 5px;
width: 150px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Below are unique tags (working fine)</label>
<input type="text" data-nest="parent.child.grandchild1" value="gchild1-first"/>
<input type="text" data-nest="parent.child.grandchild2" value="gchild2-second"/>
<label>Below is multiple occurances of the same tag (find a way to break these into an array of objects)</label>
<input type="text" data-nest="parent.child.grandchild" value="gchild-first"/>
<input type="text" data-nest="parent.child.grandchild" value="gchild-second"/>
<label>Single array example</label>
<input type="text" data-nest="parent.child.array" value="this,is,an,array"/>
<div id="test">
Test
</div>
&#13;
答案 3 :(得分:0)
通过使用不同的方法进行攻击已解决了这个问题。
我们将我们想要的元素设置为[]
添加到data-nest
属性末尾的数组 - 然后我们可以将其用作我们想要转换的基线。
如果有人好奇,请点击更新的fiddle