抓住php变量中的第一个和最后一个<li> </li>

时间:2010-10-18 10:52:40

标签: php html regex parsing dom

echo $ul; // gives this code:

<ul id="menu">
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class">...</li>
</ul>

如何为第一个和最后一个<li>添加一些课程?

需要正则表达式解决方案

echo $ul;应该给出(如果我们为最后一个my_class添加了课程<li>):

<ul id="menu">
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class my_class">...</li>
</ul>

5 个答案:

答案 0 :(得分:37)

DOM解决方案

$dom = new DOMDocument;
$dom->loadHTML( $ul );
$xPath = new DOMXPath( $dom );
$xPath->query( '/html/body/ul/li[last()]/@class' )
      ->item( 0 )
      ->value .= ' myClass';

echo $dom->saveXml( $dom->getElementById( 'menu' ) );

如果您知道HTML有效,您也可以使用loadXML。这将使DOM不再添加HTML骨架。请注意,您必须将XPath更改为'/ul/li[last()]/@class'

如果您不熟悉XPath查询,还可以使用常规DOM接口,例如

$dom = new DOMDocument;
$dom->loadHTML( $ul );
$liElements = $dom->getElementsByTagName( 'li' );
$lastLi  = $liElements->item( $liElements->length-1 );
$classes = $lastLi->getAttribute( 'class' ) . ' myClass';
$lastLi->setAttribute( 'class',  $classes );
echo $dom->saveXml( $dom->getElementById( 'menu' ) );

编辑由于您已将问题更改为第一个和最后一个类,因此以下是使用XPath执行此操作的方法。这假设您的标记是有效的XHTML。如果没有,请切换回loadHTML(请参阅上面的代码):

$dom = new DOMDocument;
$dom->loadXML( $html );
$xpath = new DOMXPath( $dom );
$first = $xpath->query( '/ul/li[1]/@class' )->item( 0 );
$last = $xpath->query( '/ul/li[last()]/@class' )->item( 0 );
$last->value .= ' last';
$first->value .= ' first';
echo $dom->saveXML( $dom->documentElement );

答案 1 :(得分:9)

或者,您可以在CSS中使用“#menu li:last-child”而不是类名,这样您就不必修改PHP代码。

答案 2 :(得分:4)

如果您必须为此使用正则表达式(不完全是建议)。 我认为这应该有用......

$replacement1 = "<li\s.*?class="(.*?)".*?>.*?</li>\s</ul>";
$string1 = "$1 class_last";
$ul = preg_replace($ul, $replacement1, $string1);)

$replacement2 = "<ul.*?>\s<li\s.*?class="(.*?)".*?>";
$string2 = "$1 class_first";
$ul = preg_replace($ul, $replacement2, $string2);)

答案 3 :(得分:3)

如果你真的想用正则表达式做这个工作,你可以尝试:

$ul = '
<ul id="menu">
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class">...</li>
</ul>
';

// explode input string to an array
$lines = explode("\n", $ul);

$found_first = 0;   // is the first li founded
$found_last  = 0;   // index of the last li
$class_first = "class_first"; // class for the first li
$class_last  = "class_last";  // class for the last li

// loop on all lines
for ($i = 0; $i < count($lines); $i++) {
  $line = $lines[$i];

  // the line begins with <li
  if (preg_match("/^<li/", $line)) {

    // is it the first one
    if (!$found_first) {
      // add the class
      $lines[$i] = preg_replace('/ class="([^"]+?)"/', " class=\"$1 $class_first\"", $lines[$i]);
      // the first li have been found
      $found_first = 1;
    }
    // memo the last line proceded
    $found_last = $i;
  }
}

// this will add class_last even if the last li
// is also the first one (ie: only one li)
if ($found_last) {
  $lines[$found_last] = preg_replace('/ class="([^"]+?)"/', " class=\"$1 $class_last\"", $lines[$found_last]);
}

$ul = implode("\n", $lines);

echo $ul;

输出继电器:

<ul id="menu">
<li id="some_id" class="some_class class_first">...</li>
<li id="some_id" class="some_class">...</li>
<li id="some_id" class="some_class class_last">...</li>
</ul>

答案 4 :(得分:3)

您可以使用计数器:

<?php
$list = array('aaa', 'bbb', 'ccc', 'ddd');
$items = count($list); // count items in list
$i = 1; // set counter to one, because first item in list will be item number: 1

echo '<ul>';

// create loop
foreach($list as $value) {

  // first item
  if($i == 1) {
    $class = 'some_class first_class';

  // last item
  } elseif ($i == $items) {
    $class = 'some_class last_class';

  // not first / not last item
  } else {
    $class = 'some_class';
  }

  echo '<li id="some_id" class="'.  $class .'">' . $value . '</li>';
  $i++; // raise $i by one
}

echo '</ul>';
?>

将输出:

<ul>
<li id="some_id" class="some_class first_class">aaa</li>
<li id="some_id" class="some_class">bbb</li>
<li id="some_id" class="some_class">ccc</li>
<li id="some_id" class="some_class last_class">ddd</li>
</ul>

但是,我的建议是:

<ul id="menu">
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
  <li>ddd</li>
</ul>

在你的CSS中:

#menu {
}

#menu li:first-child {
}

#menu li {
}

#menu li:last-child {
}