2012-06-11 160 views
7

我正在編寫一個腳本,它需要一個網頁,並檢測使用像Facebook這樣的按鈕的次數。由於這最好用DOM完成,所以我決定使用PHP的DOMDocument。PHP DOMDocument命名空間

的一個問題我也碰到過,不過,是像Facebook的喜歡按鈕元素:

<fb:like send="true" width="450" show_faces="true"></fb:like> 

由於該元素在技術上有「FB」的命名空間,DOM文檔拋出一個警告,說這個命名空間前綴是沒有定義的。然後繼續剝離前綴,所以當我到達所述元素時,其標籤不再是fb:如,而是,如

有什麼辦法可以「預註冊」一個命名空間嗎?有什麼建議麼?

回答

0

我有同樣的問題,我提出了以下解決方案/解決方法:

有沒有乾淨的方式來解析使用的DOMDocument不失命名空間的命名空間HTML,但也有一些解決方法:

  • 使用另一個接受HMTL代碼中名稱空間的分析器。在這裏尋找一個不錯的和詳細的HTML解析器列表。這可能是最有效的方法。
  • 如果你想堅持DOMDocument,你基本上必須預先和後處理代碼。

    • 之前,你的代碼發送到上一層> loadHTML,使用正則表達式,循環或任何你想找到的所有命名空間的標籤和一個自定義屬性添加到包含命名空間的開放標籤。然後

      <fb:like send="true" width="450" show_faces="true"></fb:like> 
      

      將導致

      <fb:like xmlNamespace="fb" send="true" width="450" show_faces="true"></fb:like> 
      
    • 現在請編輯的代碼到上一層> loadHTML。它會帶出的命名空間,但它會繼續屬性導致

      <like xmlNamespace="fb" send="true" width="450" show_faces="true"></like> 
      
    • 現在(再次使用正則表達式,環或任何你想要的)找到屬性XML命名空間的所有標籤,更換與實際命名空間的屬性。不要忘記還要將名稱空間添加到結束標記中!

我不認爲OP還在尋找一個答案,我只是張貼這對任何人說發現這個帖子在他們的研究。

+0

這聽起來像一個非常直接的解決方案,所以我決定與它一起運行。下面是我最終與任何人討厭正則表達式的代碼。 (\ w +)/','<\ 1 namespace =「\ 2」 ','postContent);' '//重新構建任何名稱間隔標籤' '$ postContent = preg_replace('/ <(\ w +)namespace =「(\ w +)」/','<\ 1 :\ 2',$ postContent);' – lupos

0

這是你在找什麼?你可以試試SimpleHTMLDOM。然後你可以運行類似...

$html = new simple_html_dom(); 
$html->load_file('fileToParse.html'); 
$count=0; 
foreach($html->find('fb:like') as $element){ 
    $count+=1 
} 
echo $count; 

這應該工作。

我看起來更進一步,發現這一點。我從PHP.net上的DOMDocument中獲取了此信息。

$dom = new DOMDocument; 
$dom->loadHTML('fileToParse.html'); // or $dom->loadXML('fileToParse.html'); 
$likes = $dom->getElementsByTagName('fb:like'); 
$count=0; 
foreach ($likes as $like) { 
    $count+=1; 
} 

這一次之後,我被卡住

$file=file_get_contents("other.html"); 
$search = '/<fb:like[^>]*>/'; 
$count = preg_match_all($search , $file, $matches); 
echo $count; 
//Below is not needed 
print_r($matches); 

這是不過正則表達式,是相當緩慢的。我試過了:

$dom = new DOMDocument; 
$xpath = new DOMXPath($dom); 
$dom->load("other.html"); 
$xpath = new DOMXPath($dom); 
$rootNamespace = $dom->lookupNamespaceUri($dom->namespaceURI); 
$xpath->registerNamespace('fb', $rootNamespace); 
$elementList = $xpath->query('//fb:like'); 

但是得到了和你一樣的錯誤。

+0

一些醜陋的東西這之前,但爲了速度,我想使用本機解決方案。我可能不得不默認回到這個:( – Obto

+0

@Obto我在我的小網站上使用這個,所以我沒有速度問題 – Bonzo

+0

我已經更新了這個應該更快的另一個解決方案 – Bonzo

4

在使用xml解析器之前,可以使用tidy來修飾它。

$tidy = new tidy(); 
$config = array(
    'output-xml' => true, 
    'input-xml' => true, 
    'add-xml-decl' => true, 
); 
$tidy->ParseString($htmlSoup, $config); 
$tidy->cleanRepair(); 
echo $tidy; 
0

一直未能找到方法來處理DOM。我很驚訝這個正則表達式比DOMDocument慢,因爲通常情況並非如此。 strpos應該是最快的,但:

strpos($dom, '<fb:like'); 

這隻能找到第一次出現,但你可以寫一個簡單的遞歸函數改變適當補償。

1

因爲這是從來沒有「解決」我決定繼續實施syndance的解決方案,誰不喜歡搞清楚正則表達式的任何人。

// do this before you use loadHTML()  
// store any name spaced elements so we can re-add them later 
$postContent = preg_replace('/<(\w+):(\w+)/', '<\1 data-namespace="\2"' , $postContent); 

// once you are done using domdocument fix things up 
// re-construct any name-spaced tags 
$postContent = preg_replace('/<(\w+) data-namespace="(\w+)"/', '<\1:\2 ' , $postContent); 
-1

嘗試正則表達式的解決方案...... 有一個問題結束標記,因爲他們不接受屬性!

<ns namespace="node">text</ns> 

(高於一切,正則表達式沒有考慮到關閉標籤...) 所以最後我做到了我所用像

$output = preg_replace('/<(\/?)(\w+):(\w+)/', '<\1\2thistaghasanamespace\3' , $output); 

$output = preg_replace('/<(\/?)(\w+)thistaghasanamespace(\w+)/', '<\1\2:\3' , $output);