22

DOMDocument を使用して HTML コードを解析し、変更などを行ってから、出力に送信する文字列にアセンブルしようとしています。

ただし、解析に関していくつかの問題があります。つまり、DOMDocument に送信したものが常に同じ形式で返されるとは限りません:)

リストは次のとおりです。

  1. ->loadHTMLを使用:

    • preserveWhitespaceとの設定に関係なくドキュメントをフォーマットしformatOutputます (整形済みテキストの空白を失います)
    • <header>などのhtml5タグがあるとエラーが発生しますが、<footer>それらは抑制できるため、これで問題ありません。
    • 一貫性のないマークアップを生成します-たとえば、<link ... />(自己終了タグを使用して) 要素を追加すると、HTML の解析/保存後に出力は次のようになります<link .. >
  2. ->loadXMLを使用:

    • >from<style>または<script>tags:のbody > divようなエンティティをエンコードします。body &gt; div
    • <meta ... />すべてのタグは同じように閉じられ<meta...></meta>ます。しかし、これは正規表現で修正できます。

HTML5lib は試しませんでしたが、パフォーマンス上の理由から、カスタム パーサーではなく DOMDocument を使用したいと思います。


アップデート:

前述の Honeymonster のように、CDATA を使用すると、loadXML の主な問題が修正されます。

正規表現を使用せずに、特定のセット以外のすべての空の HTML タグの自己終了を防ぐ方法はありますか?

今私は持っています:

$html = $dom->saveXML($node);

$html = preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($matches){

       // ignore only these tags
       $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param' ,'meta');

       // if a element that is not in the above list is empty,
       // it should close like   `<element></element>` (for eg. empty `<title>`)
       return in_array($matches[1], $xhtml_tags) ? "<{$matches[1]}{$matches[2]} />" : "<{$matches[1]}{$matches[2]}></{$matches[1]}>";
}, $html);

これは機能しますが、CDATAコンテンツの置換も行いますが、これは望ましくありません...

4

6 に答える 6

14

html5libを使用します。html5 を解析して DOMDocument を生成できます。例:

require_once '/path/to/HTML5/Parser.php';
$dom = HTML5_Parser::parse('<html><body>...');

ドキュメンテーション

于 2012-05-23T04:57:38.407 に答える
10

HTML5 をサポートしたい場合は、DOMDocument には一切触れないでください。

現在、最良の選択肢はhttps://github.com/Masterminds/html5-phpのようです

以前はhttps://github.com/html5lib/html5lib-phpが最適なオプションでしたが、説明にあるように「現在メンテナンスされていません」。これは 2011 年 10 月からのステータスなので、もう息を止めていません。

私はhtml5-php本番環境で使用したことがないため、それについて実際の経験を提供することはできません。私はhtml5lib-php本番環境で使用しており、整形式のドキュメントを正しく解析していると言えますが、いくつかの単純な構文エラーを伴う予期しないエラーがあります。一方、養子縁組機関のアルゴリズムやその他のいくつかの奇妙なコーナーケースは正しく実装されているようです。まだ維持されていればhtml5lib-php、私はまだそれを好むでしょう。ただし、現状では、html5-php残りのバグを使用して修正することをお勧めします。

于 2016-04-26T12:41:03.580 に答える
7

残念ながら、またはおそらく幸いなことに、domdocument は元のドキュメントの書式設定を保持しようとしないように設計されています。これは、すべての要素を同じスタイルに保つことで、パーサーの内部状態を管理しやすくするためです。私の知る限り、ほとんどのパーサーはメモリ内にツリー表現を作成し、ユーザーが要求するまでテキストの書式設定について心配する必要はありません。これが、セルフ クローズ タグが個別のクローズ タグで出力される理由です。良いニュースは、それが問題ではないということです。

<>に変換されるスタイル タグとスクリプト タグ&lt;&gt;に関しては、次のように、問題の要素のコンテンツを推奨される cdata タグで囲むことにより、変換を回避できる場合があります。

<style>
  /*<![CDATA[*/
    body > div {
      width: 50%;
    }
  /*]]>*/
</style>

cdata 宣言の周りのコメント/* */は、cdata セクションを認識せず、代わりに宣言を CSS コードとして扱う壊れたクライアントを許可するためのものです。ドキュメントを内部でのみ使用している場合は、/* */コメントの囲みを省略して、cdata 宣言のみを使用できます。/* */ドキュメントを操作し、コメントが保持されていることを確認せずにブラウザに送信すると、前述の壊れたクライアントで問題が発生する可能性があります。domdocument がこれらを保持するかどうかはわかりません。

于 2012-05-28T19:04:36.733 に答える
3

html5lib と html5php の両方を試しましたが、提供された HTML ではどちらも機能しませんでした。HTML を解析できた別の方法は、https ://github.com/ivopetkov/html5-dom-document-php です。

メイン クラスは、PHP のネイティブ DomDocument を拡張します。

于 2017-01-07T18:03:58.437 に答える
3

10 年が経過しましたが、問題はまだ PHP DOMDocument に存在します。問題を解決する 2 つの方法を見つけました。

解決策 1

次のように loadHTML メソッドにオプションとして追加LIBXML_NOERRORします。

<?php

$dom = new DOMDocument();

$dom->loadHTML('<header data-attribute="foo">bar<', LIBXML_NOERROR);

echo $dom->saveHTML();
// outputs the html with valid closing tag without any error
?>

解決策 2

libxml_use_internal_errors(true)HTMLをロードする前に追加

<?php

$dom = new DOMDocument();

libxml_use_internal_errors(true);

$dom->loadHTML('<header data-attribute="foo">bar<');

echo $dom->saveHTML();
// outputs the html with valid closing tag without any error
?>
于 2021-12-10T10:35:16.267 に答える
-7

domDocument を初期化するときは、次のようにします。

$dom = new DOMDocument(5, 'UTF-8');
于 2015-08-26T00:48:37.070 に答える