ラボ > PHP:HTML、Javascript絡み、各種エラー、DOM関連

phpQueryでXMLで始まるHTMLのパースでエラー

HTMLのパースを行おうとしたら1行目にあったXMLの記述が原因でエラーが出てきた。

作成日:2018-02-09, 更新日:2020-10-26

下記のようエラー

phpQueryでパースしようとしたら下記のようなエラーが出てきた。

Fatal error: Uncaught exception 'Exception' with message 'Error loading XML markup' in 〇〇〇〇/phpQuery-onefile.php:XXX Stack trace: 
#0 〇〇〇〇/phpQuery-onefile.php(XXX): DOMDocumentWrapper->loadMarkupXML('<xml version="...') 
#1 〇〇〇〇/phpQuery-onefile.php(XXX): DOMDocumentWrapper->loadMarkup('<xml version="...') 
#2 〇〇〇〇/phpQuery-onefile.php(XXX): DOMDocumentWrapper->load('<xml version="...', NULL, NULL) 
#3 〇〇〇〇/phpQuery-onefile.php(XXX): DOMDocumentWrapper->__construct('<xml version="...', NULL, NULL) 
#4 〇〇〇〇/phpQuery-onefile.php(XXX): phpQuery::createDocumentWrapper('<xml version="...', NULL) 
#5 〇〇〇〇/〇〇〇〇.php(XXX): phpQuery::newDocument('<xml version="...') 
#6 {main} thrown in 〇〇〇〇/phpQuery-onefile.php on line XXX

対象のHTMLファイルを見ると1行目に「<?xml version="1.0" encoding="utf-8"?>」ってのがいた。
ひとまず、これを削除するとパースは出来る。

エラーになっている箇所

エラーメッセージにあるように「phpQuery-onefile.php」の「loadMarkupXML()」内にある「throw new Exception("Error loading XML markup");」ってトコ。
※「phpQuery-onefile.php」をカスタマイズしていなければ424行目だと思う。

ココに入るまでの流れを見ると15行目ぐらいにある「$return = $this->document->loadXML($markup, $libxmlStatic);」ってトコ。
この下にコメントされている文がある。

$return = $this->document->loadXML($markup, $libxmlStatic);
// if (! $return)
// $return = $this->document->loadHTML($markup);

「loadXML()」で失敗したら「loadHTML()」をさせようとしたけど、やっぱやーめたって感じ。

ひとまずコメント解除。

「loadHTML()」のコメント解除

コメント解除して、再度パースしようとしたら次は下記のようなエラー。

Warning: DOMDocument::loadHTML(): Attempt to load network entity http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtdhtmlParseEntityRef: expecting ';' in Entity, line: 158 in 〇〇〇/phpQuery-onefile.php on line 431

調べると「$this->document->loadHTML($markup);」がよくないらしい。

// if (! $return)
// $return = $this->document->loadHTML($markup);
// ▼コメント解除して、下記のように修正
if (! $return)
  $return = $this->document->loadHTML(htmlspecialchars($markup));

ひとまず、これでエラーは出なくなったけど、パースはされない・・・。

調べると文字化けしていた。

文字化け対策

取得したソースを下記のようにUTF8にして「loadHTML()」していたけどダメらしいので、修正。

// $sorce = mb_convert_encoding($sorce, "UTF-8", "auto");
$sorce = mb_convert_encoding($sorce, "HTML-ENTITIES", "auto");
$dom = phpQuery::newDocument($sorce);

// 「HTML-ENTITIES」が何者かは知らないが、phpQuery-onefile.php内のコイツをやっても文字化けはしなくなった。
// $this->document->loadHTML(htmlspecialchars($markup));

挫折

文字化けして、再度パースするけど、どうしても・・・パースが出来ない。

解決

諦めようとしたけど・・・よくよく考えたらHTMLのパース時に「loadMarkupXML()」を実行されるのがよくない。
無理やりHTMLのパースをしてくれる関数のほうに誘導したい!ってコトに思い至ってソースを確認。

「phpQuery::newDocument()」から辿ろうとすると「phpQuery::newDocumentHTML()」ってヤツがいた。
修正箇所をすべて元に戻して・・・下記のように修正。

$sorce = mb_convert_encoding($sorce, "UTF-8", "auto");
//$dom = phpQuery::newDocument($sorce);
$dom = phpQuery::newDocumentHTML($sorce);