TobiasNickel/tXml

Attributes are not included in simple result for elements without children

dasDaniel opened this issue · 3 comments

Wasn't sure whether this was a feature or bug, but I'm thinking it might be the latter.

Here is the input

<response>
  <error msg="haha, nice try">
    <anything></anything>
  </error>
</response>

and this is the output

{
  "response": {
    "error": {
      "anything": "",
      "_attributes": {
        "msg": "haha, nice try"
      }
    },
    "_attributes": {}
  }
}

if I take out the anything tags, the msg attribute is not included anymore

<response>
  <error msg="haha, nice try">
  </error>
</response>

result:

{
  "response": {
    "error": "",
    "_attributes": {}
  }
}

but I'm expecting:

{
  "response": {
    "error": {
      "_attributes": {
        "msg": "haha, nice try"
      }
    },
    "_attributes": {}
  }
}

It looks like the presence of an additional child tag is required to treat the element as an object instead of as a string value

yes, I would also expect that. I will look into this later this weekend.

Actually it is a feature, But this is a situation where some decision need to be made, and there will always be situations that some developers would expect the opposite (not the fault of the developer).
For the implementation of txml.simplify I have made the same output as PHP simpleXML.

To get the result you expected, you can use the following method it return what is expected, but other developers would think "why is errors now an object and not a string".

function logicalSimplify(children) {
    var out = {};

    if (children.length === 1 && typeof children[0] == 'string') {
        return children[0];
    }
    // map each object
    children.forEach(function(child) {
        if (typeof child !== 'object') {
            return;
        }
        if (!out[child.tagName])
            out[child.tagName] = [];
        var kids = logicalSimplify(child.children);
        out[child.tagName].push(kids);
        if (Object.keys(child.attributes).length) {
            kids._attributes = child.attributes;
        }
    });

    for (var i in out) {
        if (out[i].length == 1) {
            out[i] = out[i][0];
        }
    }

    return out;
};

To resolve that issue, I made the txml.simplifyLostLess() implementation. It might not be as pretty, because every value is going to be an array, even if it has only one item. But when there are situations, where there can be one or more items of the same type, then it need to stay an array. As developer then there is the direct way, to know there is only one and access the value using ...[0] or as an array using ....map(...) or forEach.

That's the problem with xml=>json, it's hard to tell intent. The nice thing is that using the xml method, the user can reduce as needed to get desired result.