これは私が取り組んだコードです。
<?php
$content_old = <<<'EOM'
<p> </p>
<p>lol<strong>test</strong></p>
<p><strong>This is a header</strong></p>
<p>Content content blah blah blah.</p>
EOM;
$content = preg_replace("/<p[^>]*>[\s| ]*<\/p>/", '', $content_old);
$doc = new DOMDocument;
$doc->loadHTML($content);
$xp = new DOMXPath($doc);
foreach ($xp->query('//p/strong') as $node) {
$parent = $node->parentNode;
if ($parent->textContent == $node->textContent &&
str_word_count($node->textContent) <= 8) {
$header = $doc->createElement('h2');
$parent->parentNode->replaceChild($header, $parent);
$header->appendChild($doc->createTextNode( $node->textContent ));
}
}
// just using saveXML() is not good enough, because it adds random html tags
$xp = new DOMXPath($doc);
$everything = $xp->query("body/*"); // retrieves all elements inside body tag
$output = '';
if ($everything->length > 0) { // check if it retrieved anything in there
foreach ($everything as $thing) {
$output .= $doc->saveXML($thing) . "\n";
}
};
echo "--- ORIGINAL --\n\n";
echo $content_old;
echo "\n\n--- UPDATED ---\n\n";
echo $output;
スクリプトを実行すると、次のような出力が得られます。
--- ORIGINAL --
<p> </p>
<p>lol<strong>test</strong></p>
<p><strong>This is a header</strong></p>
<p>Content content blah blah blah.</p>
--- UPDATED ---
<p>lol<strong>test</strong></p>
<h2>This is a header</h2>
<p>Content content blah blah blah.</p>
更新 #1
タグ内に他の<p><strong>
タグ (たとえば、<p><strong><a>
) がある場合、全体<p>
が置き換えられることは何の価値もありませんが、これは私の意図ではありませんでした。
これは、if を次のように変更することで簡単に修正できます。
if ($parent->textContent == $node->textContent &&
str_word_count($node->textContent) <= 8 &&
$node->childNodes->item(0)->nodeType == XML_TEXT_NODE) {
アップデート #2
元の createElement は、エスケープする<p><strong>
必要のある HTML 文字 (たとえば&
) 内のコンテンツが含まれている場合に問題を引き起こすことにも注意してください。
古いコードは次のとおりです。
$header = $doc->createElement('h2', $node->textContent);
$parent->parentNode->replaceChild($header, $parent);
新しいコード (正しく動作します) は次のとおりです。
$header = $doc->createElement('h2');
$parent->parentNode->replaceChild($header, $parent);
$header->appendChild($doc->createTextNode( $node->textContent ));