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

第045回_SDDecl

»
今回はXMLDeclの中のSDDeclについて解説します。

SDDeclのW3Cの勧告内容

SDDeclをスタンドアロン文書宣言と呼びます。スタンドアロン文書宣言についてW3Cの勧告を確認していきます。また、39回に説明した適合性の内容が関連しますのでそちらも再度ご確認ください。

----W3C勧告----
2.9 Standalone Document Declaration
Markup declarations can affect the content of the document, as passed from an XML processor to an application; examples are attribute defaults and entity declarations. The standalone document declaration, which may appear as a component of the XML declaration, signals whether or not there are such declarations which appear external to the document entity or in parameter entities. [Definition: An external markup declaration is defined as a markup declaration occurring in the external subset or in a parameter entity (external or internal, the latter being included because non-validating processors are not required to read them).]
----W3C勧告----
----日本語訳----
2.9 スタンドアロン文書宣言
XMLプロセッサからアプリケーションへ渡されるときに、マークアップ宣言は文書の内容に影響することができる;例として属性値のデフォルトや実体宣言があげられる。XML宣言の一部として現れることができるスタンドアロン文書宣言は、
文書実体の外やパラメータ実体の中に現れるそのような宣言があるかどうか
を知らせる。
[定義:外部マークアップ宣言は外部サブセット、パラメータ実体の中に現れるマークアップ宣言である。(パラメータ実体は外部および内部パラメータ実体の両方である。後者の内部パラメータ実体が含まれるのは、妥当性を検証しないプロセッサは内部のパラメータ実体も読む義務を負わないからである。)]
----日本語訳----

続きを読みます。

----W3C勧告----
Standalone Document Declaration
03. [32] SDDecl ::= S 'standalone' Eq
        (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
        [VC: Standalone Document Declaration]

In a standalone document declaration, the value "yes" indicates that there are no external markup declarations which affect the information passed from the XML processor to the application. The value "no" indicates that there are or may be such external markup declarations. Note that the standalone document declaration only denotes the presence of external declarations; the presence, in a document, of references to external entities, when those entities are internally declared, does not change its standalone status.
----W3C勧告----
----日本語訳----
スタンドアロン文書宣言
03. [32] SDDecl ::= S 'standalone' Eq
        (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
        [妥当性制約: スタンドアロン文書宣言]

スタンドアロン文書宣言では、 値"yes"は、XMLプロセッサからアプリケーションへ渡す情報に影響を与える外部マークアップ宣言がないことを示す。値"no"は、XMLプロセッサからアプリケーションへ渡す情報に影響を与える外部マークアップ宣言がある、またはあるかもしれないことを示す。

スタンドアロン文書宣言は外部宣言の存在を示すものでしかないということに注意せよ。;文書の中に外部実体への参照が存在している場合にも、その外部実体が内部で宣言してあるならば、スタンドアロン状態であることを変えさせる理由にはならない。
----日本語訳----

さらに続きを読みます。

----W3C勧告----
If there are no external markup declarations, the standalone document declaration has no meaning. If there are external markup declarations but there is no standalone document declaration, the value "no" is assumed.

Any XML document for which standalone="no" holds can be converted algorithmically to a standalone document, which may be desirable for some network delivery applications.
----W3C勧告----
----日本語訳----
外部マークアップ宣言がない場合、スタンドアロン文書宣言は何も意味を持たない。
外部マークアップ宣言がある場合、かつ、スタンドアロン文書宣言がない場合はそれはスタンドアロン文書宣言が"no"としたとみなす。

standalone="no"であるすべてのXML文書は、アルゴリズムによってスタンドアロン文書に変換できる。ネットワークを転送するアプリケーションにとっては、これは望ましいことかもしれない。
----日本語訳----

さらにさらに続きを読みます。

----W3C勧告----
Validity constraint: Standalone Document Declaration
The standalone document declaration must have the value "no" if any external markup declarations containdeclarations of:
attributes with default values, if elements to which these attributes apply appear in the document without specifications of values for these attributes, or
entities (other than amp, lt, gt, apos, quot), if references to those entities appear in the document, or
attributes with tokenized types, where the attribute appears in the document with a value such that normalization will produce a different value from that which would be produced in the absence of the declaration, or
element types with element content, if white space occurs directly within any instance of those types.
----W3C勧告----
----日本語訳----
妥当性制約: スタンドアロン文書宣言
スタンドアロン文書宣言は、
 もし、以下の外部マークアップ宣言を含む場合
standalone="no"でなければいけない。
デフォルト属性値を宣言していて、もし対応する要素に特定の属性値を指定せずに文書内に現れた場合
補足:つまり実際にデフォルト属性値を適用した場合
実体(amp, lt, gt, apos, quot以外)の参照が文書中に現れた場合
tokenized typesの属性値を定義して、
 tokenized typeの場合の正規化して出来た値

 その宣言が無かったときに出来た値
に差異がある属性値が文書中に現れた場合
要素内容を持つ要素で、直接ホワイトスペースを持つ場合
----日本語訳----

仕様について整理していきます。

SDDeclの仕様整理

W3Cの仕様を整理して考えていきます。

スタンドアロン文書宣言は、妥当性検証の有無によってXMLプロセッサを利用するアプリケーションに渡す結果が異なるかどうかを指定します。各意味は、
"yes":妥当性検証の有無によって結果が異ならない
"no":妥当性検証の有無によって結果が異なるかもしれない
指定無し:"no"とみなすので妥当性検証の有無によって結果が異なるかもしれない
を意味します。
もし、
 スタンドアロン文書宣言がyes
かつ
 妥当性検証の有無で結果が異なる場合
妥当性制約違反とします。

-妥当性検証の有無によって結果が異なる(概要)
妥当性を検証しないプロセッサは、
 外部マークアップ宣言
を読み込む義務を負いません。そこでXMLプロセッサと外部マークアップ宣言の有無の関係について整理すると次のようになります。

No.妥当性検証処理XML文書の中の外部マークアップ宣言結果※1
―――――――――――――――――――――――――――――――――――
1外部マークアップ宣言を読むA
2外部マークアップ宣言を読むAまたはB
3外部マークアップ宣言を読まないA
4外部マークアップ宣言を読まないA
※1 読み込んだ結果をA、外部マークアップ宣言によって結果が変わった場合をBとする。

上記の表の中で1と3、2と4の違いが妥当性検証の有無になります。
この時、外部マークアップ宣言が無い1と3は結果が同じで、外部マークアップ宣言が有る2と4は結果が(外部マークアップ宣言の内容によって)同じ場合もあれば異なる場合もあります。

-妥当性検証の有無によって結果が異なる(詳細)
4つのことを述べています。
1.外部マークアップ宣言で宣言した属性値のデフォルト値を適用するとき
2.外部マークアップ宣言で宣言した実体の参照が文書中にあり、実体値に変換しようとするとき。ただし、定義済み実体は除外します。
3.外部マークアップ宣言で宣言した属性値がtokenized typeで、正規化処理を行うことで値が変化するとき
4.要素が要素内容を持ち、直接ホワイトスペースを持つとき

-W3C勧告の問題点
W3Cの勧告は「スタンドアロン文書宣言は外部宣言の存在を示すものでしかない」と述べていて混乱を与えると思います。これはXML文書を製作するユーザ視点で見て、XMLの内容に「なんらかの影響を与えるもの」ではないと述べていると、考えれば納得がいきます。

一方で、XMLプロセッサを製作する視点で見ると、スタンドアロン文書宣言によって妥当性制約や整形式性制約を処理するかしないかを変更します。そういう意味でW3Cの勧告を読むユーザにあわせてどのような各仕様が機能を持つかを記載するべきでしょう。「スタンドアロン文書宣言は外部宣言の存在を示すものでしかない」などと書けばXMLプロセッサはそれを無視しても良いと考えるべきなので、私はそのような「書き方は問題」があると思います。

また、一般に妥当性を検証するプロセッサより妥当性を検証しないプロセッサの方が処理が高速です。しかし、スタンドアロン文書宣言の処理自体が無用の長物である可能性は否定できません。
妥当性を検証するプロセッサで、
 スタンドアロン文書宣言を処理するもの

 スタンドアロン文書宣言を処理しないもの
を比較した場合に、この処理にかかるコストが妥当性を検証するかしないかと同程度のコストを生むようでは「仕様に問題がある」と筆者は思っています。

-スタンドアロン文書宣言を読み込んだ時点での処理
スタンドアロン文書宣言をXML文書のXMLDeclで読み取ったからといって、その時点で何かをするわけではありません。
# 差分があるのに気づくのは、DTDや文書の内容を
# 読み込んだ時点ですから当然です。
ここではyesのフラグを立てる(またはフラグを立てない)という処理をするだけです。

-立てたフラグによる処理分岐
フラグを立てただけでは見通しが悪いので、立てたフラグによってどのように処理分岐するかについて述べます。

スタンドアロン文書宣言に関連するのは、
5.1 妥当性を検証するプロセッサとしないプロセッサの適合性の要件

4 物理構造の実体の実体参照
にある
整形式性制約: 宣言された実体
妥当性制約 : 宣言された実体
です。

5.1については 39回で既に述べています。
# 実体については実体のコラムで今後、解説します。

また、スタンドアロン文書宣言自体の妥当性制約もありますから、まとめると次のように分岐します。
1.妥当性を検証するプロセッサ
1-1.スタンドアロン文書宣言がyes
整形式制約:
定義済み実体以外の実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
1-1-1.外部マークアップ宣言で宣言した属性値のデフォルト値を適用するとき:妥当性制約違反
1-1-2.外部マークアップ宣言で宣言した実体の参照が文書中にあり、実体値に変換しようとするとき:ただし、定義済み実体は除外します。:妥当性制約違反
1-1-3.外部マークアップ宣言で宣言した属性値がtokenized typeで、正規化処理を行うことで値が変化するとき:妥当性制約違反
1-1-4.要素が要素内容を持ち、直接ホワイトスペースを持つとき:妥当性制約違反
1-2.スタンドアロン文書宣言がno
1-2-1.DTDを持たない文書
整形式制約:
定義済み実体以外の実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。
属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
# DTDを持たないのに実体が宣言できるのか?
1-2-2.DTDを持つ文書
1-2-2-1.外部サブセットを持つ文書
妥当性制約:
実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。パラメータ実体参照が現れる場合、それ以前に宣言がなくてはならない。属性リスト宣言のデフォルト値に一般実体が現れる場合、それ以前に宣言がなくてはならない。
1-2-2-2.外部サブセットを持たない文書(内部サブセットだけの文書)
1-2-2-2-1.パラメータ実体の参照を持つ文書
妥当性制約:
実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。パラメータ実体参照が現れる場合、それ以前に宣言がなくてはならない。属性リスト宣言のデフォルト値に一般実体が現れる場合、それ以前に宣言がなくてはならない。
1-2-2-2-2.パラメータ実体の参照を持たない文書
整形式制約:
定義済み実体以外の実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
2.妥当性を検証しないプロセッサ
2-1.スタンドアロン文書宣言がyes
整形式制約:
定義済み実体以外の実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
適合性の要件:
参照することができないパラメータ実体が現れた後の実体宣言と属性リスト宣言を無視する
2-2.スタンドアロン文書宣言がno
# 妥当性を検証しないので妥当性制約を実施しない。
適合性の要件:
参照することができないパラメータ実体が現れた後の実体宣言と属性リスト宣言を処理する

-必要な仕様だけにする
このコラムで開発しているXMLプロセッサは妥当性を検証するプロセッサです。また、DTDを持つかどうかは外部サブセット、内部サブセットの有無と本質的には同じです。よって、スタンドアロン文書宣言で立てたフラグを利用する処理パターンは、

1.スタンドアロン文書宣言がyes
整形式制約:
定義済み実体以外の実参照体のNameは実体宣言の内の一つの名前にマッチしなければならない。属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
1-1.外部マークアップ宣言で宣言した属性値のデフォルト値を適用するとき:妥当性制約違反
1-2.外部マークアップ宣言で宣言した実体の参照が文書中にあり、実体値に変換しようとするとき。ただし、定義済み実体は除外します。:妥当性制約違反
1-3.外部マークアップ宣言で宣言した属性値がtokenized typeで、正規化処理を行うことで値が変化するとき:妥当性制約違反
1-4.要素が要素内容を持ち、直接ホワイトスペースを持つとき:妥当性制約違反
2.スタンドアロン文書宣言がno
2-1.外部サブセットを持つ文書(内部サブセットは持っていても、持っていなくても良い)
妥当性制約:
実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。パラメータ実体参照が現れる場合、それ以前に宣言がなくてはならない。属性リスト宣言のデフォルト値に一般実体が現れる場合、それ以前に宣言がなくてはならない。
2-2.外部サブセットを持たず内部サブセットを持つ文書
2-2-1.パラメータ実体の参照を持つ文書
妥当性制約:
実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。パラメータ実体参照が現れる場合、それ以前に宣言がなくてはならない。属性リスト宣言のデフォルト値に一般実体が現れる場合、それ以前に宣言がなくてはならない。
2-2-2.パラメータ実体の参照を持たない文書
整形式制約:
定義済み実体以外の実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
2-3.外部サブセットも内部サブセットも持たない文書
整形式制約:
定義済み実体以外の実体参照のNameは実体宣言の内の一つの名前にマッチしなければならない。属性リスト宣言のデフォルト値に現れる実体参照はそれ以前に宣言してなければならない。
# DTDを持たないのに実体が宣言できるのか?
と要件を整理できます。

実装
実装は次のようになります。尚、Visitorは、
 意味解析を行うSemanticAnalysisVisitor(XmlDecl以下は呼び出さない)
 XmlDecl以下の構文を解析するMakingXmlDeclDataVisitor
の2つを作成します。

XmlDeclData

public class XmlDeclData
{
    private final static XmlDeclData m_instance = new XmlDeclData();

    //yes = true, no = false, 未宣言 = false
    private boolean m_standalone;
    
    private XmlDeclData()
    {
        m_standalone = false;//デフォルト値はno
    }
    
    public static XmlDeclData getInstance()
    {
        return m_instance;
    }
    
    public boolean isStandalone()
    {
        return m_standalone;
    }

    public void setStandalone(boolean standalone)
    {
        m_standalone = standalone;
    }
}

SemanticAnalysisVisitor

public class SemanticAnalysisVisitor extends SyntaxParserVisitor
{
    public SemanticAnalysisVisitor()
    {
    }

    @Override
    public void visit(EbnfXmlDeclNode n)
    {
        MakingXmlDeclDataVisitor v = new MakingXmlDeclDataVisitor();
        n.accept(v);

        m_result = v.getResult();
    }
}

MakingXmlDeclDataVisitor

public class MakingXmlDeclDataVisitor extends SyntaxParserVisitor
{
    //XMLDeclデータ
    private static XmlDeclData m_data = XmlDeclData.getInstance();

    public MakingXmlDeclDataVisitor()
    {
    }

    @Override
    public void visit(EbnfStandaloneYesNode n)
    {
        Token token = m_tokenManager.nextToken();
        
        m_result = token.match(n);
        
        if (m_result)
        {
            m_data.setStandalone(true);
        }
        else
        {
            //何もしない
        }
    }
}

これらの仕様は、属性値の正規化やホワイトスペースの処理等に根付く問題がありますが、それらは各仕様で検討することにします。
Comment(0)

コメント

コメントを投稿する