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

第056回_EntityDecl_実体参照と文字参照の展開

»

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

今回は実体値の説明の最後として、附録にあるC 実体参照と文字参照の展開(非規範的)ついて読んでいきます。
この附録は、これまで説明した内容を複合的に、テクニカルに利用する例を使って細かい考慮が必要なことを示しています。

まずはW3Cの勧告から読んでいきます。
----W3C勧告----
C Expansion of Entity and Character References (Non-Normative)

This appendix contains some examples illustrating the sequence of entity- and character-reference recognition and expansion, as specified in 4.4 XML Processor Treatment of Entities and References.

If the DTD contains the declaration
<!ENTITY example "<p>An ampersand (&#38;#38;) may be escaped
numerically (&#38;#38;#38;) or with a general entity
(&amp;amp;).</p>" >
then the XML processor will recognize the character references when it parses the entity declaration, and resolve them before storing the following string as the value of the entity "example":
<p>An ampersand (&#38;) may be escaped
numerically (&#38;#38;) or with a general entity
(&amp;amp;).</p>
A reference in the document to "&example;" will cause the text to be reparsed, at which time the start- and end-tags of the p element will be recognized and the three references will be recognized and expanded, resulting in a p element with the following content (all data, no delimiters or markup):
An ampersand (&) may be escaped
numerically (&#38;) or with a general entity
(&amp;).
A more complex example will illustrate the rules and their effects fully. In the following example, the line numbers are solely for reference.
1 <?xml version='1.1'?>
2 <!DOCTYPE test [
3 <!ELEMENT test (#PCDATA) >
4 <!ENTITY % xx '&#37;zz;'>
5 <!ENTITY % zz '&#60;!ENTITY tricky "error-prone" >' >
6 %xx;
7 ]>
8 <test>This sample shows a &tricky; method.</test>
This produces the following:
  • in line 4, the reference to character 37 is expanded immediately, and the parameter entity "xx" is stored in the symbol table with the value "%zz;". Since the replacement text is not rescanned, the reference to parameter entity "zz" is not recognized. (And it would be an error if it were, since "zz" is not yet declared.)
  • in line 5, the character reference "&#60;" is expanded immediately and the parameter entity "zz" is stored with the replacement text  "<!ENTITY tricky "error-prone">", which is a well-formed entity declaration.
  • in line 6, the reference to "xx" is recognized, and the replacement text of "xx" (namely "%zz;") is parsed. The reference to "zz" is recognized in its turn, and its replacement text ("<!ENTITY tricky "error-prone">") is parsed. The general entity "tricky" has now been declared, with the replacement text "error-prone".
  • in line 8, the reference to the general entity "tricky" is recognized, and it is expanded, so the full content of the test element is the self-describing (and ungrammatical) string This sample shows a error-prone method.
----W3C勧告----
----日本語訳----
この附録は、4.4 XMLプロセッサにおける実体と参照の扱い にて仕様化した、実体参照と文字参照の認識と展開の一連の流れを説明するいくつかの例を含む。 例えば、DTDが次の宣言を含む場合、
<!ENTITY example "<p>An ampersand (&#38;#38;) may be escaped
numerically (&#38;#38;#38;) or with a general entity
(&amp;amp;).</p>" >
XMLプロセッサは、実体宣言を構文解析するときに文字参照を認識し、実体"example"の値として次の文字列を保存する前に、その文字参照を解決するだろう。
<p>An ampersand (&#38;) may be escaped
numerically (&#38;#38;) or with a general entity
(&amp;amp;).</p>
文書中にある参照"&example;"は、上記の文字列の再解析を引き起こし、その際に、p要素の開始タグと終了タグが認識され、3つの参照が認識されて展開される。その結果、p要素は次の内容を持つ。(区切り子やマークアップをのないすべてのデータ):
An ampersand (&) may be escaped
numerically (&#38;) or with a general entity
(&amp;).
さらに複雑な例は、規則とそれらの影響について完全に説明できるだろう。次の例において、行番号は説明のためにつけられたものである。
1 <?xml version='1.1'?>
2 <!DOCTYPE test [
3 <!ELEMENT test (#PCDATA) >
4 <!ENTITY % xx '&#37;zz;'>
5 <!ENTITY % zz '&#60;!ENTITY tricky "error-prone" >' >
6 %xx;
7 ]>
8 <test>This sample shows a &tricky; method.</test>
この例は、次のようになる:
  • 4行目にて、37の文字参照は直ちに展開されて、パラメータ実体"xx"はシンボルテーブルに値"%zz;"とともに保存される。置換テキストは再スキャンされないので、パラメータ実体参照"zz"は、認識されない。(もしそうなるなら"zz"はまだ宣言されていないので、エラーになってしまうだろう。)
  • 5行目にて、文字参照"&#60;"は直ちに展開されて、パラメータ実体"zz"は、置換テキスト"<!ENTITY tricky "error-prone">"とともに保存される。これは、整形式の実体宣言である。
  • 6行目にて、"xx"の参照が認識され、"xx"の置換テキスト(すなわち"%zz;")が解析される。"zz"の参照が認識されると置換テキスト("<!ENTITY tricky "error-prone">")が解析される。置換テキスト"error-prone"を伴った一般実体"tricky"が宣言されたことになる。
  • 8行目にて、一般実体"tricky"の参照が認識されると、展開される。その結果、test要素の完全な内容 は、それ自体が説明的な(そして、文法的でない)文字列 This sample shows a error-prone method.となる。
----日本語訳----

■W3C勧告の例/検討したロジックの確認

●4行目
関係する検討済みの処理ロジックは以下の通りです。
---------------再掲---------------
-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.その他(外部・解析対象外・一般実体)の場合
エラーとする

3.パラメータ実体の参照を認識したとき
3-1.実体名をキーにパラメータ実体テーブルを検索する
3-2.実体名がテーブルに無い場合
3-2-1.スタンドアロン文書宣言がyesのとき
3-2-1-1.★仕様なし
3-2-2.スタンドアロン文書宣言がnoのとき
3-2-2-1.条件1.外部サブセットが無い、かつ。条件2.内部サブセットが無い)
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)を返す。
---------------再掲---------------

上記のロジックを適用すると、4行目の&#37;を読み終わった時点でコンシュームドトークンマップ(CTM、コラム38回参照)は次のようになります。

---------------CTM---------------
+document
+prolog
+XMLDecl
+SYMBOL('<?xml')
+VersionInfo
+S
+WORD('version')
+Eq
+VersionNum('1.1')
+SYMBOL('?>')
+doctypedecl
+SYMBOL('<!DOCTYPE')
+S
+Name(test)
+S
+SYMBOL('[')
+intSubset
+markupdecl
+elementdecl
+SYMBOL('<!ELEMENT')
+S
+Name
+S
+contentspec
+SYMBOL('(')
+Mixed
+SYMBOL('#PCDATA')
+SYMBOL(')')
+S
+SYMBOL('>')
+EntityDecl
+SYMBOL('<!ENTITY')
+S
+PEDecl
+SYMBOL('%')
+S
+Name('xx')
+S
+PEDef
+EntityValue
+SYMBOL("'")
+Reference
+CharRef
+SYMBOL("&#")
+WORD("37")
+SYMBOL(";")
---------------CTM---------------

構文解析器は、この時点(認識した時点で直ちに/置換テーブル登録前)で文字参照CharRef(&#37;)を認識し NORMAL_TOKEN_B2(%)に変換します。さらに4行目の最後まで読み込むと

---------------CTM---------------
~省略~
+EntityDecl
+SYMBOL('<!ENTITY')
+S
+PEDecl
+SYMBOL('%')
+S
+Name('xx')
+S
+PEDef
+EntityValue
+SYMBOL("'")
+Reference
+CharRef
+SYMBOL("&#")
+WORD("37")
+SYMBOL(";")
+NormalTokenB2(zz;)
+SYMBOL("'")
+SYMBOL(">")
---------------CTM---------------

となり、構文解析器は、Name('xx'),EntityValue(NORMAL_TOKEN_B2('%') NORMAL_TOKEN_B2('zz;'))の組を得ます。

そして、パラメータ実体テーブルに、
Key置換テキスト
xx%zz;
を登録します。

●5行目
4行目の処理と同じように構文解析器はパラメータ実体テーブルに登録する前にCharRef(&#60;)をNORMAL_TOKEN_B2('<')に変換します。また5行目の最後まで読み込んだ時点でのコンシュームドトークンマップは、

---------------CTM---------------
~省略~
+EntityDecl
+SYMBOL('<!ENTITY')
+S
+PEDecl
+SYMBOL('%')
+S
+Name('zz')
+S
+PEDef
+EntityValue
+SYMBOL("'")
+Reference
+CharRef
+SYMBOL("&#")
+WORD("60")
+SYMBOL(";")
+NormalTokenB2(!ENTITY tricky "error-prone" >)
+SYMBOL("'")
+SYMBOL(">")
---------------CTM---------------

となり、構文解析器は、Name('zz'),EntityValue(NORMAL_TOKEN_B2('<') NORMAL_TOKEN_B2('!ENTITY tricky "error-prone" >'))の組を得ます。

そして、パラメータ実体テーブルに、
Key置換テキスト
xx%zz;
zz<!ENTITY tricky "error-prone" >
を登録します。

●6行目
関係する検討済みの処理ロジックは以下の通りです。
---------------再掲---------------
-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.内部サブセットが無い)
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を差し戻す。
---------------再掲---------------

上記のロジックを適用して6行目の最後まで読み込みます。この時点でのCTMは、
---------------CTM---------------
~省略~
+DeclSep
+PEReference
+SYMBOL('%')
+Name('xx')
+SYMBOL(';')
---------------CTM---------------

となり、パラメータ実体の参照を認識したときの処理に入ります。

【パラメータ実体の参照を認識したときの処理】
まず、xxでパラメータ実体テーブルを検索し、 %zz;を得ます。
これの両端に#x20を付け、#x20%zz;#x20に置き換えます。
その後、50回DeclSepで説明した整形式性制約 宣言の間のパラメータ実体参照によって置換テキストをextSubsetDeclに与えて、再スキャンをします。
#この処理については4.4の一覧表になく、わかり難いと思います。

その結果、

---------------CTM---------------
~省略~
+DeclSep
+S
+DeclSep
+PEReference
+SYMBOL('%')
+Name('zz')
+SYMBOL(';')
+DeclSep
+S
---------------CTM---------------

を得ます。すると、さらにパラメータ実体参照を認識したときの処理に入ります。
zzでパラメータ実体テーブルを検索し、 <!ENTITY tricky "error-prone" > を得ます。
これの両端に#x20を付け、#x20<!ENTITY tricky "error-prone" >#x20が置換テキストになります
この置換テキストも同じように、extSubsetDeclを使って再スキャンします。 最終的に、
---------------CTM---------------
~省略~
+DeclSep
+S
+EntityDecl
+SYMBOL('<!ENTITY')
+S
+GEDecl
+Name('tricky')
+S
+EntityValue
+SYMBOL('"')
+NormalTokenB1('error-prone')
+SYMBOL('"')
+SYMBOL('>')
+DeclSep
+S
---------------CTM---------------

となり、構文解析器は、Name('tricky'),EntityValue(NORMAL_TOKEN_B1('error-prone'))の組を得ます。 そして、一般実体テーブルに
Key置換テキスト
trickyerror-prone
を登録します。

●8行目
関係する検討済みの処理ロジックは以下の通りです。
---------------再掲---------------
-Contentの処理
1.文字参照を認識したとき
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにCharData(RepText)を返す。 2.一般実体の参照を認識したとき、
2-1.実体名がamp,lt,gt,apos,quoteの場合(定義済み実体の場合)
2-1-1.それぞれ置換テキストCharData(&)、CharData(<)、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.条件1.外部サブセットが無い、かつ、条件2.内部サブセットがない。または、内部サブセットがあってもパラメータ実体の参照がない)
2-2-2-2-1-1.整形式性制約違反エラー
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.整形式性制約エラー/致命的エラーとする
---------------再掲---------------

上記のロジックを適用して8行目の一般実体参照を認識するまで読み込みます。この時点でのCTMは、
---------------CTM---------------
~省略~
+element
+STag
+SYMBOL('<')
+Name(test)
+SYMBOL('>')
+content
+CharData(This sample shows a )
+Reference
+SYMBOL('&')
+EntityRef(tricky)
+SYMBOL(';')
---------------CTM---------------

構文解析器は一般実体参照trickyを認識して、置換テキスト(error-prone)を得ます。
置換テキストに対して構文contentを適用して再スキャンし、CharData(error-prone)を取得します。
また、最後まで読み込んだところで
---------------CTM---------------
~省略~
+element
+STag
+SYMBOL('<')
+Name(test)
+SYMBOL('>')
+content
+CharData(This sample shows a )
+CharData(error-prone)
+CharData( method.)
+ETag
+SYMBOL('</')
+Name(test)
+SYMBOL('>')
---------------CTM---------------

となり、Contentの内容は、

This sample shows a error-prone method.

とすることができます。

■附録が示唆するもの

この附録は3つの重要な内容を示唆しています。

-1.文字参照とパラメータ実体を含む置換テキストが存在する
実体値リテラルから置換テキストを作成する処理は
 1.文字参照を認識した場合、直ちに展開する
 2.パラメータ実体を認識した場合、直ちに展開する
 3.一般実体を認識した場合、バイパスする
ですから、作成した置換テキストには文字参照とパラメータ実体が無いように見えます。

しかし、複雑な例において、実体名xxの置換テキストが%zz;であることから判るように、文字参照を使うことによってパラメータ実体や一般実体の置換テキストに文字参照とパラメータ実体の参照を含むことができます。

-2.DeclSepにおける置換テキストの再スキャン
複雑な例からわかるように、DeclSepでパラメータ実体の参照を認識した場合は、展開した置換テキストを生成規則extSubsetDeclで構文解析します。(再スキャンします)

-3.置換テキストは文脈に合わせて再スキャンする
先の2の説明でDeclSepにおける再スキャンを説明しました。また、最初の例では一般実体の参照&example;の置換テキストは生成規則contentで再スキャンする旨が記述してあります。

よって、
"一般実体の参照 を展開するとき、対応する置換テキストは文脈に依存して再スキャンする"
"パラメータ実体の参照を展開するとき、対応する置換テキストは文脈に依存して再スキャンする"
ということが言えます。

次に、勘違いの元となるのが、複雑な例の4行目に対する解説にある"置換テキストは再スキャンされない"という文言だと思います。
これはかなり省略した説明の仕方で、より正確を期すなら
"リテラル実体値から置換テキストを作成する処理は、認識した文字参照を展開する。"
"リテラル実体値から置換テキストを作成する処理は、認識したパラメータ実体の参照を展開する。"
"作成した置換テキスト自体の再スキャンはしない。"
となります。

これらを総合すると、
リテラル実体値から置換テキストを作成する処理において、パラメータ実体の参照を展開するとき、パラメータ実体の置換テキストは文脈EntityValueにマッチするよう再スキャンする。
ということが言えます。
#細かく言うと正確な説明ではありませんので、後で問題点を解説します。

再スキャン方法まで加えて整理すると
"Content内で一般実体の参照を展開するとき、対応する置換テキストは生成規則contentを使って構文解析する"
"AttValue内で一般実体の参照を展開するとき、対応する置換テキストは生成規則AttValueを使って構文解析する"
#細かく言うと正確な説明ではありませんので、後で問題点を解説します。

"EntityValue内でパラメータ実体の参照を展開するとき、対応する置換テキストは生成規則EntityValueを使って構文解析する"
"DeclSep内でパラメータ実体の参照を展開するとき、対応する置換テキストは生成規則extSubsetDeclを使って構文解析する"
"外部サブセットの先頭と末尾のトークンを除いた任意の場所にあるパラメータ実体の参照を展開するとき、対応する置換テキストは直前までに使用していた生成規則の状態を引き継いで構文解析する"
ということが言えます。

■再スキャンに適用する構文の検討

EntityValueの中でパラメータ実体を展開するとき、またはAttValueの中で一般実体を展開するときに、その置換テキストに構文の終りを示すダブルコーテーションやシングルコーテーションが含まれていても、これを構文の末尾とは認識しません。一方でEntityValueやAttValueの構文はそれらを認識しますから、単純に構文を適用して再スキャンすることができないことがわかります。


●EntityValue内のパラメータ実体の参照を再スキャンするときの構文の検討
EntityValue内のパラメータ実体の参照を展開する場合、これを生成規則EntityValueで構文解析するというのは正しくありません。
実際は、
EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"'
      | "'" ([^%&'] | PEReference | Reference)* "'"
であることを考慮して、PEReferenceが示す置換テキストは、([^%&"] | PEReference | Reference)*、または([^%&'] | PEReference | Reference)*
に入れ替わっても良いといっているので
二重引用符で囲まれた場合は ([^%&"] | PEReference | Reference)*
単引用符 で囲まれた場合は ([^%&'] | PEReference | Reference)*
で構文解析する、と言ったほうが正確な説明になります。

さらに、前々回の整理で述べたようにEntityValue内のパラメータ実体の参照を展開する場合は、4.4.5 リテラル内で展開の仕様に従います。従って、置換テキスト内の引用符はトークンの終わりになりません。
よって、引用符の区別なく置換テキストは、
([^%&] | PEReference | Reference)*
で構文解析すれば良いことが判ります。

[^%&]はこれまでにないトークンですから、
ReplacementText ::= (NormalTokenC | PEReference | Reference)*
NormalTokenC ::= NORMAL_TOKEN_Cトークン
NormalTokenCトークン::= [^%&]
という構文とトークンを定義します。

これによって、
 ReplacementText内のパラメータ実体/一般実体/文字参照に関する仕様
が追加になります。

また、EntityValueの処理と再帰的に実行する置換文字列の再スキャンが分離することで、
EntityValueの処理の"整形式性制約:再帰しない"に関する部分は
 最初の1回部分にエラー判定処理を削除する
修正になります。

最終的に、次の仕様を追加します。
  • "EntityValue内でパラメータ実体の参照を展開するとき、対応する置換テキストは生成規則ReplacementTextを使って構文解析する"
  • 構文解析器がReplacementText処理中に、文字参照を認識したとき、ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得て、これをNORMAL_TOKEN_C (RepText)とする。
  • 構文解析器がReplacementText処理中に、一般実体の参照を認識したとき、一般実体のトークンの中のWORD (Name)をkeyに一般実体テーブルを検索し、それが一般実体であるなら、バイパスする。
  • 構文解析器がReplacementText処理中に、パラメータ実体の参照を認識したとき、パラメータ実体のトークンの中のWORD (Name)をkeyにパラメータ実体テーブルを検索し、それがパラメータ実体であるなら、置換テキストRepTextを取得する。RepTextを生成規則ReplacementTextを使って構文解析するパラメータ実体のトークン列 SYMBOL (%) WORD (Name) SYMBOL (;)の代わりにRepTextを構文解析したトークン列を得る。
●AttValue内で一般実体の参照を再スキャンするときの構文の検討
EntityValueの中のパラメータ実体の参照時の再スキャンと同じように、
AttValueの中の一般実体の参照を再スキャンするときは、生成規則AttValueではなく、
AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
ですから、
([^<&] | Reference)*
で構文解析すれば良いことが判ります。 [^<&]はこれまでにないトークンですから、
ReplacementText2 ::= (NormalTokenD | | Reference)*
NormalTokenD ::= NORMAL_TOKEN_Dトークン
NormalTokenDトークン::= [^<&]
という構文とトークンを定義します。

これによって、
 ReplacementText2内の一般実体/文字参照に関する仕様
が追加になります。

また、AttValueの処理と再帰的に実行する置換文字列の再スキャンが分離することで、AttValueの処理の"整形式性制約:再帰しない"に関する部分は
 最初の1回部分にエラー判定処理を削除する
修正になります。

最終的に、次の仕様を追加します。
  • "AttValue内で一般実体の参照を展開するとき、対応する置換テキストは生成規則ReplacementText2を使って構文解析する"
  • 構文解析器がReplacementText2処理中に、文字参照を認識したとき、ISO/IEC 10646のコードポイントを参照することで置換テキストRepTextを得て、これをNORMAL_TOKEN_D (RepText)とする。
  • 構文解析器がReplacementText2処理中に、一般実体の参照を認識したとき、一般実体のトークンの中のWORD (Name)をkeyに一般実体テーブルを検索し、それが解析対象・一般実体であるなら、置換テキストRepTextを取得する。RepTextを生成規則ReplacementText2を使って構文解析する一般実体の参照のトークン列 SYMBOL (&) WORD (Name) SYMBOL (;)の代わりにRepTextを構文解析したトークン列を得る。

■仕様整理

修正がいくつかあるのでまとめた結果を掲載します。(修正がないものもあります)

-Contentの処理
1.文字参照を認識したとき(修正なし)
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにCharData(RepText)を返す。

2.一般実体の参照を認識したとき(修正あり)
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
2-2-1.スタンドアロン文書宣言がyesのとき
2-2-1-1.整形式性制約違反エラー
2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-1.外部サブセットが無い場合
2-2-2-1-1.内部サブセットが無い場合
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-1.妥当性制約違反エラー
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体または、外部・解析対象・一般実体の場合
Update!※スタックの確認処理を削除
2-3-1-1.再帰用のスタックに実体名を追加する
2-3-1-2.置換テキストRepTextを取得する
2-3-1-3.RepTextをContentで構文解析する(New!)
2-3-1-4.一般実体のトークン列の代わりに構文解析したトークン列を返す(Update!)
2-3-2.その他(実体が解析対象外実体)の場合
2-3-2-1.整形式性制約エラー/致命的エラーとする

-属性リスト宣言のデフォルト値の中での処理
1.文字参照を認識したとき(修正なし)
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_A1(RepText)または、NORMAL_TOKEN_A2(RepText)を返す。

2.一般実体の参照を認識したとき(修正あり)
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
2-2-1.スタンドアロン文書宣言がyesのとき
2-2-1-1.整形式性制約違反エラー
2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-1.外部サブセットが無い場合
2-2-2-1-1.内部サブセットにパラメータ実体の参照が有る場合
2-2-2-1-1-1.妥当性制約違反エラー
2-2-2-1-2.内部サブセットにパラメータ実体の参照が無い場合
2-2-2-1-2-1.整形式性制約エラー
2-2-2-2.外部サブセットが有る場合
2-2-2-2-1.妥当性制約違反エラー
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体の場合
Update!※スタックの確認処理を削除
2-3-1-1.再帰用のスタックに実体名を追加する
2-3-1-2.置換テキストRepTextを取得する
2-3-1-3.RepTextをReplacementText2で構文解析する(New!)
2-3-1-4.一般実体のトークン列の代わりに構文解析したトークン列を返す(Update!)
2-3-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/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_A1 (RepText)または、NORMAL_TOKEN_A2 (RepText)を返す。

2.一般実体の参照を認識したとき(修正あり)
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
2-2-1.スタンドアロン文書宣言がyesのとき
2-2-1-1.整形式性制約違反エラー
2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-1.外部サブセットが無い場合
2-2-2-1-1.内部サブセットが無い場合
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-1.妥当性制約違反エラー
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体の場合
Update!※スタックの確認処理を削除
2-3-1-1.再帰用のスタックに実体名を追加する
2-3-1-2.置換テキストRepTextを取得する
2-3-1-3.RepTextをReplacementText2で構文解析する(New!)
2-3-1-4.一般実体のトークン列の代わりに構文解析したトークン列を返す(Update!)
2-3-2.その他(実体が外部・解析対象・一般実体または、外部・解析対象外・一般実体)の場合
2-3-2-1.整形式性制約エラー/致命的エラーとする

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

2.属性リスト宣言のTYPEがENTITY型でもENTITIES型でもない場合
特に処理なし

-EntityValueの処理
1.文字参照を認識したとき(修正なし)
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_B1(RepText)または、NORMAL_TOKEN_B2(RepText)を返す。

2.一般実体の参照を認識したとき(修正なし)
2-1.参照名を参照チェックテーブルに登録する
2-2.バイパスする(何もしない)

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.実体名がテーブルに有る場合
Update!※スタックの確認処理を削除
3-3-1.再帰用のスタックに実体名を追加する
3-3-2.置換テキストRepTextを取得する
3-3-3.RepTextをReplacementTextで構文解析する(New!)
3-3-4.パラメータ実体のトークン列の代わりに構文解析したトークン列を返す(Update!)

-DTDをすべて読み込み終わったとき(修正なし)
1.参照チェックテーブルの実体名を一般実体テーブルから取得する
2.取得した一般実体が外部・解析対象外・一般実体の場合
2-1.エラー(4.4.9に対応)
3.取得した一般実体が外部・解析対象外・一般実体でない場合
3-1.何もしない

-DeclSepの処理(New!)
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.実体名がテーブルに有る場合
Update!※スタックの確認処理を削除
1-3-1.再帰用のスタックに実体名を追加する
1-3-2.置換テキストRepTextの先頭と末尾に#x20を追加してRepText2にする。
1-3-3.RepText2をextSubsetDeclで構文解析する(New!)
1-3-4.パラメータ実体のトークン列の代わりに構文解析したトークン列を返す(Update!)

-外部サブセットのマークアップ宣言で先頭と末尾のトークン以外の処理(New!)
1.パラメータ実体の参照を認識したとき
1-1.実体名をキーにパラメータ実体テーブルを検索する
1-2.実体名がテーブルに無い場合
1-2-1.スタンドアロン文書宣言がyesのとき
1-2-1-1.★仕様なし
1-2-2.スタンドアロン文書宣言がnoのとき
1-2-2-1.妥当性制約違反エラー
1-3.実体名がテーブルに有る場合
Update!※スタックの確認処理を削除
1-3-1.再帰用のスタックに実体名を追加する
1-3-2.置換テキストRepTextの先頭と末尾に#x20を追加してRepText2にする。
1-3-3.RepText2をextSubsetDeclで構文解析する(New!)
1-3-4.現在の構文解析器に戻して、字句解析をし直す。(Update!)

-ReplacementTextの処理(New!)
1.文字参照を認識したとき
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_C(RepText)を返す。

2.一般実体の参照を認識したとき
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
2-2-1.何もしない
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体または、外部・解析対象・一般実体の場合
2-3-1-1.バイパスする(何もしない)
2-3-2.その他(外部・解析対象外・一般実体)の場合
エラーとする

3.パラメータ実体の参照を認識したとき
3-1.実体名をキーにパラメータ実体テーブルを検索する
3-2.実体名がテーブルに無い場合
3-2-1.スタンドアロン文書宣言がyesのとき
3-2-1-1.仕様不明(EntityValueに合わせる)
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.RepTextをReplacementTextで構文解析する
3-3-3-4.パラメータ実体のトークン列の代わりに構文解析したトークン列を返す

-デフォルト値からのReplacementText2の処理(New!)
1.文字参照を認識したとき
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_D(RepText)を返す。

2.一般実体の参照を認識したとき
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
2-2-1.スタンドアロン文書宣言がyesのとき
2-2-1-1.整形式性制約違反エラー
2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-1.外部サブセットが無い場合
2-2-2-1-1.内部サブセットにパラメータ実体の参照が有る場合
2-2-2-1-1-1.妥当性制約違反エラー
2-2-2-1-2.内部サブセットにパラメータ実体の参照が無い場合
2-2-2-1-2-1.整形式性制約エラー
2-2-2-2.外部サブセットが有る場合
2-2-2-2-1.妥当性制約違反エラー
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体の場合
2-3-1-1.再帰用のスタックに既に同名の実体名があるかチェックする
2-3-1-2.再帰用のスタックに既に同名の実体名が有る場合
2-3-1-2-1.整形式性制約エラー
2-3-1-3.再帰用のスタックに既に同名の実体名が無い場合
2-3-1-3-1.再帰用のスタックに実体名を追加する
2-3-1-3-2.置換テキストRepTextを取得する
2-3-1-3-3.RepTextをReplacementText2で構文解析する
2-3-1-3-4.一般実体のトークン列の代わりに構文解析したトークン列を返す
2-3-2.その他(実体が外部・解析対象・一般実体または、外部・解析対象外・一般実体)の場合
2-3-2-1.整形式性制約エラー/致命的エラーとする

-開始タグの属性値からのReplacementText2の処理(New!)
1.文字参照を認識したとき
1-1.ISO/IEC10646のコードポイントを参照することで置換テキストRepTextを得る。
1-2.文字参照のトークン列の代わりにNORMAL_TOKEN_D(RepText)を返す。

2.一般実体の参照を認識したとき
2-1.実体名をキーに一般実体テーブルを検索する
2-2.実体名がテーブルに無い場合
2-2-1.スタンドアロン文書宣言がyesのとき
2-2-1-1.整形式性制約違反エラー
2-2-2.スタンドアロン文書宣言がnoのとき
2-2-2-1.外部サブセットが無い場合
2-2-2-1-1.内部サブセットが無い場合
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-1.妥当性制約違反エラー
2-3.実体名がテーブルに有る場合
2-3-1.実体が内部・解析対象・一般実体の場合
2-3-1-1.再帰用のスタックに既に同名の実体名があるかチェックする
2-3-1-2.再帰用のスタックに既に同名の実体名が有る場合
2-3-1-2-1.整形式性制約エラー
2-3-1-3.再帰用のスタックに既に同名の実体名が無い場合
2-3-1-3-1.再帰用のスタックに実体名を追加する
2-3-1-3-2.置換テキストRepTextを取得する
2-3-1-3-3.RepTextをReplacementText2で構文解析する
2-3-1-3-4.一般実体のトークン列の代わりに構文解析したトークン列を返す
2-3-2.その他(実体が外部・解析対象・一般実体または、外部・解析対象外・一般実体)の場合
2-3-2-1.整形式性制約エラー/致命的エラーとする

Comment(0)

コメント

コメントを投稿する