Related
I'm adding some APIs to a JavaScript project to replace what used to be multi-field manual data entry with lookups. (E.g., we want to stop asking you 20 questions about a car, and instead just ask your VIN and autopopulate the other 19 answers from a VIN decoder.)
I'm spending more time than I'd like mapping data from the response schema into the existing internal schema of my app. Lots of the work requires a human touch to suss out synonyms, like:
internal.postal_code = api.zipCode;
Some times I find myself writing a really gnarly if to avoid a sometimes-null or missing object half way down a deep tree, like
if(api.a && api.a.b && api.a.b.c){
internal.z = api.a.b.c.d;
}
Is there a good library that would let me write a simple map and do all this work for me? A map might look like:
map = {
'zipCode' : 'postal_code',
'a.b.c.d' : 'z'
};
mapperTool( api, internal, map );
(Note the internal object is stitched together from several APIs and pre-existing tools, so adding or overwriting properties on internal is better than outputting a new object.)
Try this:
function mapperTool(source, desc, map) {
Object.keys(map).forEach(function(key) {
var value = key.split('.').reduce(function(obj, name) {
if (obj && obj[name]) {
return obj[name];
}
}, source);
desc[map[key]] = value;
});
}
var map = {
'zipCode' : 'postal_code',
'a.b.c.d' : 'z'
};
var internal = {};
mapperTool({a:{b:{c:{d: 10}}},zipCode:20}, internal, map);
document.body.innerHTML = '<pre>' + JSON.stringify(internal, true, 4) + '</pre>';
How would you convert from XML to JSON and then back to XML?
The following tools work quite well, but aren't completely consistent:
xml2json
Has anyone encountered this situation before?
I think this is the best one: Converting between XML and JSON
Be sure to read the accompanying article on the xml.com O'Reilly site, which goes into details of the problems with these conversions, which I think you will find enlightening. The fact that O'Reilly is hosting the article should indicate that Stefan's solution has merit.
https://github.com/abdmob/x2js - my own library (updated URL from http://code.google.com/p/x2js/):
This library provides XML to JSON (JavaScript Objects) and vice versa javascript conversion functions. The library is very small and doesn't require any other additional libraries.
API functions
new X2JS() - to create your instance to access all library functionality. Also you could specify optional configuration options here
X2JS.xml2json - Convert XML specified as DOM Object to JSON
X2JS.json2xml - Convert JSON to XML DOM Object
X2JS.xml_str2json - Convert XML specified as string to JSON
X2JS.json2xml_str - Convert JSON to XML string
Online Demo on http://jsfiddle.net/abdmob/gkxucxrj/1/
var x2js = new X2JS();
function convertXml2JSon() {
$("#jsonArea").val(JSON.stringify(x2js.xml_str2json($("#xmlArea").val())));
}
function convertJSon2XML() {
$("#xmlArea").val(x2js.json2xml_str($.parseJSON($("#jsonArea").val())));
}
convertXml2JSon();
convertJSon2XML();
$("#convertToJsonBtn").click(convertXml2JSon);
$("#convertToXmlBtn").click(convertJSon2XML);
These answers helped me a lot to make this function:
function xml2json(xml) {
try {
var obj = {};
if (xml.children.length > 0) {
for (var i = 0; i < xml.children.length; i++) {
var item = xml.children.item(i);
var nodeName = item.nodeName;
if (typeof (obj[nodeName]) == "undefined") {
obj[nodeName] = xml2json(item);
} else {
if (typeof (obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xml2json(item));
}
}
} else {
obj = xml.textContent;
}
return obj;
} catch (e) {
console.log(e.message);
}
}
As long as you pass in a jquery dom/xml object: for me it was:
Jquery(this).find('content').eq(0)[0]
where content was the field I was storing my xml in.
I've created a recursive function based on regex, in case you don't want to install library and understand the logic behind what's happening:
const xmlSample = '<tag>tag content</tag><tag2>another content</tag2><tag3><insideTag>inside content</insideTag><emptyTag /></tag3>';
console.log(parseXmlToJson(xmlSample));
function parseXmlToJson(xml) {
const json = {};
for (const res of xml.matchAll(/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) {
const key = res[1] || res[3];
const value = res[2] && parseXmlToJson(res[2]);
json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null;
}
return json;
}
Regex explanation for each loop:
res[0] - return the xml (as is)
res[1] - return the xml tag name
res[2] - return the xml content
res[3] - return the xml tag name in case the tag closes itself. In example: <tag />
You can check how the regex works here:
https://regex101.com/r/ZJpCAL/1
Note: In case json has a key with an undefined value, it is being removed.
That's why I've inserted null at the end of line 9.
I was using xmlToJson just to get a single value of the xml.
I found doing the following is much easier (if the xml only occurs once..)
let xml =
'<person>' +
' <id>762384324</id>' +
' <firstname>Hank</firstname> ' +
' <lastname>Stone</lastname>' +
'</person>';
let getXmlValue = function(str, key) {
return str.substring(
str.lastIndexOf('<' + key + '>') + ('<' + key + '>').length,
str.lastIndexOf('</' + key + '>')
);
}
alert(getXmlValue(xml, 'firstname')); // gives back Hank
You can also use txml. It can parse into a DOM made of simple objects and stringify. In the result, the content will be trimmed. So formating of the original with whitespaces will be lost. But this could be used very good to minify HTML.
const xml = require('txml');
const data = `
<tag>tag content</tag>
<tag2>another content</tag2>
<tag3>
<insideTag>inside content</insideTag>
<emptyTag />
</tag3>`;
const dom = xml(data); // the dom can be JSON.stringified
xml.stringify(dom); // this will return the dom into an xml-string
Disclaimer: I am the author of txml, the fastest xml parser in javascript.
A while back I wrote this tool https://bitbucket.org/surenrao/xml2json for my TV Watchlist app, hope this helps too.
Synopsys: A library to not only convert xml to json, but is also easy to debug (without circular errors) and recreate json back to xml. Features :- Parse xml to json object. Print json object back to xml. Can be used to save xml in IndexedDB as X2J objects. Print json object.
In 6 simple ES6 lines:
xml2json = xml => {
var el = xml.nodeType === 9 ? xml.documentElement : xml
var h = {name: el.nodeName}
h.content = Array.from(el.childNodes || []).filter(e => e.nodeType === 3).map(e => e.textContent).join('').trim()
h.attributes = Array.from(el.attributes || []).filter(a => a).reduce((h, a) => { h[a.name] = a.value; return h }, {})
h.children = Array.from(el.childNodes || []).filter(e => e.nodeType === 1).map(c => h[c.nodeName] = xml2json(c))
return h
}
Test with echo "xml2json_example()" | node -r xml2json.es6 with source at https://github.com/brauliobo/biochemical-db/blob/master/lib/xml2json.es6
Disclaimer: I've written fast-xml-parser
Fast XML Parser can help to convert XML to JSON and vice versa. Here is the example;
var options = {
attributeNamePrefix : "#_",
attrNodeName: "attr", //default is 'false'
textNodeName : "#text",
ignoreAttributes : true,
ignoreNameSpace : false,
allowBooleanAttributes : false,
parseNodeValue : true,
parseAttributeValue : false,
trimValues: true,
decodeHTMLchar: false,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
};
if(parser.validate(xmlData)=== true){//optional
var jsonObj = parser.parse(xmlData,options);
}
If you want to parse JSON or JS object into XML then
//default options need not to set
var defaultOptions = {
attributeNamePrefix : "#_",
attrNodeName: "#", //default is false
textNodeName : "#text",
ignoreAttributes : true,
encodeHTMLchar: false,
cdataTagName: "__cdata", //default is false
cdataPositionChar: "\\c",
format: false,
indentBy: " ",
supressEmptyNode: false
};
var parser = new parser.j2xParser(defaultOptions);
var xml = parser.parse(json_or_js_obj);
Here' a good tool from a documented and very famous npm library that does the xml <-> js conversions very well: differently from some (maybe all) of the above proposed solutions, it converts xml comments also.
var obj = {name: "Super", Surname: "Man", age: 23};
var builder = new xml2js.Builder();
var xml = builder.buildObject(obj);
I would personally recommend this tool. It is an XML to JSON converter.
It is very lightweight and is in pure JavaScript. It needs no dependencies. You can simply add the functions to your code and use it as you wish.
It also takes the XML attributes into considerations.
var xml = ‘<person id=”1234” age=”30”><name>John Doe</name></person>’;
var json = xml2json(xml);
console.log(json);
// prints ‘{“person”: {“id”: “1234”, “age”: “30”, “name”: “John Doe”}}’
Here's an online demo!
There is an open sourced library Xml-to-json with methods jsonToXml(json) and xmlToJson(xml).
Here's an online demo!
This function directly reads the DOM properties of the XMLDocument (or document node/element) to build the JSON completely and accurately without trying to guess or match. Pass it responseXML, not responseText from XMLHttpRequest.
xml2json(xmlDoc)
If you only have a string of XML and not an XMLDocument, jQuery will convert your text to one.
xml2json($(xmlString)[0])
Each node becomes an object. (All elements are nodes, not all nodes are elements (e.g. text within an element).)
Every object contains the node name and type.
If it has attributes, they appear as properties in an attributes object.
If it has children, they appear recursively as node->objects in a children array.
If it's a Text, CDATA, or Comment node (bare text between element tags) or a comment, it shouldn't have attributes or children but the text will be in a text property.
{
// Always present
"name": "FancyElement",
"type": "Element",
// If present
"attributes: {
"attr1": "val1",
"attr2": "val2"
},
"children": [...],
"text": "buncha fancy words"
}
Caveat: I'm not familiar with all the node types. It's probably not grabbing needed/useful info from all of them. It was tested on and behaves as expected for
Element
Text
CDATA
Comment
Document
function xml2json(xml) {
try {
const types = [null,
"Element",
"Attribute",
"Text",
"CDATA",
"EntityReference", // Deprecated
"Entity", // Deprecated
"ProcessingInstruction",
"Comment",
"Document",
"DocumentType",
"DocumentFragment",
"Notation" // Deprecated
];
var o = {};
o.name = xml.nodeName;
o.type = types[xml.nodeType];
if (xml.nodeType == 3 ||
xml.nodeType == 4 ||
xml.nodeType == 8 ) {
o.text = xml.textContent;
} else {
if (xml.attributes) {
o.attributes = {};
for (const a of xml.attributes) {
o.attributes[a.name] = a.value;
}
}
if (xml.childNodes.length) {
o.children = [];
for (const x of xml.childNodes) {
o.children.push(xml2json(x))
}
}
}
return (o);
} catch (e) {
alert('Error in xml2json. See console for details.');
console.log('Error in xml2json processing node:');
console.log(o);
console.log('Error:');
console.log(e);
}
}
var doc = document.getElementById("doc");
var out = document.getElementById("out");
out.innerText = JSON.stringify(xml2json(doc), null, 2);
/* Let's process the whole Code Snippet #document, why not?
* Yes, the JSON we just put in the document body and all
* this code is encoded in the JSON in the console.
* In that copy you can see why the XML DOM will all be one line.
* The JSON in the console has "\n" nodes all throughout.
*/
console.log(xml2json(document));
#doc,
#out {
border: 1px solid black;
}
<div id="doc"><!-- The XML DOM will all be on one line --><div personality="bubbly" relevance=42>This text is valid for HTML.<span>But it probably shouldn't be siblings to an element in XML.</span></div></div>
<pre id="out"></pre>
The best way to do it using server side as client side doesn't work well in all scenarios. I was trying to build online json to xml and xml to json converter using javascript and I felt almost impossible as it was not working in all scenarios. Ultimately I ended up doing it server side using Newtonsoft in ASP.MVC. Here is the online converter http://techfunda.com/Tools/XmlToJson
How would you convert from XML to JSON and then back to XML?
The following tools work quite well, but aren't completely consistent:
xml2json
Has anyone encountered this situation before?
I think this is the best one: Converting between XML and JSON
Be sure to read the accompanying article on the xml.com O'Reilly site, which goes into details of the problems with these conversions, which I think you will find enlightening. The fact that O'Reilly is hosting the article should indicate that Stefan's solution has merit.
https://github.com/abdmob/x2js - my own library (updated URL from http://code.google.com/p/x2js/):
This library provides XML to JSON (JavaScript Objects) and vice versa javascript conversion functions. The library is very small and doesn't require any other additional libraries.
API functions
new X2JS() - to create your instance to access all library functionality. Also you could specify optional configuration options here
X2JS.xml2json - Convert XML specified as DOM Object to JSON
X2JS.json2xml - Convert JSON to XML DOM Object
X2JS.xml_str2json - Convert XML specified as string to JSON
X2JS.json2xml_str - Convert JSON to XML string
Online Demo on http://jsfiddle.net/abdmob/gkxucxrj/1/
var x2js = new X2JS();
function convertXml2JSon() {
$("#jsonArea").val(JSON.stringify(x2js.xml_str2json($("#xmlArea").val())));
}
function convertJSon2XML() {
$("#xmlArea").val(x2js.json2xml_str($.parseJSON($("#jsonArea").val())));
}
convertXml2JSon();
convertJSon2XML();
$("#convertToJsonBtn").click(convertXml2JSon);
$("#convertToXmlBtn").click(convertJSon2XML);
These answers helped me a lot to make this function:
function xml2json(xml) {
try {
var obj = {};
if (xml.children.length > 0) {
for (var i = 0; i < xml.children.length; i++) {
var item = xml.children.item(i);
var nodeName = item.nodeName;
if (typeof (obj[nodeName]) == "undefined") {
obj[nodeName] = xml2json(item);
} else {
if (typeof (obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xml2json(item));
}
}
} else {
obj = xml.textContent;
}
return obj;
} catch (e) {
console.log(e.message);
}
}
As long as you pass in a jquery dom/xml object: for me it was:
Jquery(this).find('content').eq(0)[0]
where content was the field I was storing my xml in.
I've created a recursive function based on regex, in case you don't want to install library and understand the logic behind what's happening:
const xmlSample = '<tag>tag content</tag><tag2>another content</tag2><tag3><insideTag>inside content</insideTag><emptyTag /></tag3>';
console.log(parseXmlToJson(xmlSample));
function parseXmlToJson(xml) {
const json = {};
for (const res of xml.matchAll(/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) {
const key = res[1] || res[3];
const value = res[2] && parseXmlToJson(res[2]);
json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null;
}
return json;
}
Regex explanation for each loop:
res[0] - return the xml (as is)
res[1] - return the xml tag name
res[2] - return the xml content
res[3] - return the xml tag name in case the tag closes itself. In example: <tag />
You can check how the regex works here:
https://regex101.com/r/ZJpCAL/1
Note: In case json has a key with an undefined value, it is being removed.
That's why I've inserted null at the end of line 9.
I was using xmlToJson just to get a single value of the xml.
I found doing the following is much easier (if the xml only occurs once..)
let xml =
'<person>' +
' <id>762384324</id>' +
' <firstname>Hank</firstname> ' +
' <lastname>Stone</lastname>' +
'</person>';
let getXmlValue = function(str, key) {
return str.substring(
str.lastIndexOf('<' + key + '>') + ('<' + key + '>').length,
str.lastIndexOf('</' + key + '>')
);
}
alert(getXmlValue(xml, 'firstname')); // gives back Hank
You can also use txml. It can parse into a DOM made of simple objects and stringify. In the result, the content will be trimmed. So formating of the original with whitespaces will be lost. But this could be used very good to minify HTML.
const xml = require('txml');
const data = `
<tag>tag content</tag>
<tag2>another content</tag2>
<tag3>
<insideTag>inside content</insideTag>
<emptyTag />
</tag3>`;
const dom = xml(data); // the dom can be JSON.stringified
xml.stringify(dom); // this will return the dom into an xml-string
Disclaimer: I am the author of txml, the fastest xml parser in javascript.
A while back I wrote this tool https://bitbucket.org/surenrao/xml2json for my TV Watchlist app, hope this helps too.
Synopsys: A library to not only convert xml to json, but is also easy to debug (without circular errors) and recreate json back to xml. Features :- Parse xml to json object. Print json object back to xml. Can be used to save xml in IndexedDB as X2J objects. Print json object.
In 6 simple ES6 lines:
xml2json = xml => {
var el = xml.nodeType === 9 ? xml.documentElement : xml
var h = {name: el.nodeName}
h.content = Array.from(el.childNodes || []).filter(e => e.nodeType === 3).map(e => e.textContent).join('').trim()
h.attributes = Array.from(el.attributes || []).filter(a => a).reduce((h, a) => { h[a.name] = a.value; return h }, {})
h.children = Array.from(el.childNodes || []).filter(e => e.nodeType === 1).map(c => h[c.nodeName] = xml2json(c))
return h
}
Test with echo "xml2json_example()" | node -r xml2json.es6 with source at https://github.com/brauliobo/biochemical-db/blob/master/lib/xml2json.es6
Disclaimer: I've written fast-xml-parser
Fast XML Parser can help to convert XML to JSON and vice versa. Here is the example;
var options = {
attributeNamePrefix : "#_",
attrNodeName: "attr", //default is 'false'
textNodeName : "#text",
ignoreAttributes : true,
ignoreNameSpace : false,
allowBooleanAttributes : false,
parseNodeValue : true,
parseAttributeValue : false,
trimValues: true,
decodeHTMLchar: false,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
};
if(parser.validate(xmlData)=== true){//optional
var jsonObj = parser.parse(xmlData,options);
}
If you want to parse JSON or JS object into XML then
//default options need not to set
var defaultOptions = {
attributeNamePrefix : "#_",
attrNodeName: "#", //default is false
textNodeName : "#text",
ignoreAttributes : true,
encodeHTMLchar: false,
cdataTagName: "__cdata", //default is false
cdataPositionChar: "\\c",
format: false,
indentBy: " ",
supressEmptyNode: false
};
var parser = new parser.j2xParser(defaultOptions);
var xml = parser.parse(json_or_js_obj);
Here' a good tool from a documented and very famous npm library that does the xml <-> js conversions very well: differently from some (maybe all) of the above proposed solutions, it converts xml comments also.
var obj = {name: "Super", Surname: "Man", age: 23};
var builder = new xml2js.Builder();
var xml = builder.buildObject(obj);
I would personally recommend this tool. It is an XML to JSON converter.
It is very lightweight and is in pure JavaScript. It needs no dependencies. You can simply add the functions to your code and use it as you wish.
It also takes the XML attributes into considerations.
var xml = ‘<person id=”1234” age=”30”><name>John Doe</name></person>’;
var json = xml2json(xml);
console.log(json);
// prints ‘{“person”: {“id”: “1234”, “age”: “30”, “name”: “John Doe”}}’
Here's an online demo!
There is an open sourced library Xml-to-json with methods jsonToXml(json) and xmlToJson(xml).
Here's an online demo!
This function directly reads the DOM properties of the XMLDocument (or document node/element) to build the JSON completely and accurately without trying to guess or match. Pass it responseXML, not responseText from XMLHttpRequest.
xml2json(xmlDoc)
If you only have a string of XML and not an XMLDocument, jQuery will convert your text to one.
xml2json($(xmlString)[0])
Each node becomes an object. (All elements are nodes, not all nodes are elements (e.g. text within an element).)
Every object contains the node name and type.
If it has attributes, they appear as properties in an attributes object.
If it has children, they appear recursively as node->objects in a children array.
If it's a Text, CDATA, or Comment node (bare text between element tags) or a comment, it shouldn't have attributes or children but the text will be in a text property.
{
// Always present
"name": "FancyElement",
"type": "Element",
// If present
"attributes: {
"attr1": "val1",
"attr2": "val2"
},
"children": [...],
"text": "buncha fancy words"
}
Caveat: I'm not familiar with all the node types. It's probably not grabbing needed/useful info from all of them. It was tested on and behaves as expected for
Element
Text
CDATA
Comment
Document
function xml2json(xml) {
try {
const types = [null,
"Element",
"Attribute",
"Text",
"CDATA",
"EntityReference", // Deprecated
"Entity", // Deprecated
"ProcessingInstruction",
"Comment",
"Document",
"DocumentType",
"DocumentFragment",
"Notation" // Deprecated
];
var o = {};
o.name = xml.nodeName;
o.type = types[xml.nodeType];
if (xml.nodeType == 3 ||
xml.nodeType == 4 ||
xml.nodeType == 8 ) {
o.text = xml.textContent;
} else {
if (xml.attributes) {
o.attributes = {};
for (const a of xml.attributes) {
o.attributes[a.name] = a.value;
}
}
if (xml.childNodes.length) {
o.children = [];
for (const x of xml.childNodes) {
o.children.push(xml2json(x))
}
}
}
return (o);
} catch (e) {
alert('Error in xml2json. See console for details.');
console.log('Error in xml2json processing node:');
console.log(o);
console.log('Error:');
console.log(e);
}
}
var doc = document.getElementById("doc");
var out = document.getElementById("out");
out.innerText = JSON.stringify(xml2json(doc), null, 2);
/* Let's process the whole Code Snippet #document, why not?
* Yes, the JSON we just put in the document body and all
* this code is encoded in the JSON in the console.
* In that copy you can see why the XML DOM will all be one line.
* The JSON in the console has "\n" nodes all throughout.
*/
console.log(xml2json(document));
#doc,
#out {
border: 1px solid black;
}
<div id="doc"><!-- The XML DOM will all be on one line --><div personality="bubbly" relevance=42>This text is valid for HTML.<span>But it probably shouldn't be siblings to an element in XML.</span></div></div>
<pre id="out"></pre>
The best way to do it using server side as client side doesn't work well in all scenarios. I was trying to build online json to xml and xml to json converter using javascript and I felt almost impossible as it was not working in all scenarios. Ultimately I ended up doing it server side using Newtonsoft in ASP.MVC. Here is the online converter http://techfunda.com/Tools/XmlToJson
I use fullcalendar jquery plugin from http://arshaw.com/fullcalendar/
and I use knockout js on my website.
I added the event array what is the source of the calendar. The user can modify the events (array).
Then I want to serialize the event array, send by ajax, but I can not, because the calendar modifies my array, and puts an cycle into the source array. How can I remove the changes. Why is there a cycle in my array? I read, may be there is an DOM object in this.
Chrome sendrequest error: TypeError: Converting circular structure to JSON
var a = [];
a.push({
title: "Event2",
start: "2013-09-05"
});
a.push({
title: "Event2",
start: "2013-09-15"
});
$("#calendar").fullCalendar({
events: a,
header: {
left: "title",
center: "",
right: "today prev,next"
},
editable: false
});
console.log(JSON.stringify(a));
TypeError: Converting circular structure to JSON
How can I fix it?
What is the cause of the cycle?
fiddle example, you can see my problem:
http://jsfiddle.net/erbsaag/XC3NH/1
The plugin is modifying your data.
If you run
console.log(a)
before your console.log you can see the issue. One solution is to only return the fields you need, and not return the fields which have cyclical recursions.
Example:
console.log(JSON.stringify(a.map(function(ai) { return {title: ai.title, start: ai.start}})));
Please refer to this question:
JSON.stringify, avoid TypeError: Converting circular structure to JSON
Here is a function adapting that answer into a simple reusable one-liner:
const jsonStringifySafe = (o) => {
// Almost as seen in stackoverflow.com/questions/11616630
var cache = [];
let retv = JSON.stringify(o, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// Circular reference found, discard key
return;
}
// Store value in our collection
cache.push(value);
}
return value;
});
cache = null;
return retv;
}
usage:
console.log(jsonStringifySafe(a));
Example:
http://jsfiddle.net/felyper/XC3NH/17/
How would you convert from XML to JSON and then back to XML?
The following tools work quite well, but aren't completely consistent:
xml2json
Has anyone encountered this situation before?
I think this is the best one: Converting between XML and JSON
Be sure to read the accompanying article on the xml.com O'Reilly site, which goes into details of the problems with these conversions, which I think you will find enlightening. The fact that O'Reilly is hosting the article should indicate that Stefan's solution has merit.
https://github.com/abdmob/x2js - my own library (updated URL from http://code.google.com/p/x2js/):
This library provides XML to JSON (JavaScript Objects) and vice versa javascript conversion functions. The library is very small and doesn't require any other additional libraries.
API functions
new X2JS() - to create your instance to access all library functionality. Also you could specify optional configuration options here
X2JS.xml2json - Convert XML specified as DOM Object to JSON
X2JS.json2xml - Convert JSON to XML DOM Object
X2JS.xml_str2json - Convert XML specified as string to JSON
X2JS.json2xml_str - Convert JSON to XML string
Online Demo on http://jsfiddle.net/abdmob/gkxucxrj/1/
var x2js = new X2JS();
function convertXml2JSon() {
$("#jsonArea").val(JSON.stringify(x2js.xml_str2json($("#xmlArea").val())));
}
function convertJSon2XML() {
$("#xmlArea").val(x2js.json2xml_str($.parseJSON($("#jsonArea").val())));
}
convertXml2JSon();
convertJSon2XML();
$("#convertToJsonBtn").click(convertXml2JSon);
$("#convertToXmlBtn").click(convertJSon2XML);
These answers helped me a lot to make this function:
function xml2json(xml) {
try {
var obj = {};
if (xml.children.length > 0) {
for (var i = 0; i < xml.children.length; i++) {
var item = xml.children.item(i);
var nodeName = item.nodeName;
if (typeof (obj[nodeName]) == "undefined") {
obj[nodeName] = xml2json(item);
} else {
if (typeof (obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xml2json(item));
}
}
} else {
obj = xml.textContent;
}
return obj;
} catch (e) {
console.log(e.message);
}
}
As long as you pass in a jquery dom/xml object: for me it was:
Jquery(this).find('content').eq(0)[0]
where content was the field I was storing my xml in.
I've created a recursive function based on regex, in case you don't want to install library and understand the logic behind what's happening:
const xmlSample = '<tag>tag content</tag><tag2>another content</tag2><tag3><insideTag>inside content</insideTag><emptyTag /></tag3>';
console.log(parseXmlToJson(xmlSample));
function parseXmlToJson(xml) {
const json = {};
for (const res of xml.matchAll(/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) {
const key = res[1] || res[3];
const value = res[2] && parseXmlToJson(res[2]);
json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null;
}
return json;
}
Regex explanation for each loop:
res[0] - return the xml (as is)
res[1] - return the xml tag name
res[2] - return the xml content
res[3] - return the xml tag name in case the tag closes itself. In example: <tag />
You can check how the regex works here:
https://regex101.com/r/ZJpCAL/1
Note: In case json has a key with an undefined value, it is being removed.
That's why I've inserted null at the end of line 9.
I was using xmlToJson just to get a single value of the xml.
I found doing the following is much easier (if the xml only occurs once..)
let xml =
'<person>' +
' <id>762384324</id>' +
' <firstname>Hank</firstname> ' +
' <lastname>Stone</lastname>' +
'</person>';
let getXmlValue = function(str, key) {
return str.substring(
str.lastIndexOf('<' + key + '>') + ('<' + key + '>').length,
str.lastIndexOf('</' + key + '>')
);
}
alert(getXmlValue(xml, 'firstname')); // gives back Hank
You can also use txml. It can parse into a DOM made of simple objects and stringify. In the result, the content will be trimmed. So formating of the original with whitespaces will be lost. But this could be used very good to minify HTML.
const xml = require('txml');
const data = `
<tag>tag content</tag>
<tag2>another content</tag2>
<tag3>
<insideTag>inside content</insideTag>
<emptyTag />
</tag3>`;
const dom = xml(data); // the dom can be JSON.stringified
xml.stringify(dom); // this will return the dom into an xml-string
Disclaimer: I am the author of txml, the fastest xml parser in javascript.
A while back I wrote this tool https://bitbucket.org/surenrao/xml2json for my TV Watchlist app, hope this helps too.
Synopsys: A library to not only convert xml to json, but is also easy to debug (without circular errors) and recreate json back to xml. Features :- Parse xml to json object. Print json object back to xml. Can be used to save xml in IndexedDB as X2J objects. Print json object.
In 6 simple ES6 lines:
xml2json = xml => {
var el = xml.nodeType === 9 ? xml.documentElement : xml
var h = {name: el.nodeName}
h.content = Array.from(el.childNodes || []).filter(e => e.nodeType === 3).map(e => e.textContent).join('').trim()
h.attributes = Array.from(el.attributes || []).filter(a => a).reduce((h, a) => { h[a.name] = a.value; return h }, {})
h.children = Array.from(el.childNodes || []).filter(e => e.nodeType === 1).map(c => h[c.nodeName] = xml2json(c))
return h
}
Test with echo "xml2json_example()" | node -r xml2json.es6 with source at https://github.com/brauliobo/biochemical-db/blob/master/lib/xml2json.es6
Disclaimer: I've written fast-xml-parser
Fast XML Parser can help to convert XML to JSON and vice versa. Here is the example;
var options = {
attributeNamePrefix : "#_",
attrNodeName: "attr", //default is 'false'
textNodeName : "#text",
ignoreAttributes : true,
ignoreNameSpace : false,
allowBooleanAttributes : false,
parseNodeValue : true,
parseAttributeValue : false,
trimValues: true,
decodeHTMLchar: false,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
};
if(parser.validate(xmlData)=== true){//optional
var jsonObj = parser.parse(xmlData,options);
}
If you want to parse JSON or JS object into XML then
//default options need not to set
var defaultOptions = {
attributeNamePrefix : "#_",
attrNodeName: "#", //default is false
textNodeName : "#text",
ignoreAttributes : true,
encodeHTMLchar: false,
cdataTagName: "__cdata", //default is false
cdataPositionChar: "\\c",
format: false,
indentBy: " ",
supressEmptyNode: false
};
var parser = new parser.j2xParser(defaultOptions);
var xml = parser.parse(json_or_js_obj);
Here' a good tool from a documented and very famous npm library that does the xml <-> js conversions very well: differently from some (maybe all) of the above proposed solutions, it converts xml comments also.
var obj = {name: "Super", Surname: "Man", age: 23};
var builder = new xml2js.Builder();
var xml = builder.buildObject(obj);
I would personally recommend this tool. It is an XML to JSON converter.
It is very lightweight and is in pure JavaScript. It needs no dependencies. You can simply add the functions to your code and use it as you wish.
It also takes the XML attributes into considerations.
var xml = ‘<person id=”1234” age=”30”><name>John Doe</name></person>’;
var json = xml2json(xml);
console.log(json);
// prints ‘{“person”: {“id”: “1234”, “age”: “30”, “name”: “John Doe”}}’
Here's an online demo!
There is an open sourced library Xml-to-json with methods jsonToXml(json) and xmlToJson(xml).
Here's an online demo!
This function directly reads the DOM properties of the XMLDocument (or document node/element) to build the JSON completely and accurately without trying to guess or match. Pass it responseXML, not responseText from XMLHttpRequest.
xml2json(xmlDoc)
If you only have a string of XML and not an XMLDocument, jQuery will convert your text to one.
xml2json($(xmlString)[0])
Each node becomes an object. (All elements are nodes, not all nodes are elements (e.g. text within an element).)
Every object contains the node name and type.
If it has attributes, they appear as properties in an attributes object.
If it has children, they appear recursively as node->objects in a children array.
If it's a Text, CDATA, or Comment node (bare text between element tags) or a comment, it shouldn't have attributes or children but the text will be in a text property.
{
// Always present
"name": "FancyElement",
"type": "Element",
// If present
"attributes: {
"attr1": "val1",
"attr2": "val2"
},
"children": [...],
"text": "buncha fancy words"
}
Caveat: I'm not familiar with all the node types. It's probably not grabbing needed/useful info from all of them. It was tested on and behaves as expected for
Element
Text
CDATA
Comment
Document
function xml2json(xml) {
try {
const types = [null,
"Element",
"Attribute",
"Text",
"CDATA",
"EntityReference", // Deprecated
"Entity", // Deprecated
"ProcessingInstruction",
"Comment",
"Document",
"DocumentType",
"DocumentFragment",
"Notation" // Deprecated
];
var o = {};
o.name = xml.nodeName;
o.type = types[xml.nodeType];
if (xml.nodeType == 3 ||
xml.nodeType == 4 ||
xml.nodeType == 8 ) {
o.text = xml.textContent;
} else {
if (xml.attributes) {
o.attributes = {};
for (const a of xml.attributes) {
o.attributes[a.name] = a.value;
}
}
if (xml.childNodes.length) {
o.children = [];
for (const x of xml.childNodes) {
o.children.push(xml2json(x))
}
}
}
return (o);
} catch (e) {
alert('Error in xml2json. See console for details.');
console.log('Error in xml2json processing node:');
console.log(o);
console.log('Error:');
console.log(e);
}
}
var doc = document.getElementById("doc");
var out = document.getElementById("out");
out.innerText = JSON.stringify(xml2json(doc), null, 2);
/* Let's process the whole Code Snippet #document, why not?
* Yes, the JSON we just put in the document body and all
* this code is encoded in the JSON in the console.
* In that copy you can see why the XML DOM will all be one line.
* The JSON in the console has "\n" nodes all throughout.
*/
console.log(xml2json(document));
#doc,
#out {
border: 1px solid black;
}
<div id="doc"><!-- The XML DOM will all be on one line --><div personality="bubbly" relevance=42>This text is valid for HTML.<span>But it probably shouldn't be siblings to an element in XML.</span></div></div>
<pre id="out"></pre>
The best way to do it using server side as client side doesn't work well in all scenarios. I was trying to build online json to xml and xml to json converter using javascript and I felt almost impossible as it was not working in all scenarios. Ultimately I ended up doing it server side using Newtonsoft in ASP.MVC. Here is the online converter http://techfunda.com/Tools/XmlToJson