我有一组HTML文件要处理,其中相关部分未分组在容器中,并且实际上可以包含任何元素。当前,新部分仅由下一个标头标记划定:
<h1>Section 1</h1>
<p>Paragraph Text</p>
<p>Paragraph Text</p>
<h2>Section 2</h2>
<p>Paragraph Text</p>
<img src='an image' />
<p>Further Paragraph Text</p>
<h1>Section 3</h1>
<p>Paragraph Text</p>
<p>Paragraph Text</p>
如何使用DOM functions in PHP在<div>
的这些标头标记之间包装所有内容?即将上述HTML转换为:
<div>
<h1>Section 1</h1>
<p>Paragraph Text</p>
<p>Paragraph Text</p>
</div>
<div>
<h2>Section 2</h2>
<p>Paragraph Text</p>
<img src='an image' />
<p>Further Paragraph Text</p>
</div>
<div>
<h1>Section 3</h1>
<p>Paragraph Text</p>
<p>Paragraph Text</p>
</div>
到目前为止,我已经尝试过使用循环和XPATH选择器的各种组合来尝试收集标头之间的所有元素,以便可以像上面那样包装它们-但尚未成功完成。
答案 0 :(得分:1)
我最初的想法是基于操纵输出缓冲区的,因为我未能正确阅读开头的段落,并且以下函数用作了ob_start
的回调。
您可能会注意到在函数开始时使用$ tags,后面是相当复杂的$ query-$ tags稍后用于帮助填充找到的节点,并确保我们在找到下一个节点时停止$ tags数组-而不是编写模式并独立维护此数组,我认为这样会更灵活。
基本上,它的工作原理如下:从提供的$tags
数组构造查询模式,然后使用该查询模式查询HTML DOM。如果存在匹配的节点,请遍历集合并将找到的节点(标头)添加到数组中。然后遍历找到的节点的同级并将它们添加到同一新数组中。在循环移动到集合中的下一个节点之前,请保存该数组,然后再重复此过程。处理完所有发现的节点后,就可以创建容器DIV
元素,以确保再次填充所有子项。
<?php
#https://stackoverflow.com/questions/59234379/using-domdocument-to-wrap-all-nodes-between-header-tags-in-div/59235431#59235431
function wrapcallback( $buffer ){
global $use_output_buffer;
$delimiter='#';
$tags=array('h1','h2','h3','h4','h5','h6');
$query=implode('|', explode( $delimiter, sprintf( '//%s', implode( sprintf( '%s//', $delimiter ), $tags ) ) ) );
$keepers=array();
$parents=array();
libxml_use_internal_errors( true );
$dom=new DOMDocument;
$dom->validateOnParse=false;
$dom->recover=true;
$dom->strictErrorChecking=false;
$dom->preserveWhiteSpace=true;
$dom->loadHTML( $buffer );
$errors = libxml_get_errors();
libxml_clear_errors();
$xp=new DOMXPath( $dom );
$col=$xp->query( $query );
if( $col->length > 0 ){
foreach( $col as $node ){
$parents[]=$node->parentNode;
$nodes=array( $node );
while( $node = $node->nextSibling ){
if( in_array( $node->nodeName, $tags ) )break;
if( $node->nodeType==XML_ELEMENT_NODE )$nodes[]=$node;
}
$keepers[]=$nodes;
}
}
foreach( $keepers as $index => $obj ){
$div=$dom->createElement('div');
$parents[ $index ]->appendChild( $div );
foreach( $obj as $child )$div->appendChild( $child );
}
$keepers = $parents = $xp = $div = null;
echo $dom->saveHTML();
};
$html="
<!DOCTYPE html>
<html lang='en'>
<head>
<title>It's a Christmas Wrapper!</title>
<style>
body{
background:url( https://storage.needpix.com/rsynced_images/christmas-wallpaper-1480711266Vyi.jpg );
background-repeat:repeat;
color:white;
}
</style>
</head>
<body>
<h1>Section 1</h1>
<p>Paragraph Text</p>
<p>Paragraph Text</p>
<h2>Section 2</h2>
<p>Paragraph Text</p>
<img src='/images/laracroft.png' />
<p>Further Paragraph Text</p>
<h1>Section 3</h1>
<p>Paragraph Text</p>
<p>Paragraph Text</p>
</body>
</html>";
wrapcallback( $html );
?>