Поймать первую и последнюю <li> внутреннюю переменную php

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> 

Решение 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' ) ); 

EDIT. Поскольку вы изменили вопрос на наличие классов для первого и последнего сейчас, вот как это сделать с помощью 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 ); 

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

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

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

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

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

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

 <?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 { }