これで頑張ってください、それはトリッキーになるでしょう...「HTMLパーサーを使用する」だけでは、行スパンを使用するテーブルの性質である大きな問題を実際に回避することはできません。大量のHTMLを解析するためにHTMLパーサーを使用することは常に良いアドバイスですが、そのHTMLをより小さく、信頼できるチャンクに分割できる場合は、他の手法を使用した解析が常により最適になります(ただし、明らかにより傾向があります) HTMLの微妙な予期しない違い)。
テーブルを正規化する
私の場合は、テーブルの開始位置と終了位置を検出できるものから始めます(必要がなければ、HTMLパーサーを使用している場合でもページ全体を解析したくないため):
$table = $start = $end = false;
/// 'Vrijdag' should be unique enough, but will fail if it appears elsewhere
$pos = strpos($html, 'Vrijdag');
/// find your start and end based on reliable tags
if ( $pos !== false ) {
$start = stripos($html, '<tr>', $pos);
if ( $start !== false ) {
$end = stripos($html, '</table>', $start);
}
}
if ( $start !== false && $end !== false ) {
/// we can now grab our table $html;
$table = substr($html, $start, $end - $start);
}
次に、セルが垂直方向にまたがる無計画な方法のために(ただし、水平方向に均一に見える)、「日」列を選択して下向きに作業します。
if ( $table ) {
/// break apart based on rows
$rows = preg_split('#</tr>#i', $table);
///
foreach ( $rows as $key => $row ) {
$rows[$key] = preg_split('#</td>#i', $row);
}
}
上記はあなたに次のようなものを与えるはずです:
array (
'0' => array (
'0' => "<td class='heading'>1",
'1' => "<td rowspan='1' class='empty'>"
'2' => "<td rowspan='5' class='value'>3D<br/>009<br/>Hk<br/><br/><br/>"
...
),
'0' => array (
'0' => "<td class='heading'>2",
'1' => "<td rowspan='2' class='empty'>"
'2' => "<td rowspan='3' class='value'>Hk<br/>"
...
),
)
これで、各行をスキャンできます。行スパンをpreg_matchすると、実際に完全なテーブルを作成するために、そのセルの情報のコピーを下の行(適切な場所)に作成する必要があります。構造(行スパンなし)。
/// can't use foreach here because we want to modify the array within the loop
$lof = count($rows);
for ( $rkey=0; $rkey<$lof; $rkey++ ) {
/// pull out the row
$row = $rows[$rkey];
foreach ( $row as $ckey => $cell ) {
if ( preg_match('/ rowspan=.([0-9]+)./', $cell, $regs) ) {
$rowspan = (int) $regs[1];
if ( $rowspan > 1 ) {
/// there was a gotcha here, I realised afterwards i was constructing
/// a replacement pattern that looked like this '$14$2'. Which meant
/// the system tried to find a group at offset 14. To get around this
/// problem, PHP allows the group reference numbers to be wraped with {}.
/// so we now get the value of '$1' and '$2' inserted around a literal number
$newcell = preg_replace('/( rowspan=.)[0-9]+(.)/', '${1}'.($rowspan-1).'${2}', $cell);
array_splice( $rows[$rkey+1], $ckey, $newcell );
}
}
}
}
上記は、行スパンが問題にならないようにテーブルを正規化する必要があります。
(上記は理論上のコードであることに注意してください。手動で入力しましたが、まだテストしていません。これはまもなく実行します)
テスト後
私が更新した上記のいくつかの小さなバグがありました。つまり、特定の関数のphpの引数を間違った方法で取得します...それらをソートした後、それは機能するようです:
/// grab the html
$html = file_get_contents('http://www.cibap.nl/beheer/modules/roosters/create_rooster.php?element=CR13A&soort=klas&week=37&jaar=2012');
/// start with nothing
$table = $start = $end = false;
/// 'Vrijdag' should be unique enough, but will fail if it appears elsewhere
$pos = strpos($html, 'Vrijdag');
/// find your start and end based on reliable tags
if ( $pos !== false ) {
$start = stripos($html, '<tr>', $pos);
if ( $start !== false ) {
$end = stripos($html, '</table>', $start);
}
}
/// make sure we have a start and end
if ( $start !== false && $end !== false ) {
/// we can now grab our table $html;
$table = substr($html, $start, $end - $start);
/// convert brs to something that wont be removed by strip_tags
$table = preg_replace('#<br ?/>#i', "\n", $table);
}
if ( $table ) {
/// break apart based on rows (a close tr is quite reliable to find)
$rows = preg_split('#</tr>#i', $table);
/// break apart the cells (a close td is quite reliable to find)
foreach ( $rows as $key => $row ) {
$rows[$key] = preg_split('#</td>#i', $row);
}
}
else {
/// create so we avoid errors
$rows = array();
}
/// changed this here from a foreach to a for because it seems
/// foreach was working from a copy of $rows and so any modifications
/// we made to $rows while the loop was happening were ignored.
$lof = count($rows);
for ( $rkey=0; $rkey<$lof; $rkey++ ) {
/// pull out the row
$row = $rows[$rkey];
/// step each cell in the row
foreach ( $row as $ckey => $cell ) {
/// pull out our rowspan value
if ( preg_match('/ rowspan=.([0-9]+)./', $cell, $regs) ) {
/// if rowspan is greater than one (i.e. spread across multirows)
$rowspan = (int) $regs[1];
if ( $rowspan > 1 ) {
/// then copy this cell into the next row down, but decrease it's rowspan
/// so that when we find it in the next row we know how many more times
/// it should span down.
$newcell = preg_replace('/( rowspan=.)([0-9]+)(.)/', '${1}'.($rowspan-1).'${3}', $cell);
array_splice( $rows[$rkey+1], $ckey, 0, $newcell );
}
}
}
}
/// now finally step the normalised table and get rid of the unwanted tags
/// that remain at the same time split our values in to something more useful
foreach ( $rows as $rkey => $row ) {
foreach ( $row as $ckey => $cell ) {
$rows[$rkey][$ckey] = preg_split('/\n+/',trim(strip_tags( $cell )));
}
}
echo '<xmp>';
print_r($rows);
echo '</xmp>';