如何用Google Apps Script提取日志XML并导入Google Sheets
嘿,我来帮你搞定这个XML提取和导入Google Sheets的问题!你已经完成了导入TXT文件的基础工作,接下来只需要三步就能实现需求:识别XML行、解析XML、写入表格,我给你详细的代码和说明:
1. 识别日志中的XML行
你的日志里,XML响应行都包含<S:Envelope>和</S:Envelope>标签,我们可以用正则表达式精准匹配这些行。在你现有的代码中,遍历拆分后的日志行时,加入匹配逻辑:
lines.forEach(function(line) { // 匹配包含完整SOAP Envelope的行,/s修饰符允许.匹配换行(兼容可能跨多行的XML) const xmlMatch = line.match(/<S:Envelope[\s\S]*?<\/S:Envelope>/); if (xmlMatch) { const xmlString = xmlMatch[0]; // 接下来解析这个XML字符串 } });
2. 用XmlService解析XML
Google Apps Script的XmlService是处理XML的官方工具,核心要注意命名空间的注册(你的XML里有xmlns:S="http://schemas..."的命名空间,必须准确对应)。我写了一个通用的解析函数,你可以根据实际XML结构修改:
function parseSoapXml(xmlString, logLine) { try { // 解析XML字符串为文档对象 const xmlDoc = XmlService.parse(xmlString); const rootElement = xmlDoc.getRootElement(); // 注册XML里的命名空间(替换成你日志里实际的URL!) const soapNs = XmlService.getNamespace("S", "http://schemas.xmlsoap.org/soap/envelope/"); // 提取日志里的时间戳(从原始日志行拆分) const timestampParts = logLine.split(' '); const timestamp = `${timestampParts[0]} ${timestampParts[1]}`; // 示例:提取SOAP Body节点 const soapBody = rootElement.getChild("Body", soapNs); // 这里根据你的XML结构提取具体字段,比如Body里的响应内容 // 如果你需要提取特定子节点,比如<YourResponse>,要注册对应的命名空间 // const customNs = XmlService.getNamespace("ns1", "http://your-service-url.com"); // const responseContent = soapBody.getChild("YourResponse", customNs)?.getText() || "无内容"; // 暂时用Body的原始XML作为示例,你可以替换成实际需要的字段 const responseContent = soapBody ? XmlService.getRawXml(soapBody) : "无法解析Body"; // 返回整理好的数据对象 return { timestamp: timestamp, response: responseContent }; } catch (error) { // 捕获解析错误,避免脚本崩溃,同时记录日志方便排查 console.error(`解析XML失败:${error.message},片段:${xmlString.substring(0, 100)}...`); return null; } }
3. 将解析后的数据批量写入Google Sheets
为了提高效率,我们先把所有符合条件的数据收集到数组里,再批量写入表格(比逐行写入快很多)。整合到你的Importa函数里:
function Importa() { const folder = DriveApp.getFolderById('abc_xyz'); // 替换成你的文件夹ID const spreadsheet = SpreadsheetApp.openById('abc_xyz'); // 替换成你的表格ID const targetSheet = spreadsheet.getSheetByName("INFO"); const files = folder.getFiles(); // 用来存放要写入表格的数据 const outputData = []; // 如果表格还没有表头,可以先添加: // outputData.push(["时间戳", "XML响应内容"]); while (files.hasNext()) { const file = files.next(); const fileText = file.getAs('text/plain').getDataAsString('ISO-8859-1'); const lines = fileText.split('\n'); lines.forEach(line => { const xmlMatch = line.match(/<S:Envelope[\s\S]*?<\/S:Envelope>/); if (xmlMatch) { const parsedData = parseSoapXml(xmlMatch[0], line); if (parsedData) { // 将数据对象转换成数组,顺序对应表格列 outputData.push([parsedData.timestamp, parsedData.response]); } } }); } // 批量写入表格(从最后一行的下一行开始) if (outputData.length > 0) { const lastRow = targetSheet.getLastRow(); targetSheet.getRange(lastRow + 1, 1, outputData.length, outputData[0].length) .setValues(outputData); } }
关键注意事项
- 命名空间必须准确:
XmlService对命名空间非常严格,一定要把代码里的命名空间URL替换成你日志XML里实际的那个(比如http://schemas.xmlsoap.org/soap/envelope/),否则会找不到节点。 - 处理跨多行XML:如果你的日志里XML是跨多行的,那逐行拆分就会失效,这时候可以直接匹配整个日志文本里的XML块:
const xmlBlocks = fileText.match(/<S:Envelope[\s\S]*?<\/S:Envelope>/g); if (xmlBlocks) { xmlBlocks.forEach(xmlString => { // 这里需要找到对应XML块的时间戳,比如找这个块之前最近的日志时间行 const timestampMatch = fileText.substring(0, fileText.indexOf(xmlString)) .match(/(\d{8} \d{6})/g)?.pop(); if (timestampMatch) { const parsedData = parseSoapXml(xmlString, timestampMatch); // 后续处理... } }); } - 错误处理:代码里的
try-catch能避免格式错误的XML导致脚本崩溃,同时控制台日志能帮你定位问题。
内容的提问来源于stack exchange,提问作者Sérgio Sá
相关产品推荐
相关产品推荐

