首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 將 HTML 表格轉為多維陣列:DOMDocument 解析、合併儲存格支援、資料清洗

     編輯:PHP 綜合知識

核心解析函式 (支援 rowspan/colspan)

<?php
/**
 * 將 HTML  轉為二維陣列
 * 正確處理 rowspan、colspan、thead/tbody/tfoot、嵌套表格
 * 
 * @param string $html HTML 字串或包含 
的片段 * @param int $tableIndex 第幾個 table (0-based) * @return array [ ['header'=>[], 'rows'=>[[]]] ] */ function htmlTableToArray(string $html, int $tableIndex = 0): array { libxml_use_internal_errors(true); $dom = new DOMDocument(); $dom->loadHTML('' . $html); libxml_clear_errors(); $tables = $dom->getElementsByTagName('table'); if ($tables->length <= $tableIndex) return []; $table = $tables->item($tableIndex); $rows = $table->getElementsByTagName('tr'); $grid = []; // 虛擬網格,儲存 [row][col] = cellData $maxCols = 0; foreach ($rows as $rowIdx => $tr) { $cells = $tr->getElementsByTagName('td'); if ($cells->length === 0) { $cells = $tr->getElementsByTagName('th'); // thead 可能用 th } $colIdx = 0; foreach ($cells as $cell) { // 找下一個可用欄位 (跳過被 rowspan/colspan 佔用的) while (isset($grid[$rowIdx][$colIdx])) $colIdx++; $rowspan = (int)$cell->getAttribute('rowspan'); $colspan = (int)$cell->getAttribute('colspan'); $rowspan = $rowspan > 0 ? $rowspan : 1; $colspan = $colspan > 0 ? $colspan : 1; $text = trim($cell->textContent); // 可選:保留 HTML // $htmlContent = $dom->saveHTML($cell); // 填入虛擬網格 for ($r = 0; $r < $rowspan; $r++) { for ($c = 0; $c < $colspan; $c++) { $grid[$rowIdx + $r][$colIdx + $c] = [ 'text' => $text, 'is_merged' => ($r > 0 || $c > 0), 'rowspan' => $rowspan, 'colspan' => $colspan, ]; } } $colIdx += $colspan; $maxCols = max($maxCols, $colIdx); } } // 將網格轉為陣列 (補齊缺失欄位) $result = []; for ($r = 0; $r < count($grid); $r++) { $row = []; for ($c = 0; $c < $maxCols; $c++) { $row[] = $grid[$r][$c]['text'] ?? ''; } $result[] = $row; } // 分離表頭 (假設第一行或 thead) $header = array_shift($result); return ['header' => $header, 'rows' => $result]; } // 使用 $html = file_get_contents('https://example.com/report.html'); $tableData = htmlTableToArray($html); print_r($tableData['header']); print_r($tableData['rows']);

進階:直接對應關聯陣列 (以表頭為鍵)

function tableToAssocArray(string $html, int $tableIndex = 0): array
{
    $data = htmlTableToArray($html, $tableIndex);
    $header = $data['header'];
    $rows = $data['rows'];

    $assoc = [];
    foreach ($rows as $row) {
        // 若欄位數不足,補空值
        $row = array_pad($row, count($header), '');
        $assoc[] = array_combine($header, $row);
    }
    return $assoc;
}

/*
輸出範例:
[
    ['姓名' => '張三', '年齡' => '25', '城市' => '台北'],
    ['姓名' => '李四', '年齡' => '30', '城市' => '台中'],
]
*/

資料清洗與型別轉換

function cleanTableData(array $assocData, array $typeMap = []): array
{
    return array_map(function ($row) use ($typeMap) {
        foreach ($row as $key => $value) {
            $type = $typeMap[$key] ?? 'string';
            $row[$key] = match ($type) {
                'int' => (int)filter_var($value, FILTER_SANITIZE_NUMBER_INT),
                'float' => (float)filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION),
                'date' => \DateTime::createFromFormat('Y/m/d', $value)?->format('Y-m-d') ?? $value,
                'bool' => in_array(strtolower($value), ['true', '1', 'yes', '是', 'y']),
                default => trim($value),
            };
        }
        return $row;
    }, $assocData);
}

// 使用
$clean = cleanTableData($assocData, [
    '年齡' => 'int',
    '薪資' => 'float',
    '入職日期' => 'date',
    '是否主管' => 'bool',
]);

大表格串流處理 (記憶體優化)

function parseLargeTableStream(string $filePath, callable $rowCallback): void
{
    // 使用 XMLReader (SAX 模式) 逐行解析,不載入整份文件
    $reader = new XMLReader();
    $reader->open($filePath);
    
    $inTable = $inRow = false;
    $currentRow = [];
    $cellBuffer = '';
    
    while ($reader->read()) {
        if ($reader->nodeType === XMLReader::ELEMENT) {
            if ($reader->name === 'table') $inTable = true;
            if (!$inTable) continue;
            if ($reader->name === 'tr') { $inRow = true; $currentRow = []; }
            if ($inRow && in_array($reader->name, ['td', 'th'])) {
                $cellBuffer = '';
            }
        } elseif ($reader->nodeType === XMLReader::TEXT && $inRow) {
            $cellBuffer .= $reader->value;
        } elseif ($reader->nodeType === XMLReader::END_ELEMENT) {
            if ($inRow && in_array($reader->name, ['td', 'th'])) {
                $currentRow[] = trim($cellBuffer);
            }
            if ($reader->name === 'tr') {
                $inRow = false;
                $rowCallback($currentRow); // 逐行回調處理
            }
            if ($reader->name === 'table') break;
        }
    }
    $reader->close();
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved