根据相同的属性名称

时间:2017-11-16 11:19:53

标签: javascript jquery json

我有基于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当前代码的工作原理,以帮助您更好地理解。

4 个答案:

答案 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()

&#13;
&#13;
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;
&#13;
&#13;

答案 3 :(得分:0)

通过使用不同的方法进行攻击已解决了这个问题。

我们将我们想要的元素设置为[]添加到data-nest属性末尾的数组 - 然后我们可以将其用作我们想要转换的基线。

如果有人好奇,请点击更新的fiddle