HTML表到数组PHP

我有一个在线学校日历,但我希望在我自己的应用程序中.
不幸的是我无法使用PHP和正则表达式.

问题是表格单元格不是平均分割的,而是每个类别都有变化.
您可以找到时间表herehere.

我试过的正则表达式是这样的:

<td rowspan='(?:[0-9]{1,3})' class='value'>(.+?)<br/>(.+?)<br/>(.+?)<br/><br/><br/></td>

但它无法正常工作!

结束数组必须如下所示:

[0] => Array
    (
        [0] => maandag //the day
        [1] => 1 //lesson period
        [2] => MEN, 16, dm //content of the cell
    )

我希望这个问题很清楚,因为我不是英国人;)

解决方法:

祝你好运,它会变得棘手……只是’使用HTML解析器’实际上并没有避免主要问题,这是使用rowpans的表的本质.尽管使用HTML Parser解析大量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一个rowspan的位置,你必须在下面的行(在正确的位置)创建该单元格信息的副本,以便实际创建一个完整的表格结构(没有rowpans).

/// 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>';

相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...