2011-01-06 89 views
2

我正在學習如何使用PHP提供的DOM *類,並且已經注意到(我認爲是)在測試中的不規則性。使用PHP的DOM類替換DOMNode

鑑於此文檔,ZuqML_test_100.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zuq="http://localhost/~/zuqml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Untitled Document</title> 
</head> 
<body> 
    <h1> 
     <zuq:data name="siteHeader" /> 
    </h1> 
    <h2> 
     <zuq:data name="pageHeaderName" /> 
     <span>&nbsp;|&nbsp;</span> 
     <zuq:data name="pageHeaderTitle" /> 
    </h2> 
    <zuq:region name="post"> 
     <zuq:param name="onEmpty"> 
      <div class="post noposts"> 
       <p>There are no posts to show at this time.</p> 
      </div> 
     </zuq:param> 
     <div class="post"> 
      <h3><zuq:data name="postHeader" /></h3> 
      <p> 
       <zuq:data name="postText"> 
        <zuq:format type="trim"> 
         <zuq:param name="length">300</zuq:param> 
         <zuq:param name="append"> 
          <a> 
           <zuq:attr name="href"> 
            ./?action=viewpost&amp;id=<zuq:data name="postId" /> 
           </zuq:attr> 
           <zuq:data name="postAuthor" /> 
          </a> 
         </zuq:param> 
        </zuq:format> 
       </zuq:data> 
      </p> 
     </div> 
    </zuq:region> 
</body> 
</html> 

我試圖與價值foo一個簡單的文本節點替換所有<zuq:data />節點。我用下面的代碼片段這樣做:

$root = new DOMDocument(); 
@$root->load('ZuqML_test_100.html'); 

foreach($root->getElementsByTagNameNS($root->lookupNamespaceURI('zuq'), 'data') as $node){ 
    $node->parentNode->replaceChild($node->ownerDocument->createTextNode('foo'), $node); 
} 

echo $root->saveXML(); 

它有點工作,但是我的產量仍似乎包含<zuq:data />節點,如下所示:

<?xml version="1.0"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zuq="http://ichorworkstudios.no-ip.org/~/zuqml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Untitled Document</title> 
</head> 

<body> 

     <h1> 
     foo 
    </h1> 

    <h2> 
     <zuq:data name="pageHeaderName"></zuq:data> 
     <span>&mdash;</span> 
     foo 
    </h2> 

    <zuq:region name="post"> 
     <zuq:param name="onEmpty"> 
       <div class="post noposts"> 
       <p>There are no posts to show at this time.</p> 
      </div> 
     </zuq:param> 
     <div class="post"> 
       <h3><zuq:data name="postHeader"></zuq:data></h3> 
      <p> 
       foo 
       </p> 
     </div> 
    </zuq:region> 

</body> 
</html> 

爲什麼有些<zuq:data />節點落後了嗎?

回答

3

我認爲這與你如何迭代有關。你正在改變結果列表,因爲它正在迭代,所以它打破了(副作用)。試着改變你的循環,這樣的:

$nodes = $root->getElementsByTagNameNS($root->lookupNamespaceURI('zuq'), 'data'); 
$i = $nodes->length - 1; 
while ($i >= 0) { 
    $node = $nodes->item($i); 
    $node->parentNode->replaceChild(
     $node->ownerDocument->createTextNode('foo'), 
     $node 
    ); 
    $i--; 
} 

基本上,它只是向後遍歷節點列表,從而使節點被移除時,他們是從結束而不是開始刪除...

+1

給出致命錯誤:除非你做'$ nodes-> item($ i)` – Gordon 2011-01-06 14:27:12

+0

',否則不能使用DOMNodeList類型的對象作爲第25行的F:\ Work \ code \ gordonoheim \ sandbox \ newfile.php中的數組謝謝** ircmaxell **;雖然複製粘貼證明不成功,但會出現'致命錯誤:不能使用DOMNodeList類型的對象作爲數組'。 ** @戈登**;我當時就是這麼想的。 – Dan 2011-01-06 14:28:49

3

通過ircmaxell提供的解釋是

you are changing the result list as it's being iterated against,

是正確的,但我想我一些更多的細節添加到它,所以你可以理解爲什麼出現這種情況。

這裏是運行

當在開始的時候會出現在節點列表七個節點的代碼做什麼。

第一個是

<zuq:data name="siteHeader"></zuq:data> 

之後被去除的節點計數降到6。要刪除的下一個節點是

<zuq:data name="pageHeaderTitle"></zuq:data> 

但是,如果你看一下您的標記,你會看到,未來zuq:數據元素實際上是

<zuq:data name="pageHeaderName" /> 

現在的問題是,當你刪除來自當前也在當前迭代的NodeList中的文檔的節點,該節點也將從NodeList中被移除。但是NodeList中的當前位置將仍然是相同的(或自動前進,不確定哪個方向),例如,

0 siteHeader 
1 pageHeaderName 
2 pageHeaderTitle 
n … 

在當前位置爲0,你從文檔中刪除該節點,你得到這樣

0 pageHeaderName 
1 pageHeaderTitle 
n … 

列表您仍然處於0位置,但並因而,當你去NodeList中的下一個元素將跳過新位置0處的節點。你直接去pageHeaderTitle,留下pageHeaderName未處理。

pageHeaderTitle被移除後,將節點計數下降到五,使得

<zuq:data name="pageHeaderName"></zuq:data> 

新元件在當前位置。因此,要刪除的下一個節點是

<zuq:data name="postText"> 
    <zuq:format type="trim"> 
    <zuq:param name="length">300</zuq:param> 
     <zuq:param name="append"> 
     <a> 
     <zuq:attr name="href"> 
     ./?action=viewpost&amp;id= 
     <zuq:data name="postId"></zuq:data> 
     </zuq:attr> 
     <zuq:data name="postAuthor"></zuq:data> 
     </a> 
    </zuq:param> 
    </zuq:format> 
</zuq:data> 

正如您所看到的,那裏還有兩個zuq:數據元素。因此,節點數將下降到2(5 - 1個當前節點 - 2個孩子)。

之後,遍歷所有節點列表結束,留給你

<zuq:data name="postHeader"></zuq:data> 

<zuq:data name="pageHeaderName"></zuq:data> 

文檔仍然英寸