2010-11-04 118 views
0

我正在使用PHP檢索給定URL和XPATH的內容。 我使用DOMDocument/DOMXPath(與查詢或評估)。DOMXpath查詢/評估的xpath過長太長

對於小的xpath,我獲得正確的結果,但對於更長的xpath,它不起作用。 (這XPath的似乎也不錯(我Xpather(火狐插件)獲得他們和YQL重新測試它們)

你對這種奇怪的麻煩任何意見

的代碼示例:?

$doc = new DOMDocument(); 
$myXMLString = file_get_contents('http://stackoverflow.com/questions/4097230/too-long-xpath-with-domxpath-query-evaluate-return-nothing'); 
@$doc->loadHTML($myXMLString); //@ to suppress warnings 
           //(good for not ending markup) 
$xpath = new DOMXPath($doc); 

$fullPath ="/html/body/small/path"; //it works 
//$fullPath = "/html/body/full/path/with/lot/of/markup";//does not works 
$entries = $xpath->query($fullPath); 
//or ->evalutate($fullPath) (same behaviour) 
//$entries return DOMNodeList (empty for a long path query, 
//        correct for a small path query) 

我與屬性限制測試,但似乎沒有改變(與它的工作原理小的XPath,具有更長的它不工作的更多)

例子: 這個當前頁面:

$fullPath = "/html 
       /body 
       /div[4] 
       /div[@id='content'] 
       /div[@id='question-header'] 
        /h1 
        /a";//works (retrieve the question title) 
$fullPath = "/html 
       /body 
       /div[4] 
       /div[@id='content'] 
       /div[@id='mainbar'] 
        /div[@id='question'] 
        /table 
        /tbody 
        /tr[2] 
         /td[2] 
         /div[@id='comments-4097230'] 
         /table 
         /tbody 
          /tr[@id='comment-4408626'] 
          /td[2] 
          /div 
          /a"; //does'nt work 
            //(should retrieve 'gaby' from comment) 

編輯:

我用SimpleXML lib中考了,我有完全一樣的行爲(良好的結果對於小的查詢,沒有長期的查詢)。


編輯2:

我還會刪除一些第一要素切最長的XPath和它的作品。 順便說一句我真的不明白爲什麼完整正確的xpath不起作用。

+1

給我們xml和xpath – 2010-11-04 13:44:10

+1

我添加一個例子。 – AlphaB 2010-11-04 14:04:23

回答

3

讓我們通過這一步一步:

第1步:複製錯誤。

驗證與XPath確實會不返回結果後,我寫了一個小腳本,看有多深它打破

foreach (explode('/', $fullPath) as $segment) { 
    $xpath .= trim($segment); 
    echo '-------------------------------------------', PHP_EOL, 
     'Trying: ', $xpath, PHP_EOL, 
     '-------------------------------------------', PHP_EOL; 
    echo $xp->evaluate("string($xpath)"), PHP_EOL; 
    $xpath .= '/'; 
} 

的最後一件事情之前的XPath會去它會返回一個結果爲是

/html/body/div[4]/div[@id='content']/div[@id='mainbar']/div[@id='question']/table 

步驟2:檢查所述標記

所以我檢查由DOMDocument::saveHTML()返回的標記,看看是什麼樣子,也沒有<tbody>(重新格式化爲可讀性)

<div id="question"> 
    <div class="everyonelovesstackoverflow" id="adzerk1"></div> 
     <table> 
      <tr><td class="votecell"> 

我選中此很頁面,看看它是否是DOM投擲它離開或如果它真的不存在。它不在那裏。顯然,螢火蟲將它插入,這可以解釋爲什麼會得到與XPather結果(而不是爲什麼你和YQL得到它):

Screenshot showing page source and apparently bugged Firebug view

第3步:proofchecking和結論

我刪除XPath中的<tbody>並重新執行腳本。沒問題。返回「Gaby」。

雖然我第一次懷疑在Firebug的錯誤,亞歷杭德羅評論說這會發生在IE的DeveloperTools了。然後我懷疑這是通過JavaScript添加的,但無法驗證。經過一些更多的研究Alejandro指出我Why does firebug add <tbody> to <table>? - 它實際上既不是Firebug也不是JavaScript,但瀏覽器本身。

所以要修改我的結論:你看在瀏覽器中呈現

不信任的標記,因爲它可以通過瀏覽器或其他技術進行修改。 DOM只會下載直接提供的內容。如果你再次遇到類似的問題,你現在知道如何處理它。


一些附加圖片的標題說明

除非你需要將其送入DOM之前修改標記,你不必使用file_get_contents()加載內容。您可以使用DOM的loadHTMLFile()

$dom->loadHTMLFile('http://www.example.com/foo.htm'); 

此外,爲了抑制錯誤的正確方法是告訴libxml使用它的內部錯誤處理程序。但不是處理錯誤,而是簡單地清除它們。這隻會影響與libxml有關的錯誤,例如解析錯誤(而不是所有的PHP錯誤):

libxml_use_internal_errors(TRUE); 
libxml_clear_errors(); 

最後,XPath查詢可以在關係做一個上下文節點。因此,雖然長XPath在查找時間方面效率很高,但您可以簡單地使用getElementById()來獲取最深入的已知節點,然後使用XPath來對付它。

換句話說:

libxml_use_internal_errors(TRUE); 
$dom = new DOMDocument; 
$dom->loadHTMLFile('http://www.example.com/foo.htm'); 
libxml_clear_errors(); 
echo $xp->evaluate(
    'string(td[2]/div/a)', 
    $dom->getElementById('comment-4408626')); 

將返回 「蓋比」 爲好。

+1

對不起,我的帖子不夠精確。我希望返回一個節點(其中包含gaby)的DOMNodeList。 (和THX有關libxml的建議) – AlphaB 2010-11-04 14:35:15

+0

只見YQL類,但我更喜歡如果可能快速和更小的方式(指DOM或簡單的XML lib中的使用而不是外部服務) – AlphaB 2010-11-04 14:41:45

+0

@AurelienB因爲你的另一個問題建議你使用的Zend Studio請嘗試以下操作:下載標記並將其保存到文件中。在Zend Studio中使用XML透視圖打開文件。如果它無效,您可能必須先糾正它。然後使用左下方的XPath評估器來測試它是否找到您的節點。 – Gordon 2010-11-04 16:29:18