HTML操作:匹配前X个HTML标记并移动它们

Let's say I've have the code like this:

<img src="001">
<img src="002">

<p>Some content here.</p>

<img src="003">

What I want to do now is to match the first two images (001 and 002) and store that part of the code in variable. I don't want to do anything with third image.

Id used something like preg_match_all('/<img .*>/', $result); but it obviously matched all the images. Not just those which appear on the top of the code. How to modify that regular expression to select just images that are on top of the code.

What I want to do is to now. I've have <h2> tag with title in one variable and the code above in the second. I want to move the first X images before the <h2> tag OR insert that <h2> tag after first X images. All that in back-end PHP. Would be fun to make it with CSS, but flexbox is not yet here.

You need to divide the problem to solve it. You have got two main parts here:

  1. Division of the HTML into Top and Bottom parts.
  2. Doing the DOMDocument manipulation on (both?) HTML strings.

Let's just do that:

The first part is actually quite simple. Let's say all line separators are " " and the empty line is actually an empty line " ". Then this is a simple string operation:

list($top, $bottom) = explode("

", $html, 2);

This solves the first part already. Top html is in $top and the rest we actually do not need to care much about is stored into $bottom.

Let's go on with the second part.

With simple DOMDocument operations you can now for example get a list of all images:

$topDoc = new DOMDocument();
$topDoc->loadHTML($top);
$topImages = $topDoc->getElementsByTagname('img');

The only thing you need to do now is to remove each image from it's parent:

$image->parentNode->removeChild($image);

And then insert it before the <h2> element:

$anchor = $topDoc->getElementsByTagName('h2')->item(0);
$anchor->parentNode->insertBefore($image, $anchor);

And you're fine. Full code example:

$html = <<<HTML
<h2>Title here</h2>
<img src="001">
<p>Some content here. (for testing purposes)</p>
<img src="002">

<h2>Second Title here (for testing purposes)</h2>
<p>Some content here.</p>

<img src="003">
HTML;

list($top, $bottom) = explode("

", $html, 2);

$topDoc = new DOMDocument();
$topDoc->loadHTML($top);
$topImages = $topDoc->getElementsByTagname('img');
$anchor = $topDoc->getElementsByTagName('h2')->item(0);
foreach($topImages as $image) {
    $image->parentNode->removeChild($image);
    $anchor->parentNode->insertBefore($image, $anchor);
}

foreach($topDoc->getElementsByTagName('body')->item(0)->childNodes as $child)
    echo $topDoc->saveHTML($child);
echo $bottom;

Output:

<img src="001"><img src="002"><h2>Title here</h2>
<p>Some content here. (for testing purposes)</p>
<h2>Second Title here (for testing purposes)</h2>
<p>Some content here.</p>

<img src="003">