PHP で XML を読み書きする (DOM)

ちょっとしたデータの保管や、RSS、サイトマップなどを出力する際、
XML を扱うことはかなり多いと思いますが、
実際に操作してみるとなんとなくややこしいように見えるので
基本的な方法をまとめておきます。

新規に XML を作るには、新しくDOM ドキュメントを作ります。
「1.0」は XML のバージョンで、「UTF-8」は文字コードの指定です

$dom = new DOMDocument('1.0', 'UTF-8');

ファイルから読み込む場合も新しい DOM ドキュメントを作り、
その中にファイルの内容を読み込みます。

$dom = new DOMDocument('1.0', 'UTF-8');
$dom->load("sample.xml");

すでに変数の中に文字列として XML の内容を読み込んである場合は
loadXML() を利用します。

$string = file_get_contents("sample.xml");
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXML($string);

このままでも読み込みとしては問題ないのですが、
保存時や出力時に改行やインデントがなくなるため、
整形された XML を出力したい時は次のようにします。

$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->load("sample.xml");

ノードを追加するには、createChild() でノードを作成し、
appendChild でノードを追加するのが基本的な流れです。

$datanode = $dom->createElement("data");
$root = $dom->appendChild($datanode);

この場合は空っぽのノード <data /> が作られます。
ではこの親ノードに値を持つ子ノードを追加してみます。

$childnode = $root->appendChild($dom->createElement("child", "Hello"));

今回は省略して一行にまとめてみましたがやっていることは同じです。
実行結果は下のようなります。

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <child>Hello</child>
</data>

テキストノードの代わりに CDATASection を挿入することも出来ます。
CDATASection内部では「<>」などの記号をエスケープすることなく扱うことが出来ます。
通常のテキストノードであっても自動的に「&lt;」のように変換されるので問題は有りません。

$cdata = $dom->createCDATASection("Hello");
$childnode->appendChild($cdata);
<child><![CDATA[Hello]]></child>

次は実行結果をファイルに保存します

$dom->save("test.xml");

画面に表示したり、変数に格納する場合は次のようにします

$content = $dom->saveXML();
header("Content-Type: text/xml; charset=utf-8");
echo $content;

新しい XML を表示するサンプル

<?php
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;

$datanode = $dom->createElement("data");
$root = $dom->appendChild($datanode);

$root->appendChild($dom->createElement("child", "Hello"));
$content = $dom->saveXML();
header("Content-Type: text/xml; charset=utf-8");
echo $content;

ノード値の取得、編集、検索などの方法は次回で説明します。

曜日から日付を調べる

最後の月曜日が何日だったかを調べるケースがあったので
一応メモしておきます。PHP で今日の曜日を知りたい場合

「date("w")」

で取得できます。

返り値は「0~6」の数字で、0 が日曜日、1 が月曜日のようになっています

<?php
function getDateFromDayOfWeek($target){	
  $year	 = date("Y");
  $month = date("m");
  $day	 = date("d");
  $wday	 = date("w");

  if($wday - $target >= 0) {
    $day = $day - ($wday - $target);
  } else {
    $day = $day + ($target - $wday) - 7;
  }
  $time = mktime(0,0,0,$month, $day, $year);
  return date("Y-m-d", $time);
}

$result = getDateFromDayOfWeek(2);
echo $result;

一応関数として作ってあります。
「getDateFromDayOfWeek(曜日を表す数字)」で取得できます。
この場合は 2 なので最後の火曜日の日付が得られるはずです。