В первую очередь — из-за этого:
$doc->load($str);
«load» — это для загрузки файлов и в качестве параметра ей нужно давать путь к файлу. Если вы хотите загрузить строку, нужно использовать функцию «loadHTML».
Дальше у вас появится куча предупреждений. Если появится сообщение про то, что непонятки с кодировкой появились, от него можно избавиться, если поправить строку с loadHTML:
$doc->loadHTML(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8'));
Кроме строки про кодировку будет ещё куча предупреждений, вроде:
Warning: DOMDocument::loadHTML(): Opening and ending tag mismatch: li and div in Entity
Warning: DOMDocument::loadHTML(): htmlParseEntityRef: expecting ';' in Entity
Warning: DOMDocument::loadHTML(): Opening and ending tag mismatch: td and b in Entity
Чтобы эти уведомления не засоряли эфир, можно добавить символ «@» при вызове «loadHTML»:
@$doc->loadHTML($str);
Дальше, чтобы удостовериться, что те узлы, которые вы пытаетесь искать, всё-таки существуют, можно вывести список вообще всех узлов, вот так:
$res = $xpath->query('.//*');
foreach($res as $obj) {
echo $obj->getNodePath() . "\n\r";
}
Из листинга будет видно, что упоминание связки «table/tbody/tr» некорректно. «TBODY» там нет. Такой XPath-запрос сработает нормально в FirePath из Firefox, например. И работает он из-за того, что Firefox самостоятельно достраивает DOM документа до идеального по его мнению состояния — например, добавляет «TBODY», где его нет, закрывает незакрытые теги и так далее.
В ситуации с DomDocument и DomXPath лучше смотреть чистый исходный код страницы и строить запросы именно по исходному коду, а не по сгенерированному браузером DOM.
В вашей ситуации нужно из запроса просто убрать «tbody». Получится такой запрос:
//*[@id="content-all"]/div[2]/div/table/tr[3]
Как я вижу, решение уже появилось, но, вообще, такой подход, который я описал, поможет искать ошибки в подобных ситуациях.