Convert XML to JSON (and back) using Javascript
Asked Answered
S

14

176

How would you convert from XML to JSON and then back to XML?

The following tools work quite well, but aren't completely consistent:

Has anyone encountered this situation before?

Seismo answered 20/11, 2009 at 22:6 Comment(7)
Explain the inconsistencies, pleaseIrvingirwin
Specifically, had to do with converting JSON arrays with just 1 element to XML. When you converted it back to JSON, instead of a 1-element array, it created the object literal. I worked around it by checking the type with $.isArray(), and wrapping it in an array if !$.isArray().Veda
xml2json - fyneworks.com/jquery/xml-to-json - breaks throws 500 as of 15/02/2013 14:25 AESTEllipticity
The json2xml link is broken.Rome
@Ellipticity The plugin example will not work in IE8!Statism
github.com/javadev/xml-to-json I am the mainteiner of the library.Gwendagwendolen
Have you try this?devtoolsonline20190908040816.azurewebsites.net/DevTools/…Raver
I
128

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.

Irvingirwin answered 20/11, 2009 at 22:11 Comment(11)
thanks for the reply! In my case, the JSON is the canonical representation, and XML is just used for XSLT.. the use of which is not my idea! :)Veda
This is only in the browser. Doesn't apply for node.js or non-browser environments. Any other ideas?Socman
In regards to @JasonDenizac comment to his post, I am not sure to understand how this link helps fixing the issue of having an object instead of an array of one item...Ation
I found that if you start from json-xml-json, this library works well, but if you want xml-json-xml there is a problem with reversibility since it adds metadata xml elements like <o> and <e>Satinwood
Please note that this is a copyleft licensed solution. It is only an option when you are writing open source software.Scabious
@Jasper: That isn't true re the LGPL. Straight from the gnu's mouth, as it were: gnu.org/philosophy/why-not-lgpl.html. Using the LGPL is generally only a problem if you change the code and even then you only need to release your changes.Monomerous
@Monomerous LGPL is tricky. Using a minifier (which is common for javascript) might be in breach of it (though you would need a lawyer to be sure). I was wrong to say you can't use it when not writing FOSS, but if you aren't, you will have to be careful not to step into the legal minefield that LGPL creates...Scabious
For me this alerts some "unhandled types" in Firefox v30 on Win7Statism
It is Really the Best.Drennan
Is there a "Standard" tool. i dread downloading the best tool only to find two years later its been abandoned.Marianamariand
@Dan The tools xml2json and json2xml have been abandoned for 13 years. But who cares? The scripts will continue to work. It is vanilla JS.Housebound
B
56

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);
Blow answered 9/12, 2011 at 13:22 Comment(10)
Hi, how did you overcome the issue where if you have one object in an object it is in object litteral, where if there is n > 1 objects, you have an array. This makes it hard to use xml to json objects in templates...Ation
Yes, you should use some trick and it depends on your knowledge about XML structure (because no XSD here). Use <node>...<node>_asArray syntax to access your node always as array(sequence)Blow
Sample:// XML string to JSON var xmlText = "<MyOperation><test>Success</test><test2><item>ddsfg</item><item>dsdgfdgfd</item></test2></MyOperation>"; var jsonObj = X2JS.xml_str2json( xmlText ); alert (jsonObj.MyOperation.test); alert (jsonObj.MyOperation.test_asArray[0]);Blow
My main problem, is when I transform my json to xml back, the json is full of extra properties, and when the string xml version keeps all the useless stuff. It has all kind of commas, and whitespaces...Ation
could you submit your sample to code.google.com/p/x2js/issues I'll check itBlow
Is this your own library? If so, please add a note to your answer. It's good form.Scabious
Well done, I can easily parse an entire OData $metadata Saved me days of refactorBenitobenjamen
@abdolence: you saved my time. thank you so much. it really worked.Owensby
@Blow Is that repo still maintained? It looks kinda dead :-(Roebuck
@Roebuck I'm really sorry, x2js is really an old lib and I stopped using it personally many years ago. I saw a lot of forks though and think you can find something more updated for nowadays browsers/environments.Blow
L
40

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.

Low answered 31/12, 2013 at 18:7 Comment(5)
saved my day! Almost all other examples are not working even JSFiddle examples!Buncombe
works pretty good so far. Thank youRockrose
ERROR: xml.children is undefinedAachen
Looks like you're not grabbing any element attributes, which is where almost all the data I need is stored.Unstudied
I found this most useful among all the answers because it is easy to handle all kind of attribute usages of xml docs out there, at the last part of the code "else { obj = xml.textContent; }".Egoism
S
21

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.

Stauder answered 4/5, 2020 at 13:47 Comment(7)
Not working as expected deep nested xml string values.Gwinn
@sankarmuniyappa please write an example that didn't work so I'll fix it :)Stauder
how to make it work with this XML? <chan> <item> <tag>tag content</tag><tag2>another content</tag2><tag3><insideTag>inside content</insideTag><emptyTag /></tag3> </item> <item> <tag>tag content</tag><tag2>another content</tag2><tag3><insideTag>inside content</insideTag><emptyTag /></tag3> </item> </chan>Record
The function returns the correct output for your case: {"chan":{"item":{"tag":"tag content","tag2":"another content","tag3":{"insideTag":"inside content","emptyTag":null}}}}Stauder
@Stauder hmm, in docs.scriptable.app, the function only returns the last one item: {"tag":"tag2 content","tag2":"another content 2","tag3":{"insideTag":"inside content 2","emptyTag":null}}Record
if I write <tag3> <insideTag>inside content</insideTag> <emptyTag /> </tag3> in multiple lines using Template Literals it does not return nested json instead It separates all keys.Lysis
If I use the same tag twice, it only gives the first tag and it's value.Dzungaria
E
5

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
Ericerica answered 21/6, 2019 at 10:24 Comment(2)
Keep up the job! This definitely helped me!Carlos
No problem!!! BDCarlos
A
5

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.

Abigael answered 25/8, 2020 at 10:26 Comment(1)
👍 This is a great drop-in replacement for fast-xml-parser, using simplify, that doesn't convert strings to numbers arbitrarily (like "1.0" to 1 or 1.)Llovera
S
3

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.

Spinule answered 1/9, 2013 at 19:16 Comment(1)
@kleopatra this link points to the tool which converts xml to json. Its not a reference but the actual link to the resource. Not sure how else i should do it :)Spinule
E
3

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

Equimolecular answered 12/11, 2019 at 20:49 Comment(2)
6 simple lines, plus 2000 lines from xml2jsonJeffjeffcoat
@Jeffjeffcoat the only dependency is xmldom, a xml parser. this doesn't use xml2json from npm, although the name is the sameEquimolecular
B
1

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);
Brio answered 17/2, 2018 at 3:3 Comment(1)
:D FXP is more than XML 2 JSON converter. Please check it's readme.Brio
B
0

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!

Boyd answered 22/1, 2016 at 18:27 Comment(1)
github repo not foundEquimolecular
M
0

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);
Mezereum answered 28/8, 2018 at 18:2 Comment(0)
G
0

There is an open sourced library Xml-to-json with methods jsonToXml(json) and xmlToJson(xml).

Here's an online demo!

Gwendagwendolen answered 18/1, 2023 at 1:21 Comment(0)
U
0

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>
Unstudied answered 15/2, 2023 at 10:58 Comment(0)
F
-5

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

Friedlander answered 5/6, 2015 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.