无法使用 google 应用程序脚本解析 SOAP XML 响应

unable to parse SOAP XML response using google apps script

我正在使用 google 应用脚本调用 SOAP XML 网络服务,目的是将响应内容插入 google sheet。使请求 returns 具有有效数据值的预期响应但是我在解析响应时遇到困难。下面是我的功能...

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 在项目的其他地方定义,标识目标工作sheet。我收到的错误消息是“异常:范围内的行数必须至少为 1”并突出显示 .setValues() 行。

如果我 Logger.log(response); 我得到一个 XML 结构如下的响应:

<?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>

如果我 Logger.log 在:

我也尝试在 root 声明中将 'scada-response' 换成 'node' 但得到的结果相同。

非常感谢您提供任何帮助以了解我哪里出错了。

我相信你的目标如下。

  • 您想使用 [=93] 从问题的 XML 数据中检索 node-idtrading-datetrading-periodgeneration 的值=] Apps 脚本。
  • 您想将检索到的值放入电子表格。

修改点:

  • 在您的 XML 数据中,
    • scada-responsesoapenv:Body 的 child。
    • nodescada-response的child仁。
    • trading-datenode 的 child。
    • trading-periodtrading-date 的 child。
    • generationtime-stamp 的 child。
  • 在您的脚本中,var entries = []; 是循环中 entries.push(id, new Date(td), tp, mw); 的一维数组。
    • 在这种情况下,我认为需要将id, new Date(td), tp, mwentries的值作为一维数组。

当以上几点反映到你的脚本中,就会变成下面这样。

修改后的脚本:

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);
}

确认上述脚本的脚本:

当您直接从 XML 数据测试上述脚本时,您还可以使用以下示例脚本。在这种情况下,请将其复制并粘贴到脚本编辑器和 运行 函数。

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)
}

注:

  • 请将以上修改后的脚本与 V8 运行时间一起使用。

参考: