1

i'm using google apps script to call a SOAP XML web service with the intent on inserting the response content into a google sheet. making the request returns the expected response with valid data values however i'm having difficulty parsing the response. below is my function...

function testFetch() {
  var response = UrlFetchApp.fetch(setScadaHost(), setOptions());
  var doc = XmlService.parse(response.getContentText());
  var ns = XmlService.getNamespace(setNsScada());
  var root = doc.getRootElement().getChild('scada-response', ns);
  var entries = [];
  for(var i in root) {
    var id = root[i].getAttribute('node-id').getValue();
    var td = root[i].getAttribute('trading-date').getValue();
    var tp = root[i].getAttribute('trading-period').getValue();
    var mw = root[i].getAttribute('generation').getValue();
    entries.push(id, new Date(td), tp, mw);
  }
  shtSoap.getRange(shtSoap.getLastRow()+1,1,entries.length, 4).setValues(entries);
}

shtSoap is defined elsewhere in the project, identifying the destination worksheet. the error message i get back is "Exception: The number of rows in the range must be at least 1" and highlights the .setValues() row.

if i Logger.log(response); i get an XML response structured like so:

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <scada-response response-type="Scada Service" xmlns="[domainhost]/response/scada">
            <node node-id="1st node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>1000</generation></time-stamp></trading-period></trading-date></node>
            <node node-id="2nd node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>1200</generation></time-stamp></trading-period></trading-date></node>
            <node node-id="3rd node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>1200</generation></time-stamp></trading-period></trading-date></node>
            <node node-id="4th node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>800</generation></time-stamp></trading-period></trading-date></node>
        </scada-response>
    </soapenv:Body>
</soapenv:Envelope>

if i Logger.log on:

  • (entries) after the for loop, i get an empty array.
  • (doc) after the doc declaration, i get the following error "Document: No DOCTYPE declaration, Root is [Element: <soapenv:Envelope [Namespace: http://schemas.xmlsoap.org/soap/envelope/]/>]"

i have also tried swapping out 'scada-response' for 'node' in the root declaration but get the same results.

any help you can offer to understand where i'm going wrong is greatly appreciated.

1 Answer 1

3

I believe your goal as follows.

  • You want to retrieve the values of node-id, trading-date, trading-period and generation from the XML data in your question using Google Apps Script.
  • You want to put the retrieved values to the Spreadsheet.

Modification points:

  • In your XML data,
    • scada-response is the child of soapenv:Body.
    • node is the children of scada-response.
    • trading-date is the child of node.
    • trading-period is the child of trading-date.
    • generation is the child of time-stamp.
  • In your script, var entries = []; is the 1 dimensional array by entries.push(id, new Date(td), tp, mw); in the loop.
    • In this case, I think that it is required to put the values of id, new Date(td), tp, mw to entries as one dimensional array.

When above points are reflected to your script, it becomes as follows.

Modified script:

function testFetch() {
  var response = UrlFetchApp.fetch(setScadaHost(), setOptions());
  var doc = XmlService.parse(response.getContentText());
  
  // --- I modified below script.
  var ns1 = XmlService.getNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
  var ns2 = XmlService.getNamespace('[domainhost]/response/scada');
  var nodeIds = doc.getRootElement().getChild('Body', ns1).getChild('scada-response', ns2).getChildren();
  var entries = nodeIds.map(c => {
    var tradingDate = c.getChild('trading-date', ns2);
    var tradingPeriod = tradingDate.getChild('trading-period', ns2);
    var id = c.getAttribute('node-id').getValue();
    var td = tradingDate.getAttribute('value').getValue();
    var tp = tradingPeriod.getAttribute('value').getValue();
    var mw = tradingPeriod.getChild('time-stamp', ns2).getChild('generation', ns2).getValue();
    return [id, new Date(td), tp, mw];
  });
  // ---
  
  shtSoap.getRange(shtSoap.getLastRow()+1,1,entries.length, 4).setValues(entries);
}

Script for confirmation of above script:

When you directly test above script from your XML data, you can also use the following sample script. In this case, please copy and paste it to the script editor and run the function.

function myFunction() {
  var response = `<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <scada-response response-type="Scada Service" xmlns="[domainhost]/response/scada">
            <node node-id="1st node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>1000</generation></time-stamp></trading-period></trading-date></node>
            <node node-id="2nd node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>1200</generation></time-stamp></trading-period></trading-date></node>
            <node node-id="3rd node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>1200</generation></time-stamp></trading-period></trading-date></node>
            <node node-id="4th node"><trading-date value="2020-09-21"><trading-period value="32"><time-stamp value="16:21:00.000Z"><generation>800</generation></time-stamp></trading-period></trading-date></node>
        </scada-response>
    </soapenv:Body>
</soapenv:Envelope>`;
  var doc = XmlService.parse(response);
  var ns1 = XmlService.getNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
  var ns2 = XmlService.getNamespace('[domainhost]/response/scada');
  var nodeIds = doc.getRootElement().getChild('Body', ns1).getChild('scada-response', ns2).getChildren();
  var entries = nodeIds.map(c => {
    var tradingDate = c.getChild('trading-date', ns2);
    var tradingPeriod = tradingDate.getChild('trading-period', ns2);
    var id = c.getAttribute('node-id').getValue();
    var td = tradingDate.getAttribute('value').getValue();
    var tp = tradingPeriod.getAttribute('value').getValue();
    var mw = tradingPeriod.getChild('time-stamp', ns2).getChild('generation', ns2).getValue();
    return [id, new Date(td), tp, mw];
  });
  console.log(entries)
}

Note:

  • Please use above modified script with V8 runtime.

Reference:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.