【PHP8.x】Dom\Entity::C14N()メソッドの使い方
C14Nメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『C14Nメソッドは、Dom\EntityオブジェクトをW3Cの仕様に基づいた正規形(Canonical Form)の文字列に変換する処理を実行するメソッドです。正規化(Canonicalization)とは、XML文書において意味的には同じでも、属性の順序や空白の扱いなどが異なる多様な表現を、特定のルールに従って一意の形式に変換するプロセスを指します。この処理により、例えば電子署名の検証やデータの同一性確認を行う際に、見た目の違いに影響されずに、2つのXML文書が論理的に等価であるかをバイトレベルで正確に比較できるようになります。このメソッドは、呼び出されたエンティティノードとその子孫ノードを対象に正規化を行い、その結果を文字列として返します。オプションの引数を指定することで、コメントノードを含めるか、排他的正規化(Exclusive Canonicalization)を適用するかといった、より詳細な動作を制御することも可能です。処理に成功した場合は正規化された文字列を、失敗した場合はfalseを返します。』
構文(syntax)
1$result = $entity->C14N($xpathQuery, $exclusive, $withComments, $nsPrefixes);
引数(parameters)
bool $exclusive = false, bool $withComments = false, ?array $xpath = null, ?array $nsPrefixes = null
- bool $exclusive: true に設定すると、文書全体ではなく、指定されたノードのみを正規化します。デフォルトは
falseです。 - bool $withComments: true に設定すると、コメントノードも正規化に含めます。デフォルトは
falseです。 - ?array $xpath: 正規化の対象とするノードをXPath式で指定します。指定しない場合は文書全体が対象です。
- ?array $nsPrefixes: 名前空間のプレフィックスをキー、URIを値とする連想配列を指定します。正規化の際に、これらのプレフィックスのみが使用されるようにします。
戻り値(return)
string|false
C14Nメソッドは、XML文書を正規化(Canonicalization)した結果を文字列で返します。正規化に失敗した場合はfalseを返します。
サンプルコード
PHP XML: Dom\Entity::C14Nでエンティティを正規化する
1<?php 2 3/** 4 * PHP 8のDom\Entity::C14Nメソッドのサンプルコード。 5 * この関数は、DTDで定義されたXMLエンティティの内容を正規化(C14N)する処理を示します。 6 * 7 * @param bool $exclusive 排他的正規化を適用するかどうか。 8 * @param bool $withComments コメントを含めるかどうか。 9 * @return string|false 正規化されたXML文字列、または失敗した場合は false。 10 */ 11function getCanonicalizedEntityContent(bool $exclusive = false, bool $withComments = false): string|false 12{ 13 // サンプルXMLドキュメントとDTDを作成し、エンティティを定義します。 14 $xmlString = <<<XML 15<?xml version="1.0" encoding="UTF-8"?> 16<!DOCTYPE root [ 17 <!ENTITY myEntity "Example <content> with € symbol."> 18 <!-- エンティティ関連のコメント --> 19]> 20<root> 21 <element>Reference to &myEntity;</element> 22</root> 23XML; 24 25 $dom = new Dom\Document(); 26 $dom->loadXML($xmlString); 27 28 // DTDからDom\Entityオブジェクトを取得します。 29 $entity = null; 30 if ($dom->doctype && $dom->doctype->entities) { 31 // "myEntity" という名前のエンティティを取得 32 /** @var Dom\Entity|null $entity */ 33 $entity = $dom->doctype->entities->getNamedItem('myEntity'); 34 } 35 36 // エンティティが見つからない場合は失敗を返します。 37 if (!$entity) { 38 return false; 39 } 40 41 try { 42 // Dom\Entity::C14Nメソッドを呼び出します(提供されたリファレンス情報に基づく)。 43 // 引数: bool $exclusive, bool $withComments, ?array $xpath, ?array $nsPrefixes 44 // $xpath と $nsPrefixes はこの例では null を使用します。 45 $canonicalizedContent = $entity->C14N($exclusive, $withComments, null, null); 46 return $canonicalizedContent; 47 } catch (Error $e) { 48 // メソッドが存在しない場合など、実行時のエラーを捕捉します。 49 return false; 50 } 51} 52 53// サンプルコードの実行と結果の表示 54$output = getCanonicalizedEntityContent(false, false); 55if ($output !== false) { 56 echo "--- デフォルトC14N (exclusive=false, withComments=false) ---\n"; 57 echo $output . "\n\n"; 58} else { 59 echo "--- 正規化されたコンテンツの取得に失敗しました。 ---\n\n"; 60} 61 62$outputExclusive = getCanonicalizedEntityContent(true, true); 63if ($outputExclusive !== false) { 64 echo "--- 排他的C14N (exclusive=true, withComments=true) ---\n"; 65 echo $outputExclusive . "\n"; 66} else { 67 echo "--- 排他的C14Nコンテンツの取得に失敗しました。 ---\n"; 68}
このPHPサンプルコードは、XMLのDTD(Document Type Definition)で定義されたエンティティの内容を正規化(C14N)する方法を示しています。XMLの正規化とは、XML文書の表現を標準的な形式に変換することで、異なるXML文書間の比較などを容易にする処理です。
まず、サンプルとしてXMLドキュメントとDTDを作成し、「myEntity」という名前のエンティティを定義しています。次に、Dom\Documentクラスを使用してこのXMLを読み込み、そのDTDから特定のDom\Entityオブジェクト(この場合は「myEntity」)を取得します。
Dom\Entity::C14Nメソッドは、この取得したエンティティの内容を正規化するために使用されます。引数$exclusiveは、XML正規化の際に排他的正規化という特定のルールを適用するかどうかをtrueまたはfalseで指定します。$withComments引数は、正規化された出力にXMLコメントを含めるかどうかを制御します。今回のサンプルでは、$xpathと$nsPrefixesの引数は使用せずにnullを渡しています。
このメソッドは、成功すると正規化されたエンティティの内容を文字列として返します。処理に失敗した場合はfalseが返されるため、サンプルコードではその戻り値を確認して結果を表示しています。このコードを通じて、デフォルトの正規化と、排他的正規化およびコメントを含む正規化の二つの異なるケースでの処理を理解することができます。
PHPのDom\Entity::C14Nメソッドは、XMLドキュメント全体ではなく、DTDで定義されたエンティティの内容のみを正規化する点に注意が必要です。まずDom\Documentから対象のエンティティが確実に取得できているか、getNamedItem()の結果を必ず確認してください。メソッドは成功時に正規化された文字列を返し、失敗時にはfalseを返しますので、戻り値がfalseでないかを常にチェックし、適切なエラーハンドリングを行うことが重要です。引数の$xpathや$nsPrefixesは、特定のノードや名前空間を対象とする高度な正規化に使用されるため、エンティティの内容を正規化する際は通常nullのままで問題ありません。この機能を利用するにはPHPのdom拡張が有効になっている必要があります。
PHPによるXMLのC14N正規化
1<?php 2 3/** 4 * XML文字列をDOMDocumentオブジェクトに読み込み、 5 * C14N()メソッドを使って正規化(Canonicalization)するサンプルコードです。 6 * 7 * 正規化とは、論理的に等価なXML文書が、物理的(バイト単位)にも 8 * 同じ表現になるように変換するプロセスです。 9 * 例えば、属性の順序を統一したり、不要な空白を削除したりします。 10 * これは、XML署名の検証など、XMLデータの一貫性が重要な場面で利用されます。 11 */ 12function demonstrateXmlC14N(): void 13{ 14 // 正規化の対象となるXML文字列を定義します。 15 // 属性の順序がバラバラで、不要な空白やコメントが含まれています。 16 $originalXml = <<<XML 17 <?xml version="1.0" encoding="UTF-8"?> 18 <!-- 商品リスト --> 19 <root> 20 <item name="ペン" id="item-2" > 21 <price>100</price> 22 </item> 23 <item id="item-1" name="ノート"> 24 <price>150</price> 25 </item> 26 </root> 27 XML; 28 29 // DOMDocumentオブジェクトを作成し、XMLを読み込みます。 30 $dom = new DOMDocument(); 31 // 整形のための不要な空白ノードを保持しないように設定します。 32 $dom->preserveWhiteSpace = false; 33 $dom->loadXML($originalXml); 34 35 // ドキュメント全体(DOMDocumentオブジェクト自体がノードです)に対して 36 // C14N() メソッドを呼び出し、正規化されたXML文字列を取得します。 37 // 38 // C14N(bool $exclusive = false, bool $withComments = false, ...): string|false 39 // - 第1引数 (exclusive): 排他的正規化を行うかどうか。 40 // - 第2引数 (withComments): コメントノードを含めるかどうか。 41 // 42 // ここではコメントを含めて正規化($withComments = true)します。 43 $canonicalXml = $dom->C14N(false, true); 44 45 // 結果をプレーンテキストとして出力します。 46 header('Content-Type: text/plain; charset=utf-8'); 47 48 echo "--- 元のXML ---" . PHP_EOL; 49 echo $originalXml . PHP_EOL . PHP_EOL; 50 51 echo "--- C14Nで正規化後のXML(コメントあり)---" . PHP_EOL; 52 if ($canonicalXml !== false) { 53 // 属性の順序が 'id', 'name' に統一され、 54 // 要素間の不要な空白が削除されていることがわかります。 55 echo $canonicalXml . PHP_EOL; 56 } else { 57 echo "正規化に失敗しました。" . PHP_EOL; 58 } 59} 60 61// 関数を実行します。 62demonstrateXmlC14N();
Dom\Entity::C14N()は、XML文書を正規化(Canonicalization)するためのメソッドです。正規化とは、属性の順序や空白の有無といった表現上の差異を吸収し、論理的に同じ意味を持つXML文書が物理的(バイト単位)に全く同じ表現になるように変換する処理のことです。この処理は、XML署名の検証など、データの同一性を厳密に保証する必要がある場面で利用されます。
このメソッドはDOMDocumentやDOMElementなどのノードオブジェクトに対して呼び出します。第1引数$exclusiveは、排他的正規化を行うかを真偽値で指定します。第2引数$withCommentsは、変換後の文字列にXMLコメントを含めるかを真偽値で指定します。サンプルコードでは、コメントを含める設定でこのメソッドを実行しています。その結果、元のXMLでバラバラだった属性の順序が統一され、要素間の不要な空白が削除された、正規のXML文字列が生成されます。
メソッドの戻り値は、処理が成功した場合は正規化されたXML文字列、何らかの理由で失敗した場合はfalseとなります。
このメソッドは処理に失敗するとfalseを返すため、サンプルコードのように戻り値を厳密にチェックすることが不可欠です。DOMDocumentオブジェクトだけでなく、特定のDOMElementノードに対しても呼び出し可能で、XMLの一部だけを正規化できます。出力される文字列は常にUTF-8でエンコードされます。また、このメソッドはW3C勧告の「Canonical XML Version 1.0」に基づいているため、より新しい仕様が必要な場合は注意が必要です。巨大なXMLを扱う際は、処理時間やメモリ消費が増加する可能性も考慮すると、より安全なコードになります。