簡體   English   中英

帶有DOMXpath查詢/評估的xpath太長,什么也沒有返回

[英]Too long xpath with DOMXpath query/evaluate return nothing

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

對於較小的xpath,我可以獲得正確的結果,但對於較長的xpath,則不起作用。 (這個xpath似乎很好(我是用Xpather(firefox插件)獲得的,並用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起作用,而使用更長的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:復制錯誤。

驗證XPath確實不會返回結果后,我編寫了一個小腳本,以查看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 .= '/';
}

它將返回結果的最后一件事是

/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丟棄了它或它是否確實不存在。 不在那里 顯然,Firebug插入了它,這將解釋為什么使用XPather獲得結果(而不是為什么使用YQL獲得結果):

屏幕截圖顯示了頁面源代碼和明顯錯誤的Firebug視圖

第三步:校對和結論

我從XPath中刪除了<tbody>並重新運行了腳本。 沒問題。 返回“ Gaby”。

當我首先懷疑Firebug中的一個錯誤時,Alejandro評論說這也將在IE的DeveloperTools中發生。 然后,我懷疑這是由JavaScript添加的,但無法驗證。 經過更多研究后,Alejandro指出了為什么Firebug將<tbody>添加到<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'));

也會返回“ Gaby”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM