0

This is my first javascript project where I am trying to pull data from different APIs in order to make a small dashboard. I'm pulling data from an API in XML format and would like to convert it directly to JSON and store it in a variable.

const testdataurl = 'https://api.data.abs.gov.au/data/ABS,RES_DWELL/3.3GBRI.Q';
    
async function getData() {
    const response = await fetch(testdataurl);
    data = await response.text();
    console.log(data);
    }

getData()

You can see the API endpoint in the code above if you want to have a look at the XML. What's the easiest way for me to convert that as soon as it's pulled to JSON and store in a variable?

I have looked into using this:

https://goessner.net/download/prj/jsonxml/

but I'm not sure how to best implement it.

Thanks

  • Does this answer your question? [Convert XML to JSON (and back) using Javascript](https://stackoverflow.com/questions/1773550/convert-xml-to-json-and-back-using-javascript) – Kinglish Jul 13 '21 at 23:59
  • Why bother converting to json? Can't you just use it as xml? – Jack Fleeting Jul 14 '21 at 02:07
  • @JackFleeting I don't think I can use the data as XML. I'm trying to make a dashboard that will show data nicely and I thought having all my API pulls coming in as JSON would be much easier to work with – scrape_noob Jul 14 '21 at 07:50

1 Answers1

1

There are other resources that better explain how to import script into your html to make it available in your project. The script referenced was small enough for me to just copy / paste the snippet into a single post. For some reason the json string the code snippet was supposed to provide had an undefined segment returned. I am not sure why this is the case, but after examining the xml and the string returned, it does not look like it was important so I just remove it from the json string before parsing into an object.

keep in mind this code will not work on stackoverflow because of CORS. I tested it on the api.data.abs.gov.au website to avoid CORS issues.

Hopefully this helps.

function parseXml(xml) {
   var dom = null;
   if (window.DOMParser) {
      try { 
         dom = (new DOMParser()).parseFromString(xml, "text/xml"); 
      } 
      catch (e) { dom = null; }
   }
   else if (window.ActiveXObject) {
      try {
         dom = new ActiveXObject('Microsoft.XMLDOM');
         dom.async = false;
         if (!dom.loadXML(xml)) // parse error ..

            window.alert(dom.parseError.reason + dom.parseError.srcText);
      } 
      catch (e) { dom = null; }
   }
   else
      alert("cannot parse xml string!");
   return dom;
}

/*  This work is licensed under Creative Commons GNU LGPL License.

    License: http://creativecommons.org/licenses/LGPL/2.1/
   Version: 0.9
    Author:  Stefan Goessner/2006
    Web:     http://goessner.net/ 
*/
function xml2json(xml, tab) {
   var X = {
      toObj: function(xml) {
         var o = {};
         if (xml.nodeType==1) {   // element node ..
            if (xml.attributes.length)   // element with attributes  ..
               for (var i=0; i<xml.attributes.length; i++)
                  o["@"+xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue||"").toString();
            if (xml.firstChild) { // element has child nodes ..
               var textChild=0, cdataChild=0, hasElementChild=false;
               for (var n=xml.firstChild; n; n=n.nextSibling) {
                  if (n.nodeType==1) hasElementChild = true;
                  else if (n.nodeType==3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
                  else if (n.nodeType==4) cdataChild++; // cdata section node
               }
               if (hasElementChild) {
                  if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
                     X.removeWhite(xml);
                     for (var n=xml.firstChild; n; n=n.nextSibling) {
                        if (n.nodeType == 3)  // text node
                           o["#text"] = X.escape(n.nodeValue);
                        else if (n.nodeType == 4)  // cdata node
                           o["#cdata"] = X.escape(n.nodeValue);
                        else if (o[n.nodeName]) {  // multiple occurence of element ..
                           if (o[n.nodeName] instanceof Array)
                              o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
                           else
                              o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
                        }
                        else  // first occurence of element..
                           o[n.nodeName] = X.toObj(n);
                     }
                  }
                  else { // mixed content
                     if (!xml.attributes.length)
                        o = X.escape(X.innerXml(xml));
                     else
                        o["#text"] = X.escape(X.innerXml(xml));
                  }
               }
               else if (textChild) { // pure text
                  if (!xml.attributes.length)
                     o = X.escape(X.innerXml(xml));
                  else
                     o["#text"] = X.escape(X.innerXml(xml));
               }
               else if (cdataChild) { // cdata
                  if (cdataChild > 1)
                     o = X.escape(X.innerXml(xml));
                  else
                     for (var n=xml.firstChild; n; n=n.nextSibling)
                        o["#cdata"] = X.escape(n.nodeValue);
               }
            }
            if (!xml.attributes.length && !xml.firstChild) o = null;
         }
         else if (xml.nodeType==9) { // document.node
            o = X.toObj(xml.documentElement);
         }
         else
            alert("unhandled node type: " + xml.nodeType);
         return o;
      },
      toJson: function(o, name, ind) {
         var json = name ? ("\""+name+"\"") : "";
         if (o instanceof Array) {
            for (var i=0,n=o.length; i<n; i++)
               o[i] = X.toJson(o[i], "", ind+"\t");
            json += (name?":[":"[") + (o.length > 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]";
         }
         else if (o == null)
            json += (name&&":") + "null";
         else if (typeof(o) == "object") {
            var arr = [];
            for (var m in o)
               arr[arr.length] = X.toJson(o[m], m, ind+"\t");
            json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}";
         }
         else if (typeof(o) == "string")
            json += (name&&":") + "\"" + o.toString() + "\"";
         else
            json += (name&&":") + o.toString();
         return json;
      },
      innerXml: function(node) {
         var s = ""
         if ("innerHTML" in node)
            s = node.innerHTML;
         else {
            var asXml = function(n) {
               var s = "";
               if (n.nodeType == 1) {
                  s += "<" + n.nodeName;
                  for (var i=0; i<n.attributes.length;i++)
                     s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue||"").toString() + "\"";
                  if (n.firstChild) {
                     s += ">";
                     for (var c=n.firstChild; c; c=c.nextSibling)
                        s += asXml(c);
                     s += "</"+n.nodeName+">";
                  }
                  else
                     s += "/>";
               }
               else if (n.nodeType == 3)
                  s += n.nodeValue;
               else if (n.nodeType == 4)
                  s += "<![CDATA[" + n.nodeValue + "]]>";
               return s;
            };
            for (var c=node.firstChild; c; c=c.nextSibling)
               s += asXml(c);
         }
         return s;
      },
      escape: function(txt) {
         return txt.replace(/[\\]/g, "\\\\")
                   .replace(/[\"]/g, '\\"')
                   .replace(/[\n]/g, '\\n')
                   .replace(/[\r]/g, '\\r');
      },
      removeWhite: function(e) {
         e.normalize();
         for (var n = e.firstChild; n; ) {
            if (n.nodeType == 3) {  // text node
               if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
                  var nxt = n.nextSibling;
                  e.removeChild(n);
                  n = nxt;
               }
               else
                  n = n.nextSibling;
            }
            else if (n.nodeType == 1) {  // element node
               X.removeWhite(n);
               n = n.nextSibling;
            }
            else                      // any other node
               n = n.nextSibling;
         }
         return e;
      }
   };
   if (xml.nodeType == 9) // document node
      xml = xml.documentElement;
   var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
   return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
}

const testdataurl = 'https://api.data.abs.gov.au/data/ABS,RES_DWELL/3.3GBRI.Q';
    
async function getData() {
  const response = await fetch(testdataurl);
  data = await response.text();
  const dom = parseXml(data);
  const myJsonStr = xml2json(dom);
  const fixedJsonStr = myJsonStr.replace(/\nundefined/, "");
  const jsonObj = JSON.parse(fixedJsonStr);
  console.log(jsonObj);
}

getData();
async await
  • 1,967
  • 1
  • 8
  • 19
  • Hey, thanks for your response. Is there a way for me to just call that xml2json library rather than including the whole code in my javascript file? I have tried using `import "xml2json";` but I get an error "cannot use import statement outside a module" – scrape_noob Jul 14 '21 at 07:53
  • There are other resources that better explain how to import script into your html to make it available in your project. Check this out https://stackoverflow.com/questions/51164405/how-to-use-external-javascript-libraries Basically you download the file into your project directory, and include a `` tag Make sure it is before your link to js that uses the script. – async await Jul 14 '21 at 22:23
  • Thanks so much for your help, Tom. The JSON object that's returned here doesn't seem to include any of the relevant information on that XML endpoint. For example: "id="TIME_PERIOD" value="2020-Q2"" which can be found in the XML is nowhere to be found in that JSON object. Am I missing something here? – scrape_noob Jul 16 '21 at 01:44
  • for me the object that is returned has items with `{id: "TIME_PERIOD", value: "2020-Q2"}`. Try taking a look at `itemReturned["message:GenericData"]["message:DataSet"]["generic:Obs"][0]["generic:ObsDimension"]["@id"]`. I would be grateful if you accepted my answer above. – async await Jul 16 '21 at 19:57