2016-11-07 40 views
0

根据DOMDocument::getElementsByTagName的文档,我可以用"*"参数调用该函数,并从某些HTML代码中获取所有HTML元素的列表。如何获取PHP中所有html元素的列表?

然而,用下面的代码:

<?php 
    $dom = new DOMDocument(); 
    $dom->loadHTML("<html><body><div>hello</div><div>bye</div></body></html>"); 
    $nodes = $dom->getElementsByTagName("*"); 

    foreach ($nodes as $node) { 
    $new_text= new DOMText($node->textContent."MODIFIED"); 

    $node->removeChild($node->firstChild); 
    $node->appendChild($new_text); 
    } 
    $content = $dom->saveHTML(); 
    echo $content; 
?> 

我得到的只有一个元素的列表,上面的代码的执行结果是:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html>hellobyeMODIFIED</html> 

,而我希望的东西像这样:

<html><body><div>helloMODIFIED</div><div>byeMODIFIED</div></body></html> 

不应该DOMDocument::getElementsByTagName方法返回一个尽可能多的HTML元素在HTML代码中可用?

注:我需要显式创建DOMText实例,因为我需要这个在PHP 5.4中工作。 DOMNode::textContent只能从PHP写入5.6

+0

你的元素具有相同的标签名称... – Alexis

+0

@Alexis,是的,但如果我的getElementsByTagName被改变的getElementsByTagName( “*”)( “分区”) ,那么我得到我想要的结果,并且这些元素仍然具有相同的标签名称。 –

+0

@MarcosFernandez,你不清楚你到底想要达到什么目的。你想修改所有文本节点吗?还是要修改具有文本节点的叶子(最后一个标签)的所有文本节点?例如,这个序列应该如何修改'

textabcdef
'? –

回答

2

DOMDocument::getElementsByTagName方法实际上会返回所有标记,如果第一个参数是'*'。但是你的代码在第一次迭代时用一个文本节点代替<body>标签(包括所有子节点)。

迭代的节点,并修改只有nodeType属性等于XML_TEXT_NODE节点:

$nodes = $dom->getElementsByTagName('*'); 

foreach ($nodes as $node) { 
    for ($child = $node->firstChild; $child; $child = $child->nextSibling) { 
    if (! ($child->nodeType === XML_TEXT_NODE && trim($child->textContent))) { 
     continue; 
    } 

    // The textContent is writable since PHP 5.6.1 
    if (PHP_VERSION_ID >= 50601) { 
     $child->textContent .= 'MODIFIED'; 
     continue; 
    } 

    // For older versions, create DOMText explicitly 
    $text = new DOMText($child->textContent . 'MODIFIED'); 
    try { 
     if ($child->parentNode->replaceChild($text, $child)) 
     $child = $text; 
    } catch (Exception $e) { 
     trigger_error("Failed to modify text '$child->textContent': " 
     . $e->getMessage(), E_USER_WARNING); 
    } 
    } 
} 

echo $dom->saveHTML(); 

注意,对于PHP版本5.6.1和更新,你不需要明确创建DOMText情况下,因为DOMNode::textContent属性可供读取和写入。所以你可以简单地通过给这个属性赋一个字符串值来修改文本。只确保节点除XML_TEXT_NODE之外没有子节点。

上述检查的代码,如果trim($child->textContent)不为空,因为文档可以包含额外的空间字符(包括换行),例如:

<div><!-- newline/spaces --> 
    <span>text</span><!-- newline/spaces --> 
</div><!-- newline/spaces --> 
+0

谢谢,这(几乎)它!只有一件事:我确实需要明确创建DOMText实例,因为我需要这个在PHP 5.4中工作。 'DOMNode :: textContent'只能从PHP 5.6开始编写。 5.4仍然无法完成这项工作。 –

+0

@MarcosFernandez,更新了答案 –

+0

非常感谢!我被困在了child-> parentNode的东西里。并感谢你的好解释。很多时间保存! –

0

尝试这种情况: -

foreach($dom->getElementsByTagName('*') as $element){ 

} 
0

此功能' DOMDocument :: getElementsByTagName'返回包含所有元素的DOMNodeList类的新实例。

,它工作正常:

<?php 
$dom = new DOMDocument(); 
    $dom->loadHTML("<html><body><div>hello</div><div>bye</div></body></html>"); 
    $nodes = $dom->getElementsByTagName("*"); 

    foreach ($nodes as $node) { 
     echo $node->tagName."<br />"; 
    } 
?> 

其输出文档的所有标签。

也许你需要像水木清华:

<?php 


    $dom = new DOMDocument(); 
     $dom->loadHTML("<html><body><div>hello</div><div>bye</div></body></html>"); 
     $nodes = $dom->getElementsByTagName("*"); 

     foreach ($nodes as $node) { 
      if ($node->tagName=='div'){ 
      $node->nodeValue .= "new content"; 
      } 
     } 

     $content = $dom->saveHTML(); 
     echo htmlspecialchars($content); 

?> 
相关问题