google apps 脚本:将 .xls (XHTML) 转换为 gsheet 电子表格

问题描述 投票:0回答:1

我需要做什么

我每个月都有第三方向我提供的 .xls 文件,其中包含 2 个表,我需要使用 google apps scrips 以编程方式从第二个表中检索数据,以便我可以将其记录到另一张表中以进行进一步操作。

问题

.xls 文件,当使用 Drive API 转换为 gsheet 时,因此我可以查看内容以选择我需要的内容,其内容不是预期的电子表格格式,而是此文本 TBODY > TR > TD 格式(我认为它是 XHTML)

我知道我可以打开文件并将其另存为 xlsx 文件,这应该以预期的方式获得正确的 excel 到 gsheet 转换,但如果可以的话我宁愿不这样做

我知道我可以解析文件并通过查看...之间的内容来获取数据,但如果可以的话,我宁愿使用行数组 [[cell1],[cell2],[cell3]]

我尝试使用 Drive API v2 (Drive.Files.insert) 和 v3 (Drive.Files.create) 将 .xls 文件转换为 gsheet,但两者都返回一个 gsheet,其格式为 TBODY > TR > TD文件内容。

有没有办法通过谷歌应用程序脚本以预期的正常电子表格格式获取gsheet?

提前谢谢您

更新:

我正在处理的数据在 gsheet 上看起来如下例所示。经过进一步检查,我注意到表中有一些表,因此我决定只关注我需要的数据(表内容),因此在下面的示例中,我标记了我需要的数据的开始和结束以及我需要的数据我对这些限制中包含的内容感兴趣,开始和结束应该一致,这意味着它们很可能出现在我要抓取的数据的每个文件中,看起来像这样。 最后,下面的每一行都包含在我的 gsheet A 列的一个单元格中,据我所知,没有任何内容渗透到 B 列

...
<NOBR>Some header</NOBR> -- start of data I need
</B>
</TD>
<TD width="65" align="left">
<B>
<NOBR>Product Description</NOBR>
</B>
</TD>
<TD align="left">
<B>
<NOBR>Domain Name</NOBR>
</B>
</TD>
...
<TR>
<TD align="left">01-Jan-2024 </TD>
<TD align="left">id1</TD>
<TD align="left">brand1</TD>
<TD align="left">product1</TD>
<TD align="left">abc.com</TD>
<TD align="left">tld1</TD>
<TD align="left">1</TD>
<TD align="right">value1 currencyX</TD>
</TR>
....
<TR>
<TD align="left">01-Jan-2024 </TD>
<TD align="left">id204</TD>
<TD align="left">brand67</TD>
<TD align="left">product99</TD>
<TD align="left">xyz.tld2</TD>
<TD align="left">tld2</TD>
<TD align="left">1</TD>
<TD align="right">value2 currency3</TD>
</TR>
...
TOTAL (Qtys: xxx) --end of the data I need
...
google-apps-script xhtml xls
1个回答
0
投票

所以这就是我的想法, 也许可以从中衍生出更通用的解决方案,例如如果有人感兴趣的多个表,则捕获表数组。

这个解决方案更像是我想出的一种解决方法,因为它将返回一个二维数组,可用于填充 gsheet 中的表格(该部分不包括在此处),有效地将 xhtml 转换为类似表格的结构,并不完美但适合我的需要。希望它对某人有帮助

function parseXhtmlTable(ssid) {
  
  //get the data from the sheet as is
  var tableData = SpreadsheetApp.openById(ssid).getSheets()[0].getDataRange().getValues();

  // Initialize 2D arrays to store parsed data  
  var rows = [];
  var row = [];

  // Flag if we're capturing data and if we're within a row
  let captureData = false;
  let inRow = false;
  
  //set the cell patterns so capture cell content
  var cellPattern = /<TD.*>(.*)<\/TD>/

  // Iterate through each row (table data)
  for (var i = 0; i<tableData.length; i++) {

    // Get the string from the current row
    var rowString = tableData[i][0].toString();
    //console.log(rowString)

    //should we start capturing data
    if(rowString.includes('<NOBR>Some Header</NOBR>')){
      //console.log(i)
      captureData = true;
      continue;
    }

    //should we stop capturing data and break out
    if(rowString.includes('TOTAL (')){
      //console.log(i)
      captureData = false
      break;
    }

    //as long as we're capturing data
    if(captureData){
      
      // flag Start of row end if the corresponding value is found
      if (rowString.includes('<TR>')) {
        inRow = true;
      }
      
      //flag end of row if the corresponding value is found
      if (rowString.includes('</TR>')) {
        
        //not longer within a row
        inRow = false;
        
        //if row is not empty push that to rows array
        if (row != []){
          rows.push(row);
        }
        
        //reinitialize row variable
        row = []; 
      }

      // if in row, and row matches a cell with a distinct pattern
      if (inRow && cellPattern.test(rowString)) {
        
        //get the cell value
        let cellContent = rowString.match(cellPattern)[1]
        
        //and push value to a row
        row.push(cellContent)
      }
    }
  }
© www.soinside.com 2019 - 2024. All rights reserved.