2014-10-31 100 views
2

我在PHP中編寫了這個小測試代碼,試圖瞭解DOMDocument :: getElementById的工作方式。我這樣寫,所以我可以利用方法鏈。無法理解如何使用PHP DOMDocument :: getElementById

<?php 
class SMHtmlElement extends DOMElement { 

    public function __construct($name, $value = NULL, $namespaceURI = NULL) { 
     parent::__construct($name, $value, $namespaceURI); 
    } 

    public function attr($attribute, $value) { 
     if (!empty($attribute)) { 
      $this->setAttribute($attribute, $value); 
     } 
     return $this; 
    } 

    public function id($value) { 
     $this->attr('id', $value); 

     // this doesn't helped. 
     @$this->ownerDocument->validate(); 

     $this->setIdAttribute('id',TRUE); 
     return $this; 
    } 
} 

class SMHtmlDocument extends DOMDocument { 

    private $body; 

    public function __construct() { 
     parent::__construct("1.0", "UTF-8"); 
     $this->validateOnParse = true; 
     $this->loadHTML('<!DOCTYPE html><html><head></head><body></body></html>'); 
     $this->body = $this->getElementsByTagName('body')->item(0); 
    } 

    public final function bodyAdd($element, $beforeElement = NULL) { 
     $el = new SMHtmlElement($element); 
     if ($beforeElement) 
      $beforeElement->insertBefore($el); 
     else 
      $this->body->appendChild($el); 

     return $el; 
    } 
} 

// this search should work it didn't 
$dom = new SMHtmlDocument(); 
$p1 = $dom->bodyAdd('p')->id('foo'); 
$p = $dom->getElementById('foo'); 
echo $dom->saveHTML(); 
var_dump($p); 

// when set the ID outside the method, it works. 
$p2 = $dom->getElementsByTagName('p')->item(0); 
$p2->setIdAttribute('id',true); 
$p = $dom->getElementById('foo'); 
var_dump($p); 

// let's see if both paragraph elements are the same 
var_dump($p1->isSameNode($p2)); 
?> 

執行它後,我得到了這樣的輸出:

$> php teste.php 
<!DOCTYPE html> 
<html><head></head><body><p id="foo"></p></body></html> 
NULL // first var_dump() 
object(DOMElement)#4 (0) { // second var_dump() 
} 
bool(true) 

正如你所看到的,我已標記屬性id作爲方法ID內部ID(),並沒有奏效。但是當我在對象之外調用方法setIdAttribute()時,它確實有效。

這裏的一些帖子建議使用DTD,但正如我試圖生成HTML5,據我所知,HTML5不是基於DTD的。我也知道我可以使用XPath來查找我想要的id,但我真的很想理解爲什麼我的代碼不能正常工作。

我在使用PHP 5.3的Ubuntu 12.04服務器安裝上運行此操作。

有人可以解釋我發生了什麼?

謝謝!

回答

0

我認爲這是一個非常奇怪的行爲setIdAttribute方法。由於某些奇怪的原因,這個方法必須被稱爲偶數次。但我不確定它在不同版本的PHP中是否一致。在我的情況(5.5.13)這個工程:

版本1:工作

$dom = new SMHtmlDocument(); 
$p1 = $dom->bodyAdd('p')->attr('id','foo'); 
$p = $dom->getElementById('foo'); 
echo $dom->saveHTML(); 
var_dump($p); 

$p2 = $dom->getElementsByTagName('p')->item(0); 
$p = $dom->getElementById('foo'); 
var_dump($p); 

// let's see if both paragraph elements are the same 
var_dump($p1->isSameNode($p2)); 

這工作,以及:

版本2:工作

$dom = new SMHtmlDocument(); 
$p1 = $dom->bodyAdd('p')->attr('id','foo'); 
$p1->setIdAttribute('id', TRUE); 
$p1->setIdAttribute('id', TRUE); 
$p = $dom->getElementById('foo'); 
echo $dom->saveHTML(); 
var_dump($p); 

$p2 = $dom->getElementsByTagName('p')->item(0); 
$p = $dom->getElementById('foo'); 
var_dump($p); 

// let's see if both paragraph elements are the same 
var_dump($p1->isSameNode($p2)); 

而這不:

版本3:破

$dom = new SMHtmlDocument(); 
$p1 = $dom->bodyAdd('p')->attr('id','foo'); 
$p1->setIdAttribute('id', TRUE); 
$p = $dom->getElementById('foo'); 
echo $dom->saveHTML(); 
var_dump($p); 

$p2 = $dom->getElementsByTagName('p')->item(0); 
$p2->setIdAttribute('id', TRUE); 
$p2->setIdAttribute('id', TRUE); 
$p = $dom->getElementById('foo'); 
var_dump($p); 

// let's see if both paragraph elements are the same 
var_dump($p1->isSameNode($p2)); 

我認爲這是底層的XML庫的一個bug,libxml2的可能。

+0

好主意加倍setIdAttribute(),儘管使事情更奇怪。它也適用於我。但是如果您添加第三個電話,則停止工作。所以當你說我們必須偶爾調用這個函數時你是對的。 – Daniel 2014-10-31 22:55:26