【PHP8.x】DOMNotation::C14N()メソッドの使い方
C14Nメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
DOMNotationクラスのC14Nメソッドは、ノードのサブツリーを、XMLの正規化(Canonical XML)形式でシリアライズするメソッドです。具体的には、DOMNotationノードをルートとするサブツリーを、W3C勧告の「Canonical XML Version 1.1」に準拠した形式の文字列として返します。このメソッドは、XML文書の一部を、他のシステムやコンポーネントとの間で一貫性のある方法で交換したり、デジタル署名を作成する際に、データの正規化された表現を得るために利用されます。
C14Nメソッドは、いくつかのオプション引数を受け取ることができます。これらの引数を使用することで、正規化処理の詳細な制御が可能です。例えば、コメントを含めるか、属性の順序を固定するか、名前空間の処理方法などを指定できます。これらのオプションを適切に設定することで、特定の用途に合わせた正規化されたXMLを得ることができます。
このメソッドは、DOMDocumentオブジェクトに対して適用されるのではなく、特定のDOMNotationノードに対して適用される点に注意が必要です。DOMNotationノードは、XML文書のDTD(Document Type Definition)で宣言されたNotationを表すノードです。したがって、C14Nメソッドは、通常、文書全体の正規化というよりも、特定のNotationに関連する部分の正規化に用いられます。
返り値は、正規化されたXML文字列です。もしエラーが発生した場合(例えば、サポートされていないオプションが指定された場合など)、このメソッドはFALSEを返します。そのため、返り値が文字列であることを確認してから利用することが推奨されます。システムエンジニアがXMLデータを扱う上で、データの整合性やセキュリティを確保するために、C14Nメソッドは重要な役割を果たします。
構文(syntax)
1DOMNotation::C14N( 2 ?string $exclusive = null, 3 ?bool $withComments = null, 4 ?array $xpath = null, 5 ?string $nsPrefixes = null 6): string|false
引数(parameters)
bool $exclusive = false, bool $withComments = false, ?array $xpath = null, ?array $nsPrefixes = null
PHP:
- bool $exclusive = false: 排他的な正規化を行うかどうかを指定します。
trueの場合、指定されたXPath式に一致するノードのみが正規化されます。 - bool $withComments = false: コメントノードを正規化に含めるかどうかを指定します。
- ?array $xpath = null: 正規化するノードを限定するためのXPath式を指定します。
- ?array $nsPrefixes = null: 名前空間プレフィックスを正規化に含めるかどうかを指定します。
戻り値(return)
DOMDocument | false
このメソッドは、XML文書を正規化して標準的な文字列表現にしたDOMDocumentオブジェクトを返します。正規化に失敗した場合はfalseを返します。
サンプルコード
PHP XML C14N正規化する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * XML文書をC14N(正規化)し、その結果を表示するサンプルコード。 7 * C14Nは "Canonical XML" の略で、XML文書を意味的に等価な 8 * 一意の物理表現(バイト列)に変換するプロセスです。 9 * これにより、デジタル署名や内容の比較が容易になります。 10 */ 11function executeXmlC14nExample(): void 12{ 13 // 正規化の対象となるXML文字列を定義します。 14 // 属性の順序が 'b', 'a' となっており、要素内に余分な空白が含まれています。 15 $xmlString = <<<XML 16<?xml version="1.0" encoding="UTF-8"?> 17<document> 18 <element b="value2" a="value1"> 19 Some text 20 </element> 21</document> 22XML; 23 24 try { 25 // DOMDocumentオブジェクトを作成し、XMLを読み込みます。 26 $doc = new DOMDocument(); 27 $doc->loadXML($xmlString); 28 29 // ドキュメント全体(ルート要素)に対してC14Nメソッドを呼び出します。 30 // このメソッドは DOMNode クラスで定義されており、DOMElement なども継承しています。 31 // 第1引数 (exclusive): 排他的正規化を行うか 32 // 第2引数 (withComments): コメントノードを含めるか 33 $canonicalXmlString = $doc->documentElement->C14N(false, false); 34 35 // 失敗した場合は false が返ります。 36 if ($canonicalXmlString === false) { 37 echo 'XMLの正規化に失敗しました。' . PHP_EOL; 38 return; 39 } 40 41 // 元のXMLと正規化後のXMLを比較して出力します。 42 echo '--- 元のXML ---' . PHP_EOL; 43 echo $xmlString . PHP_EOL . PHP_EOL; 44 45 echo '--- C14N (正規化) 後のXML ---' . PHP_EOL; 46 // 属性がアルファベット順 ('a', 'b') にソートされ、 47 // テキストノード周りの空白が整理されていることがわかります。 48 echo $canonicalXmlString . PHP_EOL; 49 50 } catch (Exception $e) { 51 // XMLのパースエラーなど、例外が発生した場合の処理 52 echo 'エラーが発生しました: ' . $e->getMessage() . PHP_EOL; 53 } 54} 55 56// この関数を実行します。 57executeXmlC14nExample();
DOMNode::C14N()は、XML文書を正規化(C14N)するためのメソッドです。正規化とは、XMLの意味的な内容を保ったまま、その物理的な表現を標準的で一意な形式に変換する処理を指します。これにより、属性の記述順や空白の有無といった表現上の差異を吸収できるため、XML文書が実質的に同一であるかを文字列として比較することが可能になります。デジタル署名の検証など、データの一貫性が求められる場面で利用されます。
サンプルコードでは、まずDOMDocumentオブジェクトに属性の順序が不揃いなXML文字列を読み込みます。次に、ドキュメントのルート要素に対してC14N()メソッドを実行し、正規化処理を行っています。
第1引数の$exclusiveは排他的正規化を行うか、第2引数の$withCommentsはコメントノードを出力に含めるかを真偽値で指定します。このメソッドは、処理が成功すると正規化されたXML文字列を返し、失敗した場合はfalseを返します。実行結果では、属性がアルファベット順にソートされ、テキストノード周りの不要な空白が整理されていることが確認できます。
このC14Nメソッドは、サンプルコードのように文書全体だけでなく、特定のXML要素ノードに対しても呼び出し可能です。これにより、文書の一部だけを正規化できます。メソッドの戻り値は、成功した場合に正規化されたXMLの文字列であり、DOMDocumentオブジェクトではない点に注意してください。失敗するとfalseが返るため、===演算子を使って厳密に比較し、エラー処理を必ず記述しましょう。また、第1引数で指定する排他的正規化は、XML名前空間を扱う上で重要です。特にデジタル署名などで利用する際は、その違いを理解して適切に設定する必要があります。
PHPでのXML排他的正規化(C14N)
1<?php 2 3declare(strict_types=1); 4 5/** 6 * XML文字列を排他的正規化(Exclusive C14N)するサンプルコード 7 * 8 * この関数は、XML文字列からDOMDocumentオブジェクトを生成し、 9 * C14N()メソッドを使用してXMLを正規化形式の文字列に変換します。 10 * 正規化により、属性の順序が統一され、不要な空白やコメントが削除されます。 11 * これは、XML署名などで文書の一貫性を保証するために利用されます。 12 * 13 * @see https://www.php.net/manual/ja/domnode.c14n.php 14 */ 15function generateCanonicalXmlExample(): void 16{ 17 // 正規化対象のXMLデータ。 18 // 属性の順序が統一されておらず、余分な空白やコメントが含まれています。 19 $originalXml = <<<XML 20<?xml version="1.0" encoding="UTF-8"?> 21<root xmlns:ns1="http://example.com/ns1"> 22 <!-- This is a comment --> 23 <child attr2="value2" attr1="value1"> 24 Some Text 25 </child> 26</root> 27XML; 28 29 // DOMDocumentオブジェクトをインスタンス化 30 $doc = new DOMDocument(); 31 32 // XML文字列を読み込む 33 if (!$doc->loadXML($originalXml)) { 34 echo "Failed to load XML." . PHP_EOL; 35 return; 36 } 37 38 // XMLを排他的正規化(Exclusive XML Canonicalization)します。 39 // キーワード 'c14n11' は、多くの場合この排他的正規化を指します。 40 // 第1引数 (exclusive) を true に設定します。 41 // 第2引数 (with_comments) を false に設定し、コメントを除外します。 42 $canonicalXmlString = $doc->C14N(true, false); 43 44 // --- 結果の出力 --- 45 echo "--- Original XML ---" . PHP_EOL; 46 echo $originalXml . PHP_EOL; 47 echo PHP_EOL; 48 49 echo "--- Canonicalized XML (Exclusive C14N) ---" . PHP_EOL; 50 if ($canonicalXmlString !== false) { 51 // 正規化されたXMLは、属性が統一された順序になり、 52 // コメントや余分な空白が除去されます。 53 echo $canonicalXmlString . PHP_EOL; 54 } else { 55 echo "Failed to canonicalize XML." . PHP_EOL; 56 } 57} 58 59// 関数を実行して正規化の例を表示 60generateCanonicalXmlExample();
このサンプルコードは、PHPのDOMDocumentクラスが持つC14Nメソッドを使い、XMLデータを正規化(Canonicalization)する方法を解説するものです。正規化とは、意味が同じでもテキスト表現が異なるXML文書を、決められたルールに従って一意の形式に変換する処理を指します。これにより、属性の順序が統一され、不要な空白やコメントが削除されます。この技術は、XML署名などで文書の同一性を厳密に検証する際に不可欠です。
コード内では、C14Nメソッドの第1引数にtrueを指定し、「排他的正規化(Exclusive C14N)」を実行しています。これはXML文書の一部を扱う際に、その部分に関連する名前空間宣言だけを保持する正規化方式です。第2引数にfalseを指定することで、XML内のコメントは除去されます。このメソッドは、処理が成功すると正規化されたXML文字列を返し、失敗した場合はfalseを返します。
実行結果では、元のXMLに含まれていたコメントや要素内の余分な空白が取り除かれ、child要素の属性がアルファベット順(attr1, attr2)に並べ替えられた、一貫性のあるXML文字列が出力されることを確認できます。
このC14Nメソッドは、XMLを電子署名などで利用可能な一意のテキスト形式に変換します。処理の前提として、loadXML関数でXMLが正しく読み込まれている必要があります。不正な形式のXMLを読み込むと失敗するため、事前のエラーチェックが重要です。また、このメソッドは失敗時にfalseを返す可能性があるため、サンプルコードのように!== falseで戻り値を厳密に判定し、安全に文字列として扱うようにしてください。第1引数をtrueにすると「排他的正規化」となり、XMLの一部を扱う際の挙動が変わります。第2引数をfalseに設定するとコメントが除去されるため、コメントを保持したい場合はtrueに変更する必要があります。