tags:

views:

96

answers:

4

We have variable $menu with HTML inside (there is no loop, it comes from a function).

On echo it gives the code like this:

<ul id="menu">
    <li id="some-id" class="many classes"><a title="one" href="#">text</a></li>
    <li id="some-id" class="many classes"><a href="#">text</a></li>
    <li id="some-id" class="many classes"><a title="three" href="#">text</a></li>
</ul>

What I want to do:

  1. get value of the title="" of each link, and move it to the end of parent <li> class.

  2. remove title="" from each link.

Code inside variable $menu should become:

<ul id="menu">
    <li id="some-id" class="many classes one"><a href="#">text</a></li>
    <li id="some-id" class="many classes"><a href="#">text</a></li>
    <li id="some-id" class="many classes three"><a href="#">text</a></li>
</ul>

What is the solution?

+1  A: 

Use this regex:

(<li[^>]*class=".*)("><a).*title="(.*)"(.*)

And replace each match using backreferences:

\1 \3\2\4

Note that this will work for your example, but you might need to modify it and make it "smarter" if you have cases such as:

<li id="some-id >" class="many classes"><a title="one" href="#">text</a></li>
Chetan
This does work, but your RegExp will only work if the `title` attribute is the first one declared inside the `<a...>text</a>` tag
Lucanos
@Lucanos: Thanks, I have updated my answer.
Chetan
+1  A: 

You can use PHP Simple HTML DOM Parser to modify your HTML:

In your case if no of li are fixed in $menu then you do something like this with Simple HTML DOM Parser:

// Include downloaded library
include 'simplehtmldom/simple_html_dom.php';

// Create DOM from string
$html = str_get_html( $menu );


for( $i=0 ; $i<3 ; $i++ ) {

    // Get current classes of li
    $currentClasses = $html->find('li', $i)->class;

    // Get title of link
    $linkTitle = $html->find('a', $i)->title;

    // Add link title in li classes
    $html->find('li', $i)->class = $currentClasses . ' ' . $linkTitle ;

    // Remove title attribute from link
    $html->find('a', $i)->title = null;
}


echo $html;
NAVEED
@downvoter: Any reason for downvote ?
NAVEED
@NAVEED: Someone has been running around downvoting tons of people at random lately. My answers were hit twice by the same kid in a single day. I've voted you all back up to counter the downvotes now.
BoltClock
@BoltClock: Thanks for your recovery.
NAVEED
@Boltclock, how do you know it was the 'same kid'? O.o is this one of the legendary mod-tools?
David Thomas
@David Thomas: Just a guess. It could very well be a conspiracy between three kids instead. Or a flying starfish.
BoltClock
@Boltclock, valid points all. There are days I **curse** those internet-using flying starfishes... =)
David Thomas
@NAVEED: Ah, so that's what happened to my post too. Thanks!
Chetan
+1  A: 

It's not a perfect solution, but it has worked in my testing (Regex Buddy & XAMPP) with your sample code.

$pattern = '/(<li [^>]*)(?:class=(?:"([^"]+)"|\'([^\']+)\'))([^>]*><a[^>]*)(?:title=(?:"([^"]+)"|\'([^\']+)\'))\s([^>]*>)(.*?<\/li>)/im';
$replace = '$1class="$2 $5"$4$7$8';

preg_replace( $pattern , $replace , $menu );
Lucanos
will it work, if there is no title on the link?
Happy
Does it need to? If there is no title attribute in a link, then nothing changes (as there is no title to move over to the class group).
Lucanos
A: 

Same as with your other question. Use DOM:

$dom = new DOMDocument;
$dom->loadXML( $html );
$xpath = new DOMXPath( $dom );
$links = $xpath->query( '/ul/li/a[@title]' );
foreach($links  as $link ) {
    $classes  = $link->parentNode->getAttribute( 'class' );
    $classes .= ' ' . $link->getAttribute( 'title' );
    $link->parentNode->setAttribute( 'class', $classes );
    $link->removeAttribute( 'title' );
}
echo $dom->saveXML( $dom->documentElement );

Again, this assumes you are using valid XHTML. If not, you have to load the markup with loadHTML and change the XPath to take the added HTML skeleton into account. Be aware that this also changes what documentElement of the DOMDocument, so you have to pass the menu node to saveXML instead.

Gordon