Javascript递归字符串追加

时间:2017-01-28 06:20:28

标签: javascript arrays json xml

我有简单和复杂的JSON数据,并使用JavaScript递归方法将其转换为XML,如下所示:

var json = [
  {
    "id": "42cfb980-4221-e97f-f85a-f5fcf4d37f02",
    "name": "outer",
    "value": "",
    "attributes": {},
    "subNodes": [
      {
        "id": "d0794639-5568-3728-11a4-676eb100b07a",
        "name": "inner",
        "value": "inner vlaue",
        "attributes": {},
        "subNodes": []
      }
    ]
  }
];

function prepareXmlOutput(appendTo, obj) {
        var i, k, attributeString = '';

        for (i in obj) {
            if (obj[i].attributes.length > 0) {
                for (k in obj[i].attributes) {
                    attributeString += ((obj[i].attributes[k].name != '') ? obj[i].attributes[k].name+'="'+obj[i].attributes[k].value+'"' : '') + ' ';
                }
            }
            if (obj[i].subNodes.length < 1) {
                if (obj[i].value == '') {
                    appendTo += '</' + obj[i].name + attributeString.replace(/~+$/,'') + '>';
                } else {
                    appendTo += '<' + obj[i].name + attributeString.replace(/~+$/,'') + '>' +obj[i].value+ '</' + obj[i].name + '>';
                }

            } else {
                appendTo += '<' + obj[i].name + attributeString.replace(/~+$/,'') + '>';

                appendTo += prepareXmlOutput(appendTo, obj[i].subNodes);

                appendTo += '</' + obj[i].name + '>';
            }
        }
        return appendTo;
    }

prepareXmlOutput('', json);

这使得xml非常精细但有一个问题。这是它给我的XML:

"<outer><outer><inner>inner vlaue</inner></outer>"

问题是,它重复了第一个节点。它为什么会这样?我尝试了很多用dev工具调试它,我发现光标在完成这个堆栈后直接转到return语句:

appendTo += prepareXmlOutput(appendTo, obj[i].subNodes);

2 个答案:

答案 0 :(得分:0)

替换此行:

appendTo += prepareXmlOutput(appendTo, obj[i].subNodes);

用这个:

appendTo += prepareXmlOutput('', obj[i].subNodes);

因为它必须独立于累积的appendTo创建子节点的XML字符串。然后使用+=将结果(返回值)附加到它。在您的代码中,结果会附加两次(在函数内部附加到appendTo,然后使用+=返回已经附加的结果再次附加)。对于 N 的深度,外部元素重复 N + 1 次,第二个外部元素重复 N 次,...和所以直到内部元素不再重复。

您遇到的错误示例:将appendTo '<outer>'作为参数传递给函数调用,appendTo在调用时附加到'<inner>'结束它返回'<outer><inner>'然后使用appendTo追加到'<outer>'的前一个值(+=),现在appendTo变为'<outer><outer><inner>' }(外部元素重复2次,因为它已经传递给调用一次(下面一级))如果下面有N级,那么appendTo将被传递给N次调用:

  • 通过N°1:appendTo = '<outer>'
  • 通过N°2:appendTo = '<outer><outer><inner>'
  • 通过N°3:appendTo = '<outer><outer><outer><inner><inner>'
  • ...

答案 1 :(得分:0)

只是为了一些变化;你不妨这样做;

var json = [
  {
    "id": "42cfb980-4221-e97f-f85a-f5fcf4d37f02",
    "name": "outer",
    "value": "",
    "attributes": {},
    "subNodes": [
      {
        "id": "d0794639-5568-3728-11a4-676eb100b07a",
        "name": "in01",
        "value": "inner value",
        "attributes": {color:"red"},
        "subNodes": [{
                       "id": "d0794639-5568-3728-11a4-676eb100b07a",
                       "name": "in02",
                       "value": "more inner value",
                       "attributes": {color:"blue"},
                       "subNodes": [{
                                      "id": "d0794639-5568-3728-11a4-676eb100b07a",
                                      "name": "in03",
                                      "value": "most innest value",
                                      "attributes": {color:"pink"},
                                      "subNodes": []
                                    }]
                     }]
      },
      {
        "id": "d0794639-5568-3728-11a4-676eb100b07b",
        "name": "in11",
        "value": "another inner value",
        "attributes": {color:"orange"},
        "subNodes": [{
                       "id": "d0794639-5568-3728-11a4-676eb100b07a",
                       "name": "in12",
                       "value": "more inner value",
                       "attributes": {color:"brown"},
                       "subNodes": []
                     }]
      }
     ]
  }
],

parseXML = (a, r = "") => a.length ? parseXML(a.slice(1), r + Object.keys(a[0].attributes)
                                                                    .reduce((s,k) => s + " " + k + "=\"" + a[0].attributes[k] + "\"", "<" + a[0].name)
                                                                    + ">"
                                                                    + a[0].value
                                                                    + parseXML(a[0].subNodes,"")
                                                                    + "</"
                                                                    + a[0].name
                                                                    + ">")
                                   : r;
console.log(parseXML(json));