NaturalIntelligence / fast-xml-parser

Validate XML, Parse XML and Build XML rapidly without C/C++ based libraries and no callback.
https://naturalintelligence.github.io/fast-xml-parser/
MIT License
2.6k stars 309 forks source link

getTraversalObj does not create a traversal object anymore #65

Closed janrygh closed 6 years ago

janrygh commented 6 years ago

Checklist

Please fill below checklist

Input data

Please include your sample code here

const XML_PARSER_OPTIONS = { attributeNamePrefix : "", attrNodeName: "attr", //default is 'false' textNodeName : "", ignoreAttributes : false, ignoreNameSpace : false, allowBooleanAttributes : false, parseNodeValue : true, parseAttributeValue : true, trimValues: true, decodeHTMLchar: false, cdataTagName: "__cdata", //default is 'false' cdataPositionChar: "\c", }; const myXml = ''; const tObj = xmlParser.getTraversalObj(myXml, XML_PARSER_OPTIONS); tObj.child.toptag[0].child.forEach((nodeObj) => { console.log(nodeObj.tagname); });

Code

const XML_PARSER_OPTIONS = {
    attributeNamePrefix : "",
    attrNodeName: "attr", //default is 'false'
    textNodeName : "",
    ignoreAttributes : false,
    ignoreNameSpace : false,
    allowBooleanAttributes : false,
    parseNodeValue : true,
    parseAttributeValue : true,
    trimValues: true,
    decodeHTMLchar: false,
    cdataTagName: "__cdata", //default is 'false'
    cdataPositionChar: "\\c",
};
const myXml = '<toptag><mychild id="1" /><mydog id="2" /><mycat id="3" /><mydog id="4" /></toptag>';
const tObj = xmlParser.getTraversalObj(myXml, XML_PARSER_OPTIONS);
tObj.child.toptag[0].child.forEach((nodeObj) => {
      console.log(nodeObj.tagname);
 });

Output data

Please include output data here tObj.child.toptag[0].child.forEach is not a function

expected data

Please include expected output data here mychild mydog mycat mydog

amitguptagwl commented 6 years ago

I've done a small change in last release. I'm extremely if it has broken your already running code. Now the node look like this;

function(tagname, parent, val) {
    this.tagname = tagname;
    this.parent = parent;
    this.child = {};//child tags
    this.attrsMap = {};//attributes map
    this.val = val;//text only
    this.addChild = function(child) {
        if (this.child[child.tagname]) {//already presents
            this.child[child.tagname].push(child);
        } else {
            this.child[child.tagname] = [child];
        }
    };
};

Previously, child property of a node was pointing to single value or it was an array. Now child property of a node is always an object where the keys of child are nested tag names, pointing to an array of nodes.

janrygh commented 6 years ago

OK, I just started using your library three weeks ago and found it perfect for my pruposes, since I need to parse large XMLs. But part of the parsing is iterating over the children tags in a ordered way. Seems like that possibility dissapeared with the rewrite to children as object instead of array. Any chance to get children tags as iterable array?

amitguptagwl commented 6 years ago

If I'm understanding your problem correctly, you can use Object.keys(nodechild) to iterate child tags. But you'll not get it directly from the traversal object.

Though I could have kept it as an array instead of object but it helps me when I do further parsing to json or nimn (निम्न).

So someone need to suffer..either me..or you :wink:

janrygh commented 6 years ago

Thanks, you guess you are right, I can probably use Object.keys(tObj.child)

Of course it is me that should suffer, I am just surfing on your work.

One more question:

Code

var xmlParser = require('fast-xml-parser');
const XML_PARSER_OPTIONS = {
    attributeNamePrefix : "",
    attrNodeName: "attr", //default is 'false'
    textNodeName : "",
    ignoreAttributes : false,
    ignoreNameSpace : false,
    allowBooleanAttributes : false,
    parseNodeValue : false,
    parseAttributeValue : false,
    trimValues: true,
    decodeHTMLchar: true,
    cdataTagName: "__cdata", //default is 'false'
    cdataPositionChar: "\\c",
};
const myXml = '<tag><x>1</x><y>4</y><x>2</x></tag>';
const j = xmlParser.parse(myXml, XML_PARSER_OPTIONS);
const Parser = new xmlParser.j2xParser( XML_PARSER_OPTIONS );
const xml = Parser.parse(j)

I get "<tag y=\"4\"><x>1</x><x>2</x></tag>" out

The element y is turned into an attribute.

amitguptagwl commented 6 years ago

what I can see here is that invalid XML is being parsed. You should have used validator in such case. You can get more detail about that on README.

janrygh commented 6 years ago

Hmm, I do not see what you mean. xmlParser.validate(myXml) gives true.
The return value is:

Code

<tag y="4"><x>1</x><x>2</x></tag>

maybe it was the string representation you ment.

The point is that the element y is turned into an attribute.

This happens when attributeNamePrefix : "", not when it is set to ie attributeNamePrefix : "@_"

amitguptagwl commented 6 years ago

The previous comment is edited. Now I can read it correctly.

When you transform JSON to XML back, you'll have to set appropriate options properly. E.g. in this case, you should set either ignoreAttributes:true or attributeNamePrefix to some unique prefix.

The reason I've provided multiple options while parsing is to get almost same XML. So I don't see any issue here.

janrygh commented 6 years ago

Ok, thanks.

I'll play around with it and see what suits us best.