Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】Dom\DocumentFragment::C14NFile()メソッドの使い方

C14NFileメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

Dom\DocumentFragmentクラスのC14NFileメソッドは、ドキュメントフラグメントノードを、指定されたファイルへ、W3C勧告のCanonical XML形式でシリアライズ(書き出し)するメソッドです。このメソッドを使用することで、XMLドキュメントの一部であるドキュメントフラグメントを、特定の形式でファイルに保存できます。

C14NFileメソッドは、引数として出力先のファイルパスを受け取ります。また、オプションとして、排他的な正規化を行うかどうか、コメントを含めるかどうか、指定された接頭辞のリストを使用するかどうかといったフラグを設定できます。これらのオプションを適切に設定することで、Canonical XML形式の詳細な制御が可能になります。

具体的には、$exclusiveパラメータで排他的な正規化を行うかどうかを指定し、$with_commentsパラメータでコメントを含めるかどうかを指定します。$xpathパラメータでは、正規化の範囲をXPath式で指定できます。$ns_prefixesパラメータでは、正規化の際に使用する名前空間接頭辞のリストを指定できます。

C14NFileメソッドは、システムのファイル操作を行うため、適切なファイルアクセス権限が必要です。また、出力先のファイルが存在しない場合は、新たにファイルが作成されます。ファイルが存在する場合は、上書きされますので、注意が必要です。

このメソッドを使用することで、XMLドキュメントの一部を他のシステムやアプリケーションと互換性のある形式で共有したり、永続化したりすることが容易になります。特に、XML署名やセキュリティ関連の処理を行う場合に、Canonical XML形式は重要な役割を果たします。

構文(syntax)

1<?php
2
3$dom = new DOMDocument();
4// XMLコンテンツをロードするなどの初期化処理
5// 例: $dom->loadXML('<root><item>Hello</item></root>');
6
7// C14NFileメソッドの呼び出し構文
8// string $uri: 正規化されたXMLを保存するファイルのパス
9// bool $canonicalize: trueを指定すると排他的正規化、false (デフォルト) は包含的正規化
10// array $inclusive_namespaces: 包含的正規化の場合に含める名前空間URIの配列
11$result = $dom->C14NFile('output.xml', true);
12
13// $result には、書き込まれたバイト数、または失敗した場合に false が格納されます。

引数(parameters)

string $uri, bool $exclusive = false, bool $with_comments = false, ?array $xpath = null, ?array $ns_prefixes = null

  • string $uri: 正規化するXMLドキュメントのURIを指定します。
  • bool $exclusive = false: 排他的な正規化を行うかどうかを指定します。trueの場合、指定されたXPath式に一致するノードのみを正規化します。
  • bool $with_comments = false: コメントを含めて正規化するかどうかを指定します。trueの場合、コメントも正規化対象となります。
  • ?array $xpath = null: 排他的な正規化を行う場合に、正規化対象とするノードを指定するためのXPath式の配列です。
  • ?array $ns_prefixes = null: XPath式で使用する名前空間のプレフィックスとURIの対応を指定する連想配列です。

戻り値(return)

int|false

C14NFileメソッドは、XML文書フラグメントを正規化し、その結果をバイト数で返します。正規化が成功した場合はバイト数を、失敗した場合はfalseを返します。

サンプルコード

Dom\DocumentFragment::C14NFileでXML断片を正規化する

1<?php
2
3/**
4 * Dom\DocumentFragment::C14NFile メソッドの使用例。
5 * XMLドキュメントの断片を正規化(Canonicalization)し、その結果をファイルに保存します。
6 *
7 * システムエンジニアを目指す初心者の方へ:
8 * XMLの正規化 (Canonicalization, C14N) とは、XMLドキュメントの内容が同じであれば、
9 * その表現形式(空白、属性の順序など)が異なっていても、常に同一のバイト列に変換されるようにする処理です。
10 * これにより、XML署名など、XMLの内容が改ざんされていないことを保証する際に利用されます。
11 * Dom\DocumentFragment は、XMLドキュメント全体ではなく、その一部(断片)を扱うためのオブジェクトです。
12 */
13function demonstrateDomDocumentFragmentC14NFile(): void
14{
15    // 1. XML要素を作成するために Dom\Document オブジェクトを準備します。
16    //    Dom\DocumentFragment はそれ自体で要素を作成できないため、Dom\Document が必要です。
17    $document = new Dom\Document('1.0', 'UTF-8');
18    // 出力されるXMLを見やすくするために formatOutput を設定 (C14Nの結果には影響しません)
19    $document->formatOutput = true; 
20
21    // 2. Dom\DocumentFragment オブジェクトを作成します。
22    //    ここに正規化したいXMLの断片(要素)を追加していきます。
23    $fragment = new Dom\DocumentFragment();
24
25    // 3. ドキュメントフラグメントに要素を追加します。
26    //    これらの要素が正規化処理の対象となります。
27    $element1 = $document->createElement('item');
28    $element1->setAttribute('id', 'A');
29    $element1->textContent = 'First item data.';
30    $fragment->appendChild($element1);
31
32    // 意図的に余分な空白と属性順序を異なるようにして、C14Nの効果を確認します。
33    $element2 = $document->createElement('data');
34    $element2->setAttribute('type', 'example');
35    $element2->setAttribute('id', 'B');
36    $element2->textContent = "  Second item data.  ";
37    $fragment->appendChild($element2);
38
39    // 4. 正規化されたXMLを保存する一時ファイルパスを定義します。
40    $outputFilePath = sys_get_temp_dir() . '/c14n_fragment_output.xml';
41
42    echo "正規化されたXMLをファイルに保存します: {$outputFilePath}\n";
43
44    // 5. Dom\DocumentFragment::C14NFile メソッドを呼び出します。
45    //    引数は出力ファイルURIのみを指定し、他のオプション(排他的正規化、コメント含めるかなど)は
46    //    デフォルト値(false または null)を使用します。
47    //    成功するとファイルに書き込まれたバイト数を、失敗すると false を返します。
48    $bytesWritten = $fragment->C14NFile($outputFilePath);
49
50    if ($bytesWritten !== false) {
51        echo "正規化されたXMLが正常にファイルに書き込まれました。バイト数: {$bytesWritten}\n";
52        echo "ファイルの内容:\n";
53        echo file_get_contents($outputFilePath) . "\n";
54        // C14Nによって、余分な空白が削除され、属性の順序が固定されていることが確認できます。
55    } else {
56        echo "エラー: 正規化されたXMLをファイルに書き込めませんでした。\n";
57    }
58
59    // 6. クリーンアップ: 生成された一時ファイルを削除します。
60    if (file_exists($outputFilePath)) {
61        unlink($outputFilePath);
62        echo "一時ファイルを削除しました: {$outputFilePath}\n";
63    }
64}
65
66// 上記の関数を実行して、Dom\DocumentFragment::C14NFile の動作を確認します。
67demonstrateDomDocumentFragmentC14NFile();
68
69?>

PHPのDom\DocumentFragment::C14NFileメソッドは、XMLドキュメントの「断片」を正規化(Canonicalization, C14N)し、その結果をファイルに保存する機能を提供します。XMLの正規化とは、XMLの内容が同じであれば、その表現形式(空白の有無、属性の順序など)が異なっていても、常に同一のバイト列に変換する処理を指します。これにより、XMLの改ざん検出や比較を正確に行うことが可能になります。

このメソッドが所属するDom\DocumentFragmentクラスは、XMLドキュメント全体ではなく、その一部(断片)を効率的に操作するためのオブジェクトです。C14NFileメソッドは、第一引数$uriに正規化結果を書き出すファイルパスを指定します。$exclusive$with_commentsなどのオプション引数を使用すると、排他的正規化の適用やコメントの含否、特定のノードのみの正規化といった詳細な制御が可能です。

サンプルコードでは、異なる書式で作成された複数のXML要素をDom\DocumentFragmentに追加し、C14NFileメソッドで指定されたファイルパスに正規化されたXMLとして保存しています。メソッドが成功した場合、ファイルに書き込まれたバイト数(int型)を返し、ファイルにアクセスできないなどのエラーが発生した場合はfalseを返します。この機能は、XMLベースのセキュリティ技術などで、データの整合性を保証する際に重要な役割を果たします。

Dom\DocumentFragment::C14NFileはXMLの断片を正規化し、その結果を指定ファイルに保存するメソッドです。このメソッドを利用する際は、Dom\DocumentFragment単体ではXML要素を作成できないため、事前にDom\Documentオブジェクトで要素を作成し、Dom\DocumentFragmentに追加する必要がある点に注意してください。ファイルを直接操作するため、指定するファイルパスには書き込み権限が必要であり、セキュリティを考慮した適切なパスを指定することが重要です。メソッドは成功時に書き込まれたバイト数を、失敗時にfalseを返しますので、戻り値を!== falseで厳密に確認し、エラーハンドリングを適切に行ってください。引数として排他的正規化やコメントの有無などを細かく制御できるため、XML署名などセキュリティ要件に応じてこれらのオプションを理解し、適切に設定することが求められます。

PHP C14NFileでXMLを正規化・保存する

1<?php
2
3/**
4 * 指定されたXMLファイルを読み込み、その内容をXML正規化 (C14N) して
5 * 新しいファイルとして保存します。
6 *
7 * この操作は、元のXMLデータとは異なる(正規化された)形式で
8 * 新しいファイルを作成するため、「加工してコピー(保存)」する一例と見なせます。
9 *
10 * @param string $inputXmlFilePath 入力元のXMLファイルパス。
11 * @param string $outputXmlFilePath 出力先の正規化されたXMLファイルパス。
12 * @param bool $exclusive 排他的正規化モードを使用するかどうか。
13 * @param bool $withComments コメントを正規化された出力に含めるかどうか。
14 * @return bool 処理が成功した場合は true、失敗した場合は false。
15 */
16function canonicalizeXmlAndSave(
17    string $inputXmlFilePath,
18    string $outputXmlFilePath,
19    bool $exclusive = false,
20    bool $withComments = false
21): bool {
22    // 1. DOMDocumentオブジェクトを初期化
23    $dom = new DOMDocument();
24
25    // 2. XMLファイルを読み込む
26    // @抑制演算子を使用し、エラーはload()の戻り値でチェックします。
27    if (!@$dom->load($inputXmlFilePath)) {
28        echo "エラー: XMLファイル '{$inputXmlFilePath}' の読み込みに失敗しました。\n";
29        return false;
30    }
31
32    // 3. Dom\DocumentFragment オブジェクトを初期化
33    // DocumentFragmentは、一時的にDOMノードを保持し、操作するための軽量なオブジェクトです。
34    // ここでは、DOMDocument全体のコンテンツを正規化するために使用します。
35    $fragment = new Dom\DocumentFragment();
36
37    // 4. DOMDocumentのルート要素をDocumentFragmentにインポート
38    // cloneNode(true) でディープコピーを作成し、元のDOMDocumentに影響を与えないようにします。
39    if ($dom->documentElement === null) {
40        echo "エラー: XMLファイル '{$inputXmlFilePath}' にルート要素が見つかりません。\n";
41        return false;
42    }
43    $fragment->appendChild($dom->documentElement->cloneNode(true));
44
45    // 5. DocumentFragmentの内容をXML正規化し、指定されたファイルに出力
46    // Dom\DocumentFragment::C14NFile() メソッドは、正規化されたバイト数を返すか、失敗時に false を返します。
47    // 第4引数 ($xpath) と第5引数 ($ns_prefixes) は高度な用途のため、今回は省略します。
48    $bytesWritten = $fragment->C14NFile(
49        $outputXmlFilePath,
50        $exclusive,
51        $withComments
52    );
53
54    if ($bytesWritten === false) {
55        echo "エラー: XMLの正規化とファイル '{$outputXmlFilePath}' への書き込みに失敗しました。\n";
56        return false;
57    }
58
59    echo "XMLが正規化され、'{$outputXmlFilePath}' に {$bytesWritten} バイトで保存されました。\n";
60    return true;
61}
62
63// --- サンプルコードの実行例 ---
64
65// 入力と出力ファイルのパスを定義
66$originalXmlFile = 'original_sample.xml';
67$normalizedXmlFile = 'normalized_output.xml';
68
69// サンプルXMLコンテンツ
70// XML正規化は、属性の順序、名前空間宣言の表記、空白文字の扱いなどを標準化します。
71$sampleXmlContent = <<<XML
72<?xml version="1.0" encoding="UTF-8"?>
73<root xmlns:ex="http://example.com/ns">
74    <!-- これはコメントです -->
75    <element attributeA="valueA" ex:attributeB="valueB">
76        <childNode>Original Text</childNode>
77    </element>
78    <element attributeC="valueC" attributeA="valueA">
79        <childNode>Another Node</childNode>
80    </element>
81</root>
82XML;
83
84// 1. サンプルXMLファイルをディスクに保存
85if (file_put_contents($originalXmlFile, $sampleXmlContent) === false) {
86    die("エラー: オリジナルXMLファイル '{$originalXmlFile}' の作成に失敗しました。\n");
87}
88echo "オリジナルXMLファイル '{$originalXmlFile}' を作成しました。\n";
89
90// 2. XML正規化とファイル保存を実行
91echo "\n--- XML正規化とファイル保存の実行 ---\n";
92// ここでは、排他的正規化モードはOFFにし、コメントは出力に含めます。
93$isSuccess = canonicalizeXmlAndSave(
94    $originalXmlFile,
95    $normalizedXmlFile,
96    false, // 排他的正規化はOFF
97    true   // コメントを含める
98);
99
100if ($isSuccess) {
101    echo "\n--- 処理結果の確認 ---\n";
102    echo "元のXMLファイル ('{$originalXmlFile}'):\n";
103    echo file_get_contents($originalXmlFile);
104    echo "\n\n正規化されたXMLファイル ('{$normalizedXmlFile}'):\n";
105    echo file_get_contents($normalizedXmlFile);
106} else {
107    echo "\nXMLの正規化処理が失敗しました。\n";
108}
109
110// 3. クリーンアップ: サンプルとして作成したファイルを削除
111echo "\n--- ファイルのクリーンアップ ---\n";
112if (file_exists($originalXmlFile)) {
113    unlink($originalXmlFile);
114    echo "'{$originalXmlFile}' を削除しました。\n";
115}
116if (file_exists($normalizedXmlFile)) {
117    unlink($normalizedXmlFile);
118    echo "'{$normalizedXmlFile}' を削除しました。\n";
119}
120
121?>

このPHPサンプルコードは、XMLファイルを「XML正規化(C14N)」と呼ばれる標準的な形式に変換し、新しいファイルとして保存する方法を示しています。これは、元のXMLデータに一定の加工を施した上でコピーする「加工して保存」の一例です。

コードでは、まずDOMDocumentクラスで指定された入力XMLファイルを読み込みます。次に、Dom\DocumentFragmentオブジェクトを生成し、読み込んだXMLドキュメントの内容をこのフラグメントにインポートします。Dom\DocumentFragmentは一時的にXMLの断片を保持し、操作するための軽量なコンテナです。

核心となるDom\DocumentFragment::C14NFileメソッドは、このフラグメントに含まれるXML内容を正規化し、第一引数$uriで指定されたファイルパスに保存します。第二引数$exclusiveは排他的正規化モードを使用するかどうか、第三引数$with_commentsはコメントを正規化後の出力に含めるかどうかを真偽値で設定します。これにより、属性の順序や名前空間の宣言などが標準化されます。

このメソッドは、処理が成功した場合は書き込まれたバイト数(int)を返し、ファイルの書き込みや正規化処理に失敗した場合はfalseを返します。この機能は、XMLデータの比較や電子署名など、XMLの表現に一貫性が求められる場面で活用されます。

このサンプルコードは、XMLファイルを「正規化(C14N)」し、その結果を別ファイルに保存します。これは単純なコピーではなく、XML構造を標準化する加工処理です。ファイル操作は失敗しやすいため、load()C14NFile()の戻り値(false)を必ず確認し、エラー処理を実装してください。また、Dom\DocumentFragmentにXMLノードを追加する際は、cloneNode(true)によるディープコピーで、元のDOMDocumentに影響を与えず安全に操作することが重要です。

関連コンテンツ

関連IT用語

関連プログラミング言語