2

I'm a beginner in coding and I'm trying to parse an XML file, hosted on GitHub, using JavaScript, to extract, for instance, the information contained in the <author> node nested in the <book id="bk102"> node.

I'm aware there are several similar questions in Stackoverflow, I read many of them but what I am trying to do is to extract data from the above-mentioned XML file, using only built-in JavaScript functions.

Honestly, I don't know if it is even possible but I'll explain a bit more in details what I tried to do in order to give you the whole picture.

Why I can use only JS built-in functions?

I'm developing a dynamic survey form using a data collection platform called Fulcrum.

Fulcrum allows to write JavaScript code (with some custom functions) in its 'Data events' module in order to interact with the fields and calculations contained in the survey form itself.

The 'Data events' module in Fulcrum doesn't allow me to install additional packages. For this reason, I cannot install, for example, xml-js library, as suggested here, to use the built-in JavaScript JSON functions or I cannot use DOMParser() interface, among others, since Fulcrum wouldn't recognize it.

From where I started?

Reading Fulcrum documentation, I found out I can use a custom function called REQUEST and I referred to the following example. The Fulcrum custom functions are identified with CAPITAL LETTERS.

// This example looks up the place name from OpenStreetMap when the location changes and fills in a text
// field with the place name. Replace 'place_name' below with a text field on your form.

ON('change-geometry', function(event) {
  var options = {
    url: 'https://nominatim.openstreetmap.org/search/' + LATITUDE() + ',' + LONGITUDE(),
    qs: {
      format: 'json',
      polygon: 1,
      addressdetails: 1
    }
  };

  REQUEST(options, function(error, response, body) {
    if (error) {
      ALERT('Error with request: ' + INSPECT(error));
    } else {
      var data = JSON.parse(body);
      if (data.length) {
        SETVALUE('place_name', data[0].display_name);
      }
    }
  });
});

The only issue here is that this example reads form a JSON file, while I need to read from a XML file.

What I tried?

I tried to edit the function in the example to make it work with an XML file. This is how I modified it.

ON('click', 'import_xml', function(event) {
  var options = {
    url: 'https://gist.githubusercontent.com/Ram-N/5189462/raw/46db0b43ad7bf9cbd32a8932f3ab981bd4b4da7c/books.xml',
    qs: {
      format: 'xml'
    }
  };

  REQUEST(options, function(error, response, body) {
    if (error) {
      ALERT('Error with request: ' + INSPECT(error));
    } else {
      var data = body;
      if (data.length) {
        SETVALUE('test_field_xml', data);
      }
    }
  });
});

And it works! Partially... When I click the import_xml hyperlink (refer to 1 below), I'm able to import the whole body of the XML file in the test_field_xml field (refer to 2 below) but I dont' really know how to extract only the information contained in the <author> node nested in the <book id="bk102"> node.

enter image description here

Any advice on how to proceed would be extremely helpful. Thank you, Stefano.


EDIT1:

I think I found a very "homemade" and partial solution, also not very practical or nice but it works. I edited the code above as shown below:

ON('click', 'import_xml', function(event) {
  var options = {
    url: 'https://gist.githubusercontent.com/Ram-N/5189462/raw/46db0b43ad7bf9cbd32a8932f3ab981bd4b4da7c/books.xml',
    qs: {
      format: 'xml'
    }
  };

  REQUEST(options, function(error, response, body) {
    if (error) {
      ALERT('Error with request: ' + INSPECT(error));
    } else {
      var data = body;
      var test1 = body.substring(
            body.lastIndexOf('<book id="bk102">') + 24, 
            body.lastIndexOf('<book id="bk103">') - 15
        );
      var test2 = test1.substring(
            test1.lastIndexOf('<author>') + 8, 
            test1.lastIndexOf('</author>') - 0
        );     
      if (data.length) {
        SETVALUE('test_field_xml', test2);
      }
    }
  });
});

In your opinion, could this be done in a better and more efficient way?

aragornii
  • 331
  • 4
  • 17
  • 1
    You really don't want to "hand parse" the XML in this way. For example, your code will fail if there is different whitespace in the book element, or if there's another attribute before the "id" attribute, or if the attribute is in single quotes rather than double quotes. It might work today, but it probably won't work next year. – Michael Kay Jul 23 '19 at 08:24

1 Answers1

1

You have said you are allowed to write Javascript code, but that you can't install additional Javascript packages. So the answer is to download an open-source XML parser written in Javascript and add it to your code as if it was part of the code you had written yourself.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks @Michael Kay for the suggestion, I'm really a beginner though, could you please provide some more details on how to do that? Do you have any suggestion on an open-source XML parser written in Javascript? – aragornii Jul 23 '19 at 17:17
  • I can't do more than point you in the right direction, I'm not going to lead you all the way to your destination. We use a parser derived from github/isaacs/sax-js, but there are quite a few others that have appeared over the last couple of years and I don't know if we would make the same choice today. – Michael Kay Jul 23 '19 at 17:26
  • Ok, thank you, I understand. Honestly, I haven't found yet a way to accomplish what I'm trying to do. Looking at XML parser written in JS, I see they are structured in different folders and I don't know how to "install" them since Fulcrum allows me only to write code on a blank page and when I paste the code I found [here](https://github.com/matteodelabre/saxophone/blob/master/lib/Saxophone.js), for instance, I get a lot of errors. [This](https://stackoverflow.com/a/649928/9034503) is something close to what I am allowed to do in Fulcrum but I can't make it work unfortunately. – aragornii Jul 23 '19 at 18:42
  • I don't know Fulcrum but either there must be an easy way of doing this, or it falls a million miles short of its claim to "make mobile data collection simple". But I'm always wary of any product that claims "no coding required". That usually means you can only do the things the product vendor wants you to do, not the things you want to do. – Michael Kay Jul 23 '19 at 20:07
  • Maybe I'm missing something, I'm a civil engineer not a developer so it is likely. I will make some additional research and I'll update the question here if I have any news. Thank you very much for your advice. – aragornii Jul 23 '19 at 20:13