本家「@IT」にはない内容をエンジニアライフで技術紹介するコラム。広く議論する場になることを目指します。

第054回_EntityDecl_実体参照時の動作

»
前回、前々回に引き続いてEntityDeclについて議論します。

今回は、構文解析器が実体参照を発見したときの動作について読んでいきます。

出現した位置のW3Cの勧告内容

W3Cの勧告でも良いまとめ方をした部分と思いますが、仕様とするにはいま一歩な気がしますのでさらにまとめていきます。

既に説明した箇所もありますが、仕様整理のためにすべて読んでいきます。

実体参照の動作は、出現した位置(最左端の縦のキー項目)と出現した実体参照の種類(最左端以外の横のキー項目)
の2次元テーブルで説明しています。

説明が必要となるのは、
 「出現した位置」についてのキー項目の意味

 キーが交わるテーブル内の内容
となります。
実体参照の種類についてはこれまでのW3Cの説明にあるので説明がありません。
では、「出現した位置」についての説明から見ていきましょう。

----W3C勧告----
4.4 XML Processor Treatment of Entities and References

The table below summarizes the contexts in which character references, entity references, and invocations of unparsed entities might appear and the required behavior of an XML processor in each case. The labels in the leftmost column describe the recognition context:

Reference in Content
as a reference anywhere after the start-tag and before the end-tag of an element; corresponds to the nonterminal content.

Reference in Attribute Value
as a reference within either the value of an attribute in a start-tag, or a default value in an attribute declaration; corresponds to the nonterminal AttValue.

Occurs as Attribute Value
as a Name, not a reference, appearing either as the value of an attribute which has been declared as type ENTITY, or as one of the space-separated tokens in the value of an attribute which has been declared as type ENTITIES.

Reference in Entity Value
as a reference within a parameter or internal entity's literal entity value in the entity's declaration; corresponds to the nonterminal EntityValue.

Reference in DTD
as a reference within either the internal or external subsets of the DTD, but outside of an EntityValue, AttValue,PI, Comment, SystemLiteral, PubidLiteral, or the contents of an ignored conditional section(see 3.4 Conditional Sections).
----W3C勧告----
----日本語訳----
4.4 XMLプロセッサにおける実体と参照の扱い

次に上げる表は、文字参照、実体参照、解析対象外実体を呼び出しが現れる文脈と、それぞれの文脈に対するXMLプロセッサに要求される振る舞いを要約したものである。左左端の列は、認識する文脈を意味する。;

内容の中での参照
要素の開始タグの後ろから終了タグの前のどこにでも参照として現れる。; 非終端contentに対応する。

属性値の中での参照
開始タグ内の属性値もしくは属性リスト宣言のデフォルト値の中の参照として現れる。;非終端AttValueに対応する。

属性値としての名前
Nameとして、参照ではなく、ENTITY型として宣言された属性値の値として現れるか、ENTITIES型として宣言された属性値のスペースで区切られたトークンの一つとして現る。

実体値の中での参照
パラメータ実体のリテラルまたは内部一般実体のリテラル-実体宣言のEntityValueの参照として現れる。;非終端EntityValueに対応する。

DTDの中での参照
EntityValue、AttValue、PI、Comment、SystemLiteral,PubidLiteral、条件付セクションのignoreの内容(3.4条件付セクション参照)のいずれでもない内部サブセットDTDまたは外部サブセットDTDの中に参照として現れる。
----日本語訳----

表は次のようになります。(表の内容は後程説明します)
----W3C勧告----


Entity Type Character
Parameter Internal General External Parsed General Unparsed
Reference in Content Not recognized Included Included if validating Forbidden Included
Reference in Attribute Value Not recognized Included in literal Forbidden Forbidden Included
Occurs as Attribute Value Not recognized Forbidden Forbidden Notify Not recognized
Reference in EntityValue Included in literal Bypassed Bypassed Error Included
Reference in DTD Included as PE Forbidden Forbidden Forbidden Forbidden
----W3C勧告----
----日本語訳----


実体の種類 文字参照
パラメータ実体 内部一般実体 外部解析対象一般実体 解析対象外実体
内容の中での参照 認識されない インクルードされる 妥当性を検証する場合インクルードされる 許されない インクルードされる
属性値の中での参照 認識されない リテラルの中でインクルードされる 許されない 許されない インクルードされる
属性値としての名前 認識されない 許されない 許されない 通知する 認識されない
実体値の中での参照 リテラルの中でインクルードされる バイパスされる バイパスされる エラー インクルードされる
DTDの中での参照 パラメータ実体としてインクルードされる 許されない 許されない 許されない 許されない
----日本語訳----

表の内容についてそれぞれ見ていきます。
----W3C勧告----
4.4.1 Not Recognized
Outside the DTD, the % character has no special significance; thus, what would be parameter entity references in the DTD are not recognized as markup in content. Similarly, the names of unparsed entities are not recognized except when they appear in the value of an appropriately declared attribute.

4.4.2 Included
[Definition: An entity is included when its replacement text is retrieved and processed, in place of the reference itself, as though it were part of the document at the location the reference was recognized.] The replacement text may contain both character data and (except for parameter entities) markup, which must be recognized in the usual way. (The string "AT&T;" expands to "AT&T;" and the remaining ampersand is not recognized as an entity-reference delimiter.) A character reference is included when the indicated character is processed in place of the reference itself.

4.4.3 Included If Validating
When an XML processor recognizes a reference to a parsed entity, in order to validate the document, the processor must include its replacement text. If the entity is external, and the processor is not attempting to validate the XML document, the processor may, but need not, include the entity's replacement text. If a non-validating processor does not include the replacement text, it must inform the application that it recognized, but did not read, the entity. This rule is based on the recognition that the automatic inclusion provided by the SGML and XML entity mechanism, primarily designed to support modularity in authoring, is not necessarily appropriate for other applications, in particular document browsing. Browsers, for example, when encountering an external parsed entity reference, might choose to provide a visual indication of the entity's presence and retrieve it for display only on demand.
----W3C勧告----
----日本語訳----
4.4.1 認識しない
DTDの外では、%文字は特別なシグネチャにならない。; つまり、DTDの中でパラメータ実体参照になる文字列は、contentの中のマークアップでは認識しない。同様に、解析対象外実体の名前は、適切に宣言された属性の値以外に現れる場合を除いて、認識しない。

4.4.2 インクルードされる
[定義: 実体は、実体値となる置換テキストを入手して処理した時、参照先にインクルードする。インクルードした結果は、あたかも文書中でその参照を認識した場所に、最初から置換テキストがあったように処理する。] 置換テキストは、文字データとマークアップの両方を含むことができる。(但しパラメータ実体はマークアップを含む事はできない)。マークアップは、いつも通りに認識する (例えば、文字列"AT&T;"は"AT&T;"に展開する。後者の文字列に残ったアンパサンドは実体参照の区切り子とは認識しない。)文字参照は、その参照そのものがあった場所に文字参照が意味する文字を処理するときにインクルードする。

4.4.3 妥当性を検証時展開
XMLプロセッサが解析対象実体の参照を認識したとき、文書の妥当性を検証するために、プロセッサは置換テキストをインクルードしなければならない。 外部解析対象実体の場合で、かつ、プロセッサがXML文書の妥当性を検証しようとしない場合、置換テキストをインクルードしても良いが、インクルードする必要があるわけではない。妥当性を検証しないプロセッサが置換テキストをインクルードしない場合、外部解析対象実体を認識したが読まなかったことをアプリケーションに通知しなければならない。


この規則は
SGMLとXMLの実体メカニズムによる(提供された)自動インクールドが、主に文書作成時のモジュール分割を可能とするためにデザインしてあるのに対して、必ずしも他のアプリケーションにとっては適切でない(特に文書のブラウジング)
という認識に基づいている。
例えば、ブラウザは外部解析対象実体に遭遇すると、その実体参照への視覚的な情報を提供し、表示する要求があった場合にだけ実体の参照先の情報を検索してよい。
----日本語訳----

----W3C勧告----
4.4.4 Forbidden
The following are forbidden, and constitute fatal errors:
  • the appearance of a reference to an unparsed entity, except in the EntityValue in an entity declaration.
  • the appearance of any character or general-entity reference in the DTD except within an EntityValue or AttValue.
  • a reference to an external entity in an attribute value.

4.4.5 Included in Literal
When an entity reference appears in an attribute value, or a parameter entity reference appears in a literal entity value, its replacement text must be processed in place of the reference itself as though it were part of the document at the location the reference was recognized, except that a single or double quote character in the replacement text must always be treated as a normal data character and must not terminate the literal.
For example, this is well-formed:
 <!ENTITY % YN '"Yes"' >
 <!ENTITY WhatHeSaid "He said %YN;" >

while this is not:
 <!ENTITY EndAttr "27'" >
 <element attribute='a-&EndAttr;>
----W3C勧告----
----日本語訳----
4.4.4 禁止
以下のものは許されない、致命的なエラーになる。
  • 解析対象外実体に対する参照が現れた場合、ただし、実体宣言のEntityValueに現れた場合は除く。
  • AttValueとEntittyValueを除いたDTDの中に、文字参照または一般実体参照が現れた場合
  • 属性値の中に外部実体の参照が有る場合

4.4.5 リテラル内で展開
実体参照が属性値の中に現れたとき、または、パラメータ実体の参照がリテラル実体値の中に現れたとき、その置換テキストは、まるで参照を認識した文書中の部分に存在するかのごとく、その参照を入れ替えなければいけない。ただし、置換テキストの中の引用符(単引用符、二重引用符)は常に普通の文字データとして扱わなければいけない。また、置換テキストの中の引用符がリテラルを終了してはいけない。
次の例は整形式である。
 <!ENTITY % YN '"Yes"' >
 <!ENTITY WhatHeSaid "He said %YN;" >

次の例は整形式ではない。
 <!ENTITY EndAttr "27'" >
 <element attribute='a-&EndAttr;>
----日本語訳----

----W3C勧告----
4.4.6 Notify
When the name of an unparsed entity appears as a token in the value of an attribute of declared type ENTITY or ENTITIES, a validating processor must inform the application of the system and public (if any) identifiers for both the entity and its associated notation.

4.4.7 Bypassed
When a general entity reference appears in the EntityValue in an entity declaration, it must be bypassed and left as is.

4.4.8 Included as PE
Just as with external parsed entities, parameter entities need only be included if validating.When a parameter-entity reference is recognized in the DTD and included, its replacement text must be enlarged by the attachment of one leading and one following space (#x20) character; the intent is to constrain the replacement text of parameter entities to contain an integral number of grammatical tokens in the DTD. This behavior must not apply to parameter entity references within entity values; these are described in 4.4.5 Included in Literal.

4.4.9 Error
It is an error for a reference to an unparsed entity to appear in the EntityValue in an entity declaration.
----W3C勧告----
----日本語訳----
4.4.6 通知する
解析対象外実体のNameがENTITY型またはENTITIESの属性値にトークンとして現れた場合、
妥当性を検証するプロセッサは、
 その実体のシステム識別子と(もしあれば)公開識別子
 実体と関連付けられた記法のシステム識別子と(もしあれば)公開識別子
をアプリケーションに通知しなければならない。

4.4.7 バイパスする
一般実体参照が実体宣言のEntityValueに現れた場合、バイパスして、そのままの状態にしておかなければならない。

4.4.8 パラメータ実体としてインクルードされる
外部解析対象実体と同じように、パラメータ実体は[4.4.3 妥当性を検証する場合インクルードする]と同じ制限がある。パラメータ実体の参照がDTD内で認識され、インクルードする場合、置換テキストの先頭と末尾に#x20のスペース文字を追加しなければいけない。;
これにより、DTDの中の文法トークンの必要数を含んだパラメータ実体の置換テキストを構成する。
この動作は実体値の中のパラメータ実体参照には適用してはいけない。;
この動作についての説明は、4.4.5リテラルの中でのインクルード にて記述してある。

4.4.9 エラー
解析対象外実体への参照が実体宣言のEntityValueの中で現れた場合、エラーとする。
----日本語訳----

文言・記述内容の整理

仕様について整理する前に文言や記述内容について整理します。
-表の左端列の項目について
1.内容の中での処理
2.属性値の中での処理
3.属性値での実体参照をすべて展開したあとの値に関する処理
4.実体値の中での処理
5.EntityValue、AttValue、PI、Comment、SystemLiteral、PubidLiteral、 条件付セクションのignoreの内容を除く 内部/外部サブセット上の処理

となります。ただし、属性値は、
 属性リスト宣言のデフォルト値 と 開始タグの中の属性値
の2つがあるのでこれを分けると、

1.内容の中での処理
2-1.属性リスト宣言のデフォルト値の中での処理
2-2.開始タグの中の属性値の中での処理
3-1.属性リスト宣言のデフォルト値の実体参照をすべて展開したあとの値に関する処理
3-2.開始タグの中の属性値の実体参照をすべて展開したあとの値に関する処理
4.実体値の中での処理
5.EntityValue、AttValue、PI、Comment、SystemLiteral、PubidLiteral、 条件付セクションのignoreの内容を除く、内部/外部サブセット上の処理
となります。

-4.4.1 "認識しない"について
構文解析器でただの文字列として扱うので意識する必要はありません。
# 処理は何もありません。

つまり、構文解析器によって文脈上で文字参照/実体参照を認識したときは、
4.4.2~4.4.9の仕様に従って処理します。
一方で、文字参照/実体参照の表現があっても、構文解析器がその文脈によって文字参照/実体参照を認識しないときは、それは文字データかそれ以外の何かに認識するため、文字参照や実体参照としての仕様は意識する必要はありません。

-4.4.2 "インクルードされる"について
4.4の表において"インクルードされる"は、
内部・解析対象・一般実体/内容、文字参照/内容、文字参照/AttValue、文字参照/EntityValue
の4箇所に出てきます。

●余分な文を削除して仕様をスッキリする
原文において、
置換テキストは、文字データとマークアップの両方を含むことができる。
(但しパラメータ実体はマークアップを含む事はできない)。
マークアップは、いつも通りに認識する
は、構文EntityValueの定義に関する内容です。
よって、実体参照の認識時の動作の仕様としては無視します。


●表現に関する分析
この文で意味が分からない表現は、
 実体値の説明「実体値となる置換テキストを入手して処理した時」
と、
 文字参照の説明「文字参照が意味する文字を処理するとき」
の2つの表現です。

この2つの表現が意味するところはいつなのでしょうか?つまり、そもそもの「処理するとき」とはいつなのかがわかりません。
本コラムではこれを「認識したとき」とします。
# processedについて明確な定義があれば良いのですが、それがなく、
# 単純にprocessedと書くとプログラムは全ての工程が処理なので、
# どのタイミングなのかが判断できません。
# もし私なら、recognizedと書くと思います。

ここからは推測になります。

▼タイトルの違いからみる推測
4.4.2 "インクルードされる"は、
 4.4.1 認識しない

 4.4.7 バイパスする
とは異なる内容を持ちます。つまり、認識した後でかつバイパスしないように処理します。

▼Contentの処理から見る推測
Contentの中で 例えば、
 hogehoge&sample;&sample2;fugafuga
という入力があり、&sample;を認識し、置換テキストに置き換えずに、次のトークン&sample2;の解析に移ったとすると、もはや構文解析器は&sample;に対して入力の終わりまでなんらかの処理を行うタイミングを失います。
要するに、
 認識したときにすぐに処理する

 入力を構文解析しおわったときに処理する
かの2択になります。

▼仕様を決定する
さて、2つの側面からの推測を行いました。どちらかが間違っているということはありません(少なくともW3Cの説明からは分かりません)。そこで、どちらでもよいのならモジュール構成や処理コストで判断します。

まず、モジュール構成について考えると、実体参照の認識処理は意味解析を意味しています。ただし、実体参照の置換テキスト内をさらに構文解析することまで考慮すると、構文解析の文脈を探す処理と考えてもよさそうです。

次に、処理コストでいうとあまり細かく触れませんが、認識してすぐに処理したほうが少なく済みます。
よって、「認識したときにすぐに処理する」ことにします。


●先に文字参照の定義から処理を検討する
次に4.4.2の例の注意点を考えるために、文字参照の処理を理解しておくことが必要です。
そこで文字参照から検討します。

原文における、
 # 文字参照は、その参照そのものがあった場所に文字参照が意味する文字を処理するときにインクルードする。
について考えます。


構文解析器がcontent処理中に、文字参照を認識したとき(★)
ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得て、これをCharData (RepText)とする。
#
# ★についての補足
# SYMBOL (&#) WORD ([0-9]+) SYMBOL (;)
# または、
# SYMBOL (&#x) WORD ([0-9a-fA-F]+) SYMBOL (;)
# のトークンリストが構文解析でOKになったとき、
#

構文解析器がAttValue処理中に、文字参照を認識したとき
ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得て、
これをNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)とする。

構文解析器がEntityValue処理中に、文字参照を認識したとき
ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得て、
これをNORMAL_TOKEN_B1 (RepText)または、NORMAL_TOKEN_B2 (RepText)とする。



●例の注意点
原文における、
 # (例えば、文字列"AT&amp;T;"は"AT&T;"に展開する。
 # 後者の文字列に残ったアンパサンドは実体参照の区切り子とは認識しない。)
について考えます。 構文解析器は入力バッファ"AT&amp;T;"を前方からトークンに分け、処理します。
尚、4.4.2で説明する実体はcontentの処理ですから、
この場合に使用する条件付字句解析器はNormalSectionで、対応するEBNFデータツリーはcontentであることが
分かります。

また、&amp;は 4.6 定義済み実体で説明がある内容で、
 <!ENTITY amp "&#38;#38;">
を意味します。
さらに、この置換テキスト(&#38;)は実体宣言の解析でEntityValueを読み込むときに、
 SYMBOL (&#) WORD (38) SYMBOL (;) 未処理バッファ[#38;]
を解析し、これをNORMAL_TOKEN_B1 (&)に置き換えます。

よって、残りの未処理バッファを解析すると、
 NORMAL_TOKEN_B1 (&) NORMAL_TOKENB1 (#38;)
を得ます。
#
# 自ら自分の定義を証明するようですが、
# この文字列に残った & は、実体参照の区切り子として認識しません。
#

最終的に、一般実体テーブルに、
 Key | 置換テキスト
 ------------------------
 amp | &#38;
登録します。


●一般実体の定義から導出する処理
原文における、
 # [定義: 実体は、実体値となる置換テキストを入手して処理した時、
 # 参照先にインクルードする。
 # インクルードした結果は、あたかも文書中でその参照を認識した場所に、
 # 最初から置換テキストがあったように処理する。]
について考えます。

構文解析器がcontent処理中に、一般実体の参照を認識したとき、
一般実体のトークンの中のWORD (Name)をkeyに一般実体テーブルを検索し、それが内部・解析対象・一般実体であるなら、置換テキストRepTextを取得する。一般実体のトークン列 SYMBOL (&) WORD (Name) SYMBOL (;)の代わりにCharData (RepText)を得る。


●例を用いた検証
定義から導出した処理を使って例を検証します。

原文
 # (例えば、文字列"AT&amp;T;"は"AT&T;"に展開する。
なので、
 入力バッファ[AT&amp;T;]に対して出力[AT&T]
を得ます。

検証
1. CharData (AT) 未処理バッファ[&T;]
2. CharData (AT) SYMBOL (&) 未処理バッファ[amp;T; ]
3. CharData (AT) SYMBOL (&) WORD (amp) 未処理バッファ[;T; ]
4. CharData (AT) SYMBOL (&) WORD (amp) SYMBOL (;) 未処理バッファ[T; ]
5. CharData (AT) SYMBOL (&) WORD (amp) SYMBOL (;) CharData (T;)
6. 一般実体の参照を検知したので、処理する
6-1. 一般実体テーブルをkey (amp)で検索する
6-2. 置換テキスト "&#38;" を得る
6-3. (4.3.2整形式の解析対象実体で説明したように)置換テキストをcontentにマッチするか確認する
6-3-1. 置換テキストを、 SYMBOL (&#) WORD (38) SYMBOL (;) に構文解析する。
6-3-2. 文字参照/contentを検知したので、CharData (&)に置き換える。
6-4. 置換テキストCharData (&)を得る
7. CharData (AT) CharData (&) CharData (T;)
 →出力[AT&T;] を得たので検証成功とする。

-4.4.3 "妥当性を検証時展開"について
これは前々回の説明で、
 妥当性を検証しないプロセッサ
  外部解析対象実体の参照:置換テキストをインクルードする
  または、インクルードしない場合は、読み込まなかった旨をアプリケーションに伝える

 妥当性を検証するプロセッサ
  外部解析対象実体の参照:置換テキストをインクルードする
と説明したので、次のように整理できます。


●妥当性を検証しないプロセッサ
構文解析器がcontent処理中に、一般実体の参照を認識したとき、
1-1.一般実体のトークンの中のWORD (Name)をkeyに一般実体テーブルを検索する。
1-2.実体が外部・解析対象・一般実体であるなら、置換テキストRepTextを取得する。
1-3.一般実体のトークン列 SYMBOL (&) WORD (Name) SYMBOL (;)の代わりにCharData (RepText)を得る。
または、
2-1. 一般実体のトークン列をそのままに、読み込まなかった旨をアプリケーションに通知する。

●妥当性を検証するプロセッサ
構文解析器がcontent処理中に、一般実体の参照を認識したとき、
1-1.一般実体のトークンの中のWORD (Name)をkeyに一般実体テーブルを検索する。
1-2.実体が外部・解析対象・一般実体であるなら、置換テキストRepTextを取得する。
1-3.一般実体のトークン列 SYMBOL (&) WORD (Name) SYMBOL (;)の代わりにCharData (RepText)を得る。

-4.4.4 "禁止"について
原文
 # 以下のものは許されない、致命的なエラーになる。
 # ・解析対象外実体に対する参照が現れた場合、
 # ただし、実体宣言のEntityValueに現れた場合は除く。
 # ・AttValueとEntittyValueを除いたDTDの中に、
 # 文字参照または一般実体参照が現れた場合
 # ・属性値の中に外部実体の参照が有る場合
の1つ目と3つ目から、次のようにできます。


・構文解析器がcontent処理中に、一般実体の参照を認識したとき、
 一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、
 それが外部・解析対象外・一般実体であるなら、致命的エラーとする。


・構文解析器が属性リスト宣言のデフォルト値の処理中に、一般実体の参照を認識したとき、
 一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、
 それが外部・解析対象外・一般実体であるなら、致命的エラーとする。


・構文解析器が開始タグの中の属性値の処理中に、一般実体の参照を認識したとき、
 一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、
 それが外部・解析対象外・一般実体であるなら、致命的エラーとする。


・構文解析器が属性リスト宣言のデフォルト値の処理中に、一般実体の参照を認識したとき、
 一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、
 それが外部・解析対象・一般実体であるなら、致命的エラーとする。


・構文解析器が開始タグの中の属性値の処理中に、一般実体の参照を認識したとき、
 一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、
 それが外部・解析対象・一般実体であるなら、致命的エラーとする。

尚、2つ目についてはDTDの中で構文に現れないパラメータ実体参照を念頭に書かれたものであるため、構文にはないにせよ、実装方法によっては、文字参照や一般実体参照を認識するかもしれず、その場合を考慮に入れて書いてあります。本コラムが作成するプログラムは、文字参照や一般実体参照を認識しないように実装するのでここの仕様を実装することはありません。

-4.4.5 "リテラルの中で展開"について
この項の内容は、4.4の表における、
 内部・解析対象・パラメータ実体/EntityValue
 内部・解析対象・一般実体/AttValue
を説明しています。

また、置換テキストにある引用符をリテラルとして扱う例がありますので、
処理をまとめた上で例をつかって検証します。
●処理
・構文解析器がEntityValue処理中に、パラメータ実体の参照を認識したとき、
パラメータ実体のトークンの中のWORD (Name)をkeyにパラメータ実体テーブルを検索し、それがパラメータ実体であるなら、置換テキストRepTextを取得する。
パラメータ実体のトークン列 SYMBOL (%) WORD (Name) SYMBOL (;)の代わりにNORMAL_TOKEN_B1 (RepText)または、NORMAL_TOKEN_B2 (RepText)を得る。
・構文解析器がAttValue処理中に、一般実体の参照を認識したとき、
一般実体のトークンの中のWORD (Name)をkeyに一般実体テーブルを検索し、それが内部・解析対象・一般実体であるなら、置換テキストRepTextを取得する。
一般実体のトークン列 SYMBOL WORD (Name) SYMBOL (;)の代わりにNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)を得る。


●例を用いた検証
定義から導出した処理を使って例を検証します。

原文
 # <!ENTITY % YN '"Yes"' >
 # <!ENTITY WhatHeSaid "He said %YN;" >
なので、
 入力バッファ[He said %YN;]に対して出力[He said "Yes"]を得る。

検証1
パラメータ実体テーブル
 Key | 置換テキスト
 ------------------------
 YN | "Yes"

1. NORMAL_TOKEN_B1 (He said ) 未処理バッファ[YN;]

2. NORMAL_TOKEN_B1 (He said ) SYMBOL (
) 未処理バッファ[YN;]
3. NORMAL_TOKEN_B1 (He said ) SYMBOL (%) WORD (YN) 未処理バッファ[;]
4. NORMAL_TOKEN_B1 (He said ) SYMBOL (%) WORD (YN) SYMBOL (;)
5. パラメータ実体の参照を検知したので、処理する
5-1. パラメータ実体テーブルをkey (YN)で検索する
5-2. 置換テキスト "Yes" を得る
5-3. 置換テキストNORMAL_TOKEN_B1 ("Yes")を得る
6. NORMAL_TOKEN_B1 (He said ) NORMAL_TOKEN_B1 ("Yes")
 →出力[He said "Yes"] を得たので検証成功とする。

検証2
 # 次の例は整形式ではない。
 #
 # <!ENTITY EndAttr "27'" >
 # <element attribute='a-&EndAttr;>

 実体テーブル
 Key | 置換テキスト
 ------------------------
 EndAttr | 27'

1. NORMAL_TOKEN_A2 (a-) 未処理バッファ[&EndAttr;>]
2. NORMAL_TOKEN_A2 (a-) SYMBOL (&) 未処理バッファ[EndAttr;>]
3. NORMAL_TOKEN_A2 (a-) SYMBOL (&) WORD (EndAttr) 未処理バッファ[;>]
4. NORMAL_TOKEN_A2 (a-) SYMBOL (&) WORD (EndAttr) SYMBOL (;) 未処理バッファ[>]
5. 一般実体の参照を検知したので、処理する
5-1. 一般実体テーブルをkey (EndAttr)で検索する
5-2. 置換テキスト 27' を得る
#次々回に説明する処理が本来は必要!
5-3. 置換テキストNORMAL_TOKEN_A2 (27')を得る※'はAttValueの終りと認識しない
6. 構文解析AttValue中に>遭遇し、トークンの作成に失敗(字句解析エラー)
 よって整形式でないことを検出できる。

-4.4.6 "通知する"について
●妥当性を検証しないプロセッサ
特に仕様なし
●妥当性を検証するプロセッサ
構文解析器が開始タグの属性値を解析し終わったとき
その属性値が属性リスト宣言でENTITY型、またはENTITIES型として宣言してある場合、
その属性値をkeyに一般実体テーブルを検索し、
それが外部・解析対象外・一般実体であるなら、
 システム識別子と(もしあれば)公開識別子
および、関連付けられた記法の
 システム識別子と(もしあれば)公開識別子
をアプリケーション通知用データとして抽象構文木に追加する。

-4.4.7 "バイパスする"について
構文解析器がEntityValue処理中に、一般実体の参照を認識したとき、一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、
それが 内部・解析対象・一般実体である、
または、外部・解析対象・一般実体である場合、
何もせずに次のトークンを読む処理を続ける。

-4.4.8 "パラメータ実体としてインクルードされる"について
●妥当性を検証しないプロセッサ
構文解析器がDTD処理中に、パラメータ実体の参照を認識したとき、
1-1.パラメータ実体のトークンの中のWORD (Name)をkeyにパラメータ実体テーブルを検索する。
1-2.パラメータ実体であるなら、置換テキストRepTextを取得する。
1-3.置換テキストRepTextの先頭と末尾に#x20を追加してRepText2にする。
1-4.パラメータ実体のトークン列 SYMBOL (%) WORD (Name) SYMBOL (;)の代わりにRepText2を得る。
1-5.文脈中の入力バッファにRepText2を差し戻す。
または、
2-1. パラメータ実体のトークン列をそのままに、読み込まなかった旨をアプリケーションに通知する。
●妥当性を検証するプロセッサ
構文解析器がDTD処理中に、パラメータ実体の参照を認識したとき、
1-1.パラメータ実体のトークンの中のWORD (Name)をkeyにパラメータ実体テーブルを検索する。
1-2.パラメータ実体であるなら、置換テキストRepTextを取得する。
1-3.置換テキストRepTextの先頭と末尾に#x20を追加してRepText2にする。
1-4.パラメータ実体のトークン列 SYMBOL (%) WORD (Name) SYMBOL (;)の代わりにRepText2を得る。
1-5.文脈中の入力バッファにRepText2を差し戻す。

-4.4.9 "エラー"について
構文解析器がEntityValue処理中に、一般実体の参照を認識したとき、一般実体のトークンの中のWORD(Name)をkeyに一般実体テーブルを検索し、それが外部・解析対象外・一般実体であるなら、エラーとする。

仕様整理

妥当性を検証するプロセッサの状況毎にまとめます。
また、必要があれば前回までの内容を含めます。

さらに、前々回の議論より「出現した位置」毎の仕様は細かい場合分けになります。これによって、マークアップ宣言自体が「外部/内部サブセットが無い」という条件を無視できるようになり、無用な部分を削除できます。
-Contentの処理
1.文字参照を認識したとき
1-1.ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにCharData (RepText)を返す。 2.一般実体の参照を認識したとき、
2-1.実体名がamp, lt, gt, apos, quoteの場合(定義済み実体の場合)
2-1-1.それぞれ置換テキストCharData (&#38;)、CharData (&#60;)、CharData (>)、CharData (')、CharData (")を返す。
2-2.実体名がamp, lt, gt, apos, quoteでない場合(定義済み実体でない場合)
2-2-1.実体名をキーに一般実体テーブルを検索する
2-2-2.実体名がテーブルに無い場合
2-2-2-1.スタンドアロン文書宣言がyesのとき
2-2-2-1-1.整形式性制約違反エラー
2-2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-2-1.外部サブセットが無い場合
2-2-2-2-1-1.内部サブセットが無い場合
2-2-2-2-1-1-1.整形式性制約エラー
2-2-2-2-1-2.内部サブセットが有る場合
2-2-2-2-1-2-1.パラメータ実体の参照が有る場合
2-2-2-2-1-2-1-1.妥当性制約違反エラー
2-2-2-2-1-2-2.パラメータ実体の参照が無い場合
2-2-2-2-1-2-2-1.整形式性制約エラー
2-2-2-2-2.外部サブセットが有る場合
2-2-2-2-2-1.妥当性制約違反エラー
2-2-3.実体名がテーブルに有る場合
2-2-3-1.実体が内部・解析対象・一般実体または、外部・解析対象・一般実体の場合
2-2-3-1-1.再帰用のスタックに既に同名の実体名があるかチェックする
2-2-3-1-2.再帰用のスタックに既に同名の実体名が有る場合
2-2-3-1-2-1. 整形式性制約エラー
2-2-3-1-3.再帰用のスタックに既に同名の実体名が無い場合
2-2-3-1-3-1.再帰用のスタックに実体名を追加する
2-2-3-1-3-2.置換テキストRepTextを取得する
2-2-3-1-3-3.一般実体のトークン列の代わりにCharData (RepText)を返す。
2-2-3-2.その他(実体が解析対象外実体)の場合
2-2-3-2-1.整形式性制約エラー/致命的エラーとする
-属性リスト宣言のデフォルト値の中での処理
1.文字参照を認識したとき
1-1.ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)を返す。 ※属性リスト宣言の存在自体が、「外部サブセットが有る」または、「内部サブセットが有る」を示すので該当部分を削除
2.一般実体の参照を認識したとき
2-1.実体名がamp, lt, gt, apos, quoteの場合(定義済み実体の場合)
2-1-1.それぞれ置換テキスト
 NORMAL_TOKEN_A1 (&#38;)、NORMAL_TOKEN_A2 (&#38;)、
 NORMAL_TOKEN_A1 (&#60;)、NORMAL_TOKEN_A2 (&#60;)、
 NORMAL_TOKEN_A1 (>)、 NORMAL_TOKEN_A2 (>)、
 NORMAL_TOKEN_A1 (')、 NORMAL_TOKEN_A2 (')、
 NORMAL_TOKEN_A1 (") NORMAL_TOKEN_A2 (")
 を返す。
2-2.実体名がamp, lt, gt, apos, quoteでない場合(定義済み実体でない場合)
2-2-1.実体名をキーに一般実体テーブルを検索する
2-2-2.実体名がテーブルに無い場合
2-2-2-1.スタンドアロン文書宣言がyesのとき
2-2-2-1-1.整形式性制約違反エラー
2-2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-2-1.外部サブセットが無い場合
2-2-2-2-1-1.内部サブセットにパラメータ実体の参照が有る場合
2-2-2-2-1-1-1.妥当性制約違反エラー
2-2-2-2-1-2.内部サブセットにパラメータ実体の参照が無い場合
2-2-2-2-1-2-1.整形式性制約エラー
2-2-2-2-2.外部サブセットが有る場合
2-2-2-2-2-1.妥当性制約違反エラー
2-2-3.実体名がテーブルに有る場合
2-2-3-1.実体が内部・解析対象・一般実体の場合
2-2-3-1-1.再帰用のスタックに既に同名の実体名があるかチェックする
2-2-3-1-2.再帰用のスタックに既に同名の実体名が有る場合
2-2-3-1-2-1. 整形式性制約エラー
2-2-3-1-3.再帰用のスタックに既に同名の実体名が無い場合
2-2-3-1-3-1.再帰用のスタックに実体名を追加する
2-2-3-1-3-2.置換テキストRepTextを取得する
2-2-3-1-3-3.一般実体のトークン列の代わりにNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)を返す。
2-2-3-2.その他(実体が外部・解析対象・一般実体または、外部・解析対象外・一般実体)の場合
2-2-3-2-1.整形式性制約エラー/致命的エラーとする

-属性リスト宣言のデフォルト値の実体参照をすべて展開したあとの値に関する処理
属性値(AttValue)を解析し終わったとき
1.属性リスト宣言のTYPEがENTITY型、またはENTITIES型の場合
1-1.属性値(AttValue自体)をkeyに一般実体テーブルを検索する
1-2.検索したレコードがある場合
1-2-1.外部・解析対象外・一般実体の場合
 システム識別子と(もしあれば)公開識別子
 および、関連付けられた記法のシステム識別子と(もしあれば)公開識別子
 をアプリケーション通知用データとして抽象構文木に追加する。
1-2-2.解析対象外・一般実体でない場合
 # 未だ解説していないが、3.3.2 属性デフォルトにその場合の処理について書いてある
 # この場合、実際に開始タグの内容として呼び出すまでエラーとはしない。
1-3.検索したレコードが無い場合
 妥当性制約

2.属性リスト宣言のTYPEがENTITY型でもENTITIES型でもない場合
 特に処理なし -開始タグの中の属性値の中での処理
1.文字参照を認識したとき
1-1.ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)を返す。 2.一般実体の参照を認識したとき、
2-1.実体名がamp, lt, gt, apos, quoteの場合(定義済み実体の場合)
2-1-1.それぞれ置換テキスト
 NORMAL_TOKEN_A1 (&#38;)、NORMAL_TOKEN_A2 (&#38;)、
 NORMAL_TOKEN_A1 (&#60;)、NORMAL_TOKEN_A2 (&#60;)、
 NORMAL_TOKEN_A1 (>)、 NORMAL_TOKEN_A2 (>)、
 NORMAL_TOKEN_A1 (')、 NORMAL_TOKEN_A2 (')、
 NORMAL_TOKEN_A1 (") NORMAL_TOKEN_A2 (")
 を返す。
2-2.実体名がamp, lt, gt, apos, quoteでない場合(定義済み実体でない場合)
2-2-1.実体名をキーに一般実体テーブルを検索する
2-2-2.実体名がテーブルに無い場合
2-2-2-1.スタンドアロン文書宣言がyesのとき
2-2-2-1-1.整形式性制約違反エラー
2-2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-2-1.外部サブセットが無い場合
2-2-2-2-1-1.内部サブセットが無い場合
2-2-2-2-1-1-1.整形式性制約エラー
2-2-2-2-1-2.内部サブセットが有る場合
2-2-2-2-1-2-1.パラメータ実体の参照が有る場合
2-2-2-2-1-2-1-1.妥当性制約違反エラー
2-2-2-2-1-2-2.パラメータ実体の参照が無い場合
2-2-2-2-1-2-2-1.整形式性制約エラー
2-2-2-2-2.外部サブセットが有る場合
2-2-2-2-2-1.妥当性制約違反エラー
2-2-3.実体名がテーブルに有る場合
2-2-3-1.実体が内部・解析対象・一般実体の場合
2-2-3-1-1.再帰用のスタックに既に同名の実体名があるかチェックする
2-2-3-1-2.再帰用のスタックに既に同名の実体名が有る場合
2-2-3-1-2-1. 整形式性制約エラー
2-2-3-1-3.再帰用のスタックに既に同名の実体名が無い場合
2-2-3-1-3-1.再帰用のスタックに実体名を追加する
2-2-3-1-3-2.置換テキストRepTextを取得する
2-2-3-1-3-3.一般実体のトークン列の代わりにNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)を返す。
2-2-3-2.その他(実体が外部・解析対象・一般実体または、外部・解析対象外・一般実体)の場合
2-2-3-2-1.整形式性制約エラー/致命的エラーとする
-開始タグの中の属性値の実体参照をすべて展開したあとの値に関する処理
属性値(AttValue)を解析し終わったとき
1.属性リスト宣言のTYPEがENTITY型、またはENTITIES型の場合
1-1.属性値(AttValue自体)をkeyに一般実体テーブルを検索する
1-2.検索したレコードが外部・解析対象外・一般実体の場合
 システム識別子と(もしあれば)公開識別子
 および、関連付けられた記法のシステム識別子と(もしあれば)公開識別子
 をアプリケーション通知用データとして抽象構文木に追加する。
1-3.検索したレコードが外部・解析対象外・一般実体でない場合
 3.3.1にある妥当性制約違反

2.属性リスト宣言のTYPEがENTITY型でもENTITIES型でもない場合
 特に処理なし
-EntityValueの処理
1.文字参照を認識したとき
1-1.ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_B1 (RepText)または、NORMAL_TOKEN_B2 (RepText)を返す。 2.一般実体の参照を認識したとき
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
 仕様なし
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体または、外部・解析対象・一般実体の場合
2-3-1-1.バイパスする(何もしない)
2-3-2.その他(外部・解析対象外・一般実体)の場合
 エラーとする

※EntityValueを含む実体宣言の存在自体が、「外部サブセットが有る」または、「内部サブセットが有る」を示すので該当部分を削除
3.パラメータ実体の参照を認識したとき
3-1.実体名をキーにパラメータ実体テーブルを検索する
3-2.実体名がテーブルに無い場合
3-2-1.スタンドアロン文書宣言がyesのとき
3-2-1-1.★仕様なし
3-2-2.スタンドアロン文書宣言がnoのとき
3-2-2-1.外部サブセットが無い場合
3-2-2-1-1.★仕様なし
3-2-2-2.外部サブセットが有る場合
3-2-2-2-1.妥当性制約違反エラー
3-3.実体名がテーブルに有る場合
3-3-1.再帰用のスタックに既に同名の実体名があるかチェックする
3-3-2.再帰用のスタックに既に同名の実体名が有る場合
3-3-2-1. 整形式性制約エラー
3-3-3.再帰用のスタックに既に同名の実体名が無い場合
3-3-3-1.再帰用のスタックに実体名を追加する
3-3-3-2.置換テキストRepTextを取得する。
3-3-3-3.パラメータ実体のトークン列の代わりにNORMAL_TOKEN_B1 (RepText)または、NORMAL_TOKEN_B2 (RepText)を返す。
-EntityValue、AttValue、PI、Comment、SystemLiteral、PubidLiteral、 条件付セクションのignoreの内容を除く 内部/外部サブセット上の処理
※内部/外部サブセット上の処理は、「外部サブセットが有る」または、「内部サブセットが有る」を示すので該当部分を削除
1.パラメータ実体の参照を認識したとき
1-1.実体名をキーにパラメータ実体テーブルを検索する
1-2.実体名がテーブルに無い場合
1-2-1.スタンドアロン文書宣言がyesのとき
1-2-1-1.★仕様なし
1-2-2.スタンドアロン文書宣言がnoのとき
1-2-2-1.外部サブセットが無い場合
1-2-2-1-1.★仕様なし
1-2-2-2.外部サブセットが有る場合
1-2-2-2-1.妥当性制約違反エラー
1-3.実体名がテーブルに有る場合
1-3-1.再帰用のスタックに既に同名の実体名があるかチェックする
1-3-2.再帰用のスタックに既に同名の実体名が有る場合
1-3-2-1. 整形式性制約エラー
1-3-3.再帰用のスタックに既に同名の実体名が無い場合
1-3-3-1.再帰用のスタックに実体名を追加する
1-3-3-2.置換テキストRepTextを取得する。
1-3-3-3.置換テキストRepTextの先頭と末尾に#x20を追加してRepText2にする。
1-3-3-4.パラメータ実体のトークン列の代わりにRepText2を得る。
1-3-3-5.文脈中の入力バッファにRepText2を差し戻す。

長くなりましたので次回に続きます。
Comment(0)

コメント

コメントを投稿する