要約

  • RFC 3076は未処理のファイルをそのまま正規化したのではない。オクテット列は先にXMLプロセッサーを通り、正規化・実体展開を経てXPathノード集合になった。
  • 同じ正規バイトは、特定のデータモデル、コメント選択、アルゴリズムに対する厳密な証拠だったが、原文書の復元、DTDや基底URIの保存、アプリ固有の意味までは保証しなかった。

安定した出力は処理列の途中から始まった

2001年3月、RFC 3076とW3C RecommendationのCanonical XML Version 1.0は、XMLの物理表現が一つではないという問題に答えた。属性の順序、文字エンコーディング、空要素の短縮形、文字参照や実体参照は異なっていても、多くのアプリケーションにとって同じ情報を表せる。署名や完全性比較には、同じ情報から同じオクテット列を得る手順が必要だった。

仕様は出力をUTF-8にし、XML宣言と文書型宣言を除き、空要素を開始・終了タグに展開した。属性の引用符、エスケープ、不要な名前空間宣言の除去、名前空間と属性の辞書順も定めた。コメントを含めるかどうかは入力パラメーターだった。良形式の正規出力を同じ方法に再投入しても変化しない。

しかし、正式な入力モデルはXPathノード集合である。オクテットストリームを受け取った実装は、まずXML処理によってノードを作る。正規化器が見る時点で、ファイルはすでに解析済みだった。

パーサーは並べ替えの対象を先に作っていた

XMLプロセッサーは改行と属性値を正規化し、CDATAセクションを文字内容に置き換え、文字参照と解析対象実体を解決した。DTDの既定属性をノードに追加することもある。名前空間は名前空間ノードに、連続した文字はテキストノードになる。

したがって異なる原ファイルが正しく収束できる。文字を直接書く場合と数値参照で書く場合、内部実体と置換テキスト、<e/>と<e></e>は、解析後の情報が同じなら同じ正規形を得られる。この収束がRFCの成果だった。

同時に、出力から原記法を逆算することはできない。元のエンコーディングはUTF-8に置き換わり、XML宣言とDTDは消える。実体とCDATAの境界も、属性の元の順序も残らない。正規形は「このノードモデルをどう決定的に直列化するか」を答えるが、「どのバイトと外部資源がモデルを作ったか」は答えない。

証拠はその手前から保存すべきだ。受信オクテットのハッシュと取得URI、宣言エンコーディング、パーサーの版と設定、検証モード、外部サブセットと実体の取得方針、実際に読んだ外部ファイル、基底URI、追加された既定属性が必要になる。最終ハッシュからそれらは復元できない。

同じ出力でも動作の手掛かりを失い得た

RFC 3076はXPathモデルにない情報を列挙した。外部解析対象実体の置換テキストに関わる基底URI、notationと外部非解析実体、DTDが宣言した属性型である。

外部実体に相対URIがある場合、その内容を主文書へ挿入すると、元の実体の所在を失った相対URIが別の基点で解決され得る。正規バイトは同じでも、後で開かれる資源は変わる。RFCは必要なxml:baseを付けるか、正規化前に相対URIを絶対化するよう勧めた。

DTDにも二面性がある。既定属性は解析済みノードに入り、正規出力に現れる一方、それを供給した宣言は削除される。ID、IDREF、列挙、NOTATIONなどの型制約も正規ファイルに付随しない。次のパーサーは文字列を読めても、元の型契約を回復できない。

notationと非解析実体は外部データをアプリケーションへ結び付けることがある。XPathモデルはその結合をすべて保持しなかった。RFCが「珍しい」としたことは、利用しているシステムの証拠保存を免除しない。

ノード集合は暗黙の完全な部分木ではなかった

文書部分集合では、XPathは個々のノードの集合を渡す。要素を選んでも、その属性、文字、子孫が自動で全部入るわけではない。親が選ばれていても、除外した子ノードは出力されない。一方、除外された祖先は名前空間文脈や継承属性に影響し得る。

仕様は、構成員の完全な意味を保つ責任をノード集合の作成者に置いた。部分集合の正規出力は良形式XMLでない場合さえある。「canonical」という名前だけで完全性や単独利用可能性を推定してはいけない。

これはRFC 3075の署名範囲とは別の問いである。3075はどのReferenceと変換結果が署名されたかを扱う。3076は、その前にパーサーがどの対象を作ったかを扱う。正しい署名も、記録されなかった解析由来を補えない。

正規形は普遍的な意味の同値ではない

RFCは正規形を、あらゆる論理同値の必要十分条件にしなかった。アプリケーションは特定の空白を無視したり、blackとrgb(0,0,0)を同じ色と見なしたりできる。別の仕様が追加の同値規則を持つこともある。正規形が違っても、用途上同じ場合がある。

一般的なUnicode文字モデル正規化も行わない。名前空間接頭辞は、属性値や文字内容に書かれたXPathやQName風の表現を壊さないため保存された。RFCが与えたのは、XPath表現に対する限定された実行可能な比較であり、意味全体の判定器ではない。

後の改訂が文脈の重要性を再確認した

W3Cの2006年ノートは、C14N 1.0の部分集合で相対xml:baseを子孫へ単純コピーすると、祖先の経路を失い、有効URIが変わり得ると示した。後から標準化されたxml:idも、通常のXML名前空間属性のように継承すべきではなかった。

2008年のCanonical XML 1.1はxml:idを継承せず、xml:baseを特別に合成する規則を導入した。これは仕様進化の証拠であって、全てのC14N 1.0実装の失敗を示すものではない。Exclusive XML Canonicalizationは移動した部分集合の名前空間文脈という別問題を扱い、RFC 3275はC14N 1.0をXML Signatureで必須の方法にした。どちらも原ファイルや認可を証明しない。

残すべき証拠列

原オクテット、取得元、ハッシュ、メディア型、エンコーディング、パーサーと設定、検証方式、実際に利用したDTD・カタログ・実体、基底URI、既定属性、XPath選択、ノード集合、コメント選択、アルゴリズムと版、正規出力を一続きで保存する。その後に比較・署名結果、アプリ固有の同値規則、判断、観測結果が続く。

Lu Hengの後年のrunning codeと現実層の議論は、明示した分析レンズとして有用である。再現可能なバイトは標語より強い。しかし実行層の証拠が、入力の歴史、権威、意味、結果まで所有するわけではない。

情報源