Parsing 将具有不同列/行跨度的电子表格转换为HTML表格

Parsing 将具有不同列/行跨度的电子表格转换为HTML表格,parsing,spreadsheet,Parsing,Spreadsheet,背景: 我们的客户将他们的费率保存在xlsx电子表格中,希望能够将其上传到他们的网站并自动填充HTML表格。电子表格中的某些单元格覆盖多行,某些单元格覆盖多列,以填充任何空白,例如: _______________________ |___|___|___|___|___| | | | |___|___|___|___| | | |___|___|___|___| | | |___|___|_______| |___|___|___|___|_______| |__

背景: 我们的客户将他们的费率保存在xlsx电子表格中,希望能够将其上传到他们的网站并自动填充HTML表格。电子表格中的某些单元格覆盖多行,某些单元格覆盖多列,以填充任何空白,例如:

 _______________________
|___|___|___|___|___|   |
|   |   |___|___|___|___|
|   |   |___|___|___|___|
|   |   |___|___|_______|
|___|___|___|___|_______|
|___________________|___|
(仅仅通过计算哪些单元格是空的,可能无法确定列或行的跨度,即使单元格位于空单元格的顶部,也不能安全地假定它将跨越自身和下面的单元格,因为空单元格左侧的单元格可能跨越2列。)

另一个复杂的问题是,费率一直在变化,客户不能被信任坚持使用预先制作的电子表格模板。(我注意到在我用作参考的电子表格中,他们正确设置了边框,但没有在同一边框内合并单元格。)

有没有人遇到过这个问题并想出了解决办法

谢谢


吉尔

好的,我来回答我自己的问题。我发现如何做到这一点的方法是使用getMergeCells()函数。它不是很有效率,也不是很漂亮,但它很有效

以下代码执行以下操作:

  • 首先,我使用getMergeCells()从xlsx文件中收集所有合并的单元格,这些单元格存储为字符串数组,看起来像[“A1:F1”,“H6:H7”]
  • 对于每个单元格,我检查它是否是合并的单元格之一
  • 如果是,则通过将合并的单元格字符串按冒号字符拆分并保留第二个元素来获取结束单元格
  • 然后,确定步骤3中合并的单元格字符串结束坐标与当前单元格坐标之间的不同坐标。如果是第一个坐标,我会增加行跨度。如果是第二个,我会增加colspan
  • 我使用一个for循环,该循环从当前单元格的x或y坐标开始,并不断增加,直到与合并单元格字符串结束坐标相匹配,从而增加一个变量,该变量稍后在从电子表格输出表示该单元格的表格单元格时使用
  • 这段代码是用Blade编写的,它看起来很像PHP,没有带额外“@”的花括号。。。我认为它更容易阅读。请注意,“$file”变量是在不同的文件中定义的。我不使用phpspredsheet的getHighestColumn()函数,因为这个特殊的电子表格的右侧有很多东西,但是该函数可供任何需要它的人使用

    ...
      
    
     @php
          $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
          $reader->setReadEmptyCells(false);
    
          $spreadsheet = $reader->load($file);
          $table = $spreadsheet->getActiveSheet();
          
          $highestRow = $table->getHighestDataRow(); // e.g. 10
          $columns = ['A', 'B', 'C', 'D', 'E', 'F'];
          $last_col = $columns[sizeof($columns) - 1];
    
          $highestColumn = sizeof($columns);
          // **Step 1**
          $mergeCells = $table->getMergeCells();
    
    
      @endphp
    
      <table>
        @for ($row = 4; $row <= $highestRow; $row++)
          <tr>
            @foreach ($columns as $index => $letter_coordinate)
    
              @php $colspan   = 1;
                   $rowspan   = 1;
                   $cell      = $table->getCell($letter_coordinate . $row);
                   $data      = $cell->getValue();
                   // check is data is excel function (or a numerical value)
                   if (substr($data, 0, 1) == '=' || is_numeric($data)) {
                    $data = number_format((float)$cell->getCalculatedValue() * 100, 2, '.', '') . '%';
                   }
              @endphp
              {{-- **Step 2**: Check if cell is merged --}}
              @foreach ($mergeCells as $cells)
                @if ($cell->isInRange($cells))
                  {{-- **Step 3** --}}
                  @php $limit = explode(":", $cells)[1] @endphp
                  {{-- **Step 4** --}}
                  @if ($limit[0] != $letter_coordinate) {{-- if letter letter_coordinate doesn't match --}}
                    {{-- **Step 5** --}}
                    @for ($i = $letter_coordinate; $i != $last_col; $i++)
                      @if ($limit == $i . $row )
                        @break
                      @else
                        @php $colspan++ @endphp
                      @endif
                    @endfor
                  @else
                    {{-- Step 5 (alternative)--}}
                    {{-- Find row span --}}
                    @for ($i = $row; $i <= $highestRow; $i++)
                      @if ($limit == $letter_coordinate . $i)
                        @break
                      @else
                        @php $rowspan++ @endphp
                      @endif
                    @endfor
                  @endif
                @endif
              @endforeach
              
              {{-- break to new table if all cells are empty --}}
              @if ($colspan == $highestColumn and $cell == "" and $table_row > 5)
                  </tr>
                </table>
                 <table>
    
              @else {{-- if row has one or more cells --}}
                @unless ($cell == "")
                 
                  <td
                    colspan="{{ $colspan }}" 
                    rowspan="{{ $rowspan }}"
                  >{{ $data }}
                  </td>
                @endunless
              @endif
            @endforeach
          </tr>
        @endfor
      </table>
    
    。。。
    @php
    $reader=new\PhpOffice\PhpSpreadsheet\reader\Xlsx();
    $reader->setReadEmptyCells(false);
    $spreadsheet=$reader->load($file);
    $table=$spreadsheet->getActiveSheet();
    $highestRow=$table->getHighestDataRow();//e、 g.10
    $columns=['A','B','C','D','E','F'];
    $last_col=$columns[sizeof($columns)-1];
    $highestColumn=sizeof($columns);
    //**第1步**
    $mergeCells=$table->getMergeCells();
    @endphp
    @对于($row=4;$row$letter\u坐标)
    @php$colspan=1;
    $rowspan=1;
    $cell=$table->getCell($letter\u坐标.$row);
    $data=$cell->getValue();
    //检查数据是否为excel函数(或数值)
    如果(substr($data,0,1)='='| |是数字($data)){
    $data=number_格式((float)$cell->getCalculatedValue()*100,2'.'',''.'');
    }
    @endphp
    {{--**步骤2**:检查单元格是否合并--}
    @foreach($mergeCells作为$cells)
    @如果($cell->isInRange($cells))
    {{--**步骤3**--}
    @php$limit=explode(“:”,$cells)[1]@endphp
    {{--**步骤4**--}
    @if($limit[0]!=$letter\u坐标){{--if letter\u坐标不匹配--}
    {{--**步骤5**--}
    @对于($i=$letter\u坐标;$i!=$last\u col;$i++)
    @如果($limit==$i.$row)
    @中断
    @否则
    @php$colspan++@endphp
    @恩迪夫
    @结束
    @否则
    {{--第5步(备选方案)--}
    {{--Find row span--}
    @对于($i=$row;$i 5)
    @else{--如果行有一个或多个单元格--}
    @除非($cell==“”)
    {{$data}}
    @结束语
    @恩迪夫
    @endforeach
    @结束