@IT」にはない内容をエンジニアライフで技術紹介するコラム。広く議論する場になることを目指します。2018/01/29前回、前々回に引き続いてEntityDeclについて議論します。今回は、構文解析器が実体参照を発見したときの動作について読んでいきます。出現した位置のW3Cの勧告内容W3Cの勧告でも良いまとめ方をした部分と思いますが、仕様とするにはいま一歩な気がしますのでさらにまとめていきます。説明した箇所もありますが、仕様整理のためにすべて読んでいきます。実体参照の動作は、出現した位置(最左端の縦のキー項目)と出現した実体参照の種類(最左端以外の横のキー項目)の2次元テーブルで説明しています。「出現した位置」についてのキー項目の意味とキーが交わるテーブル内の内容となります。実体参照の種類についてはこれまでのW3Cの説明にあるので説明がありません。「出現した位置」についての説明から見ていきましょう。呼び出しが現れる文脈と、それぞれの文脈に対するXMLプロセッサに要求される振る舞いを要約したものである。左左端の列は、認識する文脈を意味する。要素の開始タグの後ろから終了タグの前のどこにでも参照として現れる。非終端contentに対応する。開始タグ内の属性値もしくは属性リスト宣言のデフォルト値の中の参照として現れる。;非終端AttValueに対応する。属性値としての名前Nameとして、参照ではなく、ENTITY型として宣言された属性値の値として現れるか、ENTITIES型として宣言された属性値のスペースで区切られたトークンの一つとして現る。実体値の中での参照パラメータ実体のリテラルまたは内部一般実体のリテラル-実体宣言のEntityValueの参照として現れる。;非終端EntityValueに対応する。DTDの中での参照EntityValue、AttValue、PI、Comment、SystemLiteral,PubidLiteral、条件付セクションのignoreの内容(3.4条件付セクション参照)のいずれでもない内部サブセットDTDまたは外部サブセットDTDの中に参照として現れる。----日本語訳----表は次のようになります。許されない----日本語訳----表の内容についてそれぞれ見ていきます。認識しないDTDの外では、%文字は特別なシグネチャにならない。DTDの中でパラメータ実体参照になる文字列は、contentの中のマークアップでは認識しない。同様に、解析対象外実体の名前は、適切に宣言された属性の値以外に現れる場合を除いて、認識しない。実体は、実体値となる置換テキストを入手して処理した時、参照先にインクルードする。インクルードした結果は、あたかも文書中でその参照を認識した場所に、最初から置換テキストがあったように処理する。置換テキストは、文字データとマークアップの両方を含むことができる。(但しパラメータ実体はマークアップを含む事はできない)。(例えば、文字列"AT&amp;T;"は"AT&T;"に展開する。後者の文字列に残ったアンパサンドは実体参照の区切り子とは認識しない。)文字参照は、その参照そのものがあった場所に文字参照が意味する文字を処理するときにインクルードする。妥当性を検証時展開XMLプロセッサが解析対象実体の参照を認識したとき、文書の妥当性を検証するために、プロセッサは置換テキストをインクルードしなければならない。外部解析対象実体の場合で、かつ、プロセッサがXML文書の妥当性を検証しようとしない場合、置換テキストをインクルードしても良いが、インクルードする必要があるわけではない。認識したが読まなかったことをアプリケーションに通知しなければならない。この規則はSGMLとXMLの実体メカニズムによる(提供された)自動インクールドが、主に文書作成時のモジュール分割を可能とするためにデザインしてあるのに対して、必ずしも他のアプリケーションにとっては適切でない(特に文書のブラウジング)という認識に基づいている。ブラウザは外部解析対象実体に遭遇すると、その実体参照への視覚的な情報を提供し、表示する要求があった場合にだけ実体の参照先の情報を検索してよい。以下のものは許されない、致命的なエラーになる。解析対象外実体に対する参照が現れた場合、ただし、実体宣言のEntityValueに現れた場合は除く。実体参照が属性値の中に現れたとき、または、パラメータ実体の参照がリテラル実体値の中に現れたとき、その置換テキストは、まるで参照を認識した文書中の部分に存在するかのごとく、その参照を入れ替えなければいけない。)は常に普通の文字データとして扱わなければいけない。置換テキストの中の引用符がリテラルを終了してはいけない。次の例は整形式である。>次の例は整形式ではない。実体と関連付けられた記法のシステム識別子と(もしあれば)公開識別子をアプリケーションに通知しなければならない。バイパスする一般実体参照が実体宣言のEntityValueに現れた場合、バイパスして、そのままの状態にしておかなければならない。妥当性を検証する場合インクルードする]と同じ制限がある。パラメータ実体の参照がDTD内で認識され、インクルードする場合、置換テキストの先頭と末尾に#x20のスペース文字を追加しなければいけない。;これにより、DTDの中の文法トークンの必要数を含んだパラメータ実体の置換テキストを構成する。この動作は実体値の中のパラメータ実体参照には適用してはいけない。解析対象外実体への参照が実体宣言のEntityValueの中で現れた場合、エラーとする。仕様について整理する前に文言や記述内容について整理します。内部/外部サブセット上の処理となります。条件付セクションのignoreの内容を除く、内部/外部サブセット上の処理となります。"認識しない"について構文解析器でただの文字列として扱うので意識する必要はありません。処理は何もありません。構文解析器によって文脈上で文字参照/実体参照を認識したときは、4.4.2~4.4.9の仕様に従って処理します。一方で、文字参照/実体参照の表現があっても、構文解析器がその文脈によって文字参照/実体参照を認識しないときは、それは文字データかそれ以外の何かに認識するため、文字参照や実体参照としての仕様は意識する必要はありません。/内容、文字参照/内容、文字参照/AttValue、文字参照/EntityValueの4箇所に出てきます。置換テキストは、文字データとマークアップの両方を含むことができる。(但しパラメータ実体はマークアップを含む事はできない)。マークアップは、いつも通りに認識するは、構文EntityValueの定義に関する内容です。よって、実体参照の認識時の動作の仕様としては無視します。文字参照の説明「文字参照が意味する文字を処理するとき」の2つの表現です。この2つの表現が意味するところはいつなのでしょうか?つまり、そもそもの「処理するとき」とはいつなのかがわかりません。本コラムではこれを「認識したとき」とします。どのタイミングなのかが判断できません。私なら、recognizedと書くと思います。ここからは推測になります。バイパスするとは異なる内容を持ちます。認識した後でかつバイパスしないように処理します。hogehoge&sample;&sample2;fugafugaという入力があり、&sample;を認識し、置換テキストに置き換えずに、次のトークン&sample2;の解析に移ったとすると、もはや構文解析器は&sample;に対して入力の終わりまでなんらかの処理を行うタイミングを失います。認識したときにすぐに処理するか入力を構文解析しおわったときに処理するかの2択になります。▼仕様を決定するさて、2つの側面からの推測を行いました。どちらかが間違っているということはありません(少なくともW3Cの説明からは分かりません)。そこで、どちらでもよいのならモジュール構成や処理コストで判断します。モジュール構成について考えると、実体参照の認識処理は意味解析を意味しています。実体参照の置換テキスト内をさらに構文解析することまで考慮すると、構文解析の文脈を探す処理と考えてもよさそうです。次に、処理コストでいうとあまり細かく触れませんが、認識してすぐに処理したほうが少なく済みます。よって、「認識したときにすぐに処理する」ことにします。●先に文字参照の定義から処理を検討する次に4.4.2の例の注意点を考えるために、文字参照の処理を理解しておくことが必要です。そこで文字参照から検討します。文字参照は、その参照そのものがあった場所に文字参照が意味する文字を処理するときにインクルードする。(RepText)とする。(RepText)とする。(RepText)とする。(例えば、文字列"AT&amp;T;"は"AT&T;"に展開する。後者の文字列に残ったアンパサンドは実体参照の区切り子とは認識しない。構文解析器は入力バッファ"AT&amp;T;"を前方からトークンに分け、処理します。4.4.2で説明する実体はcontentの処理ですから、この場合に使用する条件付字句解析器はNormalSectionで、対応するEBNFデータツリーはcontentであることが分かります。"&#38;#38;">を意味します。(&)に置き換えます。(#38;)を得ます。実体参照の区切り子として認識しません。&#38;登録します。参照先にインクルードする。最初から置換テキストがあったように処理する。あるなら、置換テキストRepTextを取得する。(RepText)を得る。定義から導出した処理を使って例を検証します。(例えば、文字列"AT&amp;T;"は"AT&T;"に展開する。入力バッファ[AT&amp;T;]に対して出力[AT&T]を得ます。