ホームページ  >  記事  >  ウェブフロントエンド  >  Jsoupコード解釈パート4-パーサー(パート1)_html/css_WEB-ITnose

Jsoupコード解釈パート4-パーサー(パート1)_html/css_WEB-ITnose

WBOY
WBOYオリジナル
2016-06-21 08:57:32818ブラウズ

Java の世界で最高の HTML 解析ライブラリとして、Jsoup のパーサー実装は非常に代表的です。この部分は Jsoup の最も複雑な部分でもあり、データ構造、ステート マシン、さらにはコンパイラに関するある程度の知識が必要です。幸いなことに、HTML 構文は複雑ではなく、解析は DOM ツリーに到達するだけなので、コンパイラーの入門としては非常に適しています。このすべてを飲み込むことを期待しないでください。コーヒーを一杯入れて、謎を味わいましょう。

基本

コンパイラー

コンピューター言語を別のコンピューター言語 (通常はマシンコード、アセンブリ、または JVM バイトなどの低レベル言語) に変換します。コーディングのプロセスはと呼ばれます。編集。コンパイラ(Compiler)はコンピュータサイエンスの重要な分野であり、長年の歴史を持ち、近年では言語間コンパイルの隆盛やDSL概念の普及なども相まって、さまざまな汎用言語が次々と登場しています。 、コンパイラは非常に重要な分野になっています。

コンパイラ分野に関連する 3 つの古典的な書籍として知られています。Dragon Book「Compilers: Principles, Techniques, and Tools」、Tiger Book「X での最新のコンパイラ実装 (X はさまざまな言語を表します)」、およびクジラの本「高度なコンパイラの設計と実装」。その中で、Dragon Book はコンパイル理論に最適な選択肢として認識されていますが、後者の 2 つは実践にとってより有益です。さらに、@assemblerhead にはコンパイラに関する優れた入門ブログ シリーズがあります: http://www.cnblogs.com/Ninputer/archive/2011/06/07/2074632.html

コンパイラの基本プロセスは次のとおりです。

字句解析、構文解析、意味解析はコンパイラのフロントエンドとも呼ばれ、その後のターゲット生成や最適化などに至る中間コード生成までを指します。コンパイルに属します サーバーのバックエンド。コンパイラのフロントエンド テクノロジは非常に成熟しており、字句解析や構文解析を自動的に実行する yacc のようなツールがあります (Java には同様のツール ANTLR があります)。一方、バックエンド テクノロジはより複雑であり、現在注目されています。コンパイラの研究。

以上を述べたので、HTML に戻りましょう。 HTML は宣言型言語であり、その最終出力は実行可能なターゲット言語ではなく、ブラウザーのグラフィカル ページであることが理解できるため、ここでは Translate を Render に変更しました。

Jsoup (同様の HTML パーサーを含む) では、Lex (字句解析) と Parse (文法解析) の 2 ステップのみが実行され、HTML パースの最終出力結果は DOM ツリーになります。 。 HTML のセマンティック解析とレンダリングについては、Ctrip UED チームによる記事「ブラウザの仕組み: レンダリング エンジン、HTML 解析」を読むとよいでしょう。

ステート マシン

Jsoup の字句解析と構文解析は両方ともステート マシンを使用します。ステート マシンは、たとえば、私たちがよく扱う正規表現はステート マシンを使用して実装される特別なプログラム モデルとして理解できます。

これは、状態と遷移の 2 つの部分で構成されます。状態遷移の可能性に応じて、ステート マシンは DFA (決定的有限状態マシン) と NFA (非決定的有限状態マシン) に分類されます。ここでは例として最も単純な正規表現「a[b]*」を示します。まずこれをステート マシン DFA にマッピングします。これは次のようになります。

ステート マシン自体です。プログラミング モデル ここでは、プログラムを使用して実装してみます。最も直接的な方法はおそらく次のとおりです。

public void process(StringReader reader) throws StringReader.EOFException { char ch; switch (state) { case Init: ch = reader.read(); if (ch == 'a') { state = State.AfterA; accum.append(ch); } break; case AfterA: ... break; case AfterB: ... break; case Accept: ... break; }}

このような単純なステート マシンを作成することに問題はありませんが、少し面倒です。複雑な状況では不快です。標準的なステート マシンのソリューションもあります。これは、最初に状態遷移テーブルを作成し、次にこのテーブルを使用してステート マシンを構築します。この方法の問題は、純粋な状態転送しか実行できず、コード レベルで入出力を操作できないことです。

Jsoup ではステート パターンを使用してステート マシンを実装しています。初めて見たとき、とても目を引きました。状態パターンは、状態と対応する動作をバインドする設計パターンの一種です。ステートマシンの実装過程では、ステート転送処理を実装するために使用するのが最適です。

「a[b]*」例の状態モードは次のように実装されます。ここでは Jsoup と同じメソッドが使用され、列挙を使用して状態モードを実装します。 PS: 私は github で Jsoup コードをフォークし、このシリーズの記事を投稿し、いくつかのコードに中国語のコメントを追加しました。興味がある場合は、https://github.com/code4craft/jsoup-learning をチェックしてください。この記事で説明されているいくつかのステート マシンの完全な実装は、このリポジトリのパス https://github.com/code4craft/jsoup-learning/tree/master/src/main/java/us/codecraft/learning の下にあります。

public class StateModelABStateMachine implements ABStateMachine {State state;StringBuilder accum;enum State { Init { @Override public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException { char ch = reader.read(); if (ch == 'a') { stateModelABStateMachine.state = AfterA; stateModelABStateMachine.accum.append(ch); } } }, Accept { ... }, AfterA { ... }, AfterB { ... };public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException { } }public void process(StringReader reader) throws StringReader.EOFException { state.process(this, reader); }}
次の記事では、Jsoup 字句解析から始めて、ステート マシンの使用について説明します。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。