我试图通过nodePath对php DOMDocument元素进行排序,以便它们最先嵌入最深层次,然后按顺序存在于同一父文档中的文档中。
例如,在以下HTML中,order属性是顺序 我想要对元素进行排序。
<div order='5'>
<div order='3'>
<div order='1'></div>
<div order='2'></div>
</div>
<div order='4'></div>
</div>
我非常接近,但并非一直都在那里。
//THIS gives me order 2,1,4,3,5 which is deepest nested but not linear
within the same parent
function dorder($a,$b){
$bp=count(explode("/",$b->getNodePath()) );
$ap=count( explode("/",$a->getNodePath()) );
if($ap==$bp){
return 0;
}
else if($ap<$bp){
return 1;
}
else{
return -1;
}
}
有时排序会在一个父级中以正确的顺序获得一些元素, 但在另一位父母身上错了......
//THIS gives me 1,2,4,3,5 which is right except for 4 and 3 are swapped.
function dorder($a,$b){
$bp=count(explode("/",$b->getNodePath()) );
$ap=count( explode("/",$a->getNodePath()) );
if($ap==$bp){
return 1;
}
else if($ap<$bp){
return 1;
}
else{
return -1;
}
}
注意 在实际的XML中没有&#39; order&#39;属性来工作。它仅用于测试目的。
答案 0 :(得分:1)
这是你可以去的方式。而不是usort,你可以直接深入dom堆栈。您将按顺序可靠地命中元素:
$dom = <<<DOM
<div order='5'>
<div order='3'>
<div order='1'></div>
<div order='2'></div>
</div>
<div order='4'></div>
</div>
DOM;
echo "<pre>" . htmlentities($dom) . "</pre>";
$domDocument = new DOMDocument;
$domDocument->loadXML($dom);
$domXPath = new DOMXPath($domDocument);
$domNodes = $domXPath->query('//div');
$nodesArray = array();
orderNodes($domNodes, $nodesArray);
foreach ($nodesArray as $n) {
echo "order: $n<br>";
}
function orderNodes($domNodes, &$nodesArray) {
foreach ($domNodes as $divDOM) {
if ($divDOM->hasChildNodes()) {
orderNodes($divDOM->childNodes, $nodesArray);
}
if ($divDOM instanceof DOMElement && ! isset($divDOM->visited)) {
$nodesArray[] = $divDOM->getAttribute('order');
$divDOM->visited = true;
}
}
}
使用递归深入了解DOMNodes,深度优先。我在那里塞了一个黑客,设置了一个任意属性:$divDOM->visited = true;
。这有点像过滤器,防止在递归退出时写入重复元素。
答案 1 :(得分:1)
function depthSort($nodesArr){
$sorted=array();
foreach($nodesArr as $node){
$i=0;
$adepth=count(explode("/",$node->getNodePath() ) );
while($i<count($sorted)){
$bdepth=count(explode("/",$sorted[$i]->getNodePath()));
if($adepth>$bdepth){
array_splice($sorted,$i,0,array($node));
break;
}
$i++;
}
//order must go on the end cause it didn't go anywhere else
if($i==count($sorted)){
array_push($sorted, $node);
}
}
return $sorted;
}