Поймать первый и последний <li>внутри переменной php - PullRequest
0 голосов
/ 18 октября 2010
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 ]

37 голосов
/ 18 октября 2010

Решение 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 );
9 голосов
/ 18 октября 2010

В качестве альтернативы, вы можете использовать «#menu li:last-child» в вашем CSS вместо имени класса, чтобы вам не нужно было изменять ваш PHP-код.

4 голосов
/ 22 октября 2010

Если вы ДОЛЖНЫ использовать для этого регулярное выражение (не совсем рекомендуется). Я думаю, что это должно работать ...

$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 голосов
/ 23 октября 2010

Вы можете использовать счетчики:

<?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 {
}
3 голосов
/ 22 октября 2010

Если вы действительно хотите выполнить эту работу с регулярным выражением, вы можете попробовать:

$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;

Ouput:

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...