SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

PHPでDOMを操作する

PHP 5のDOMエクステンションで、DOMツリーをゼロから作成

DOMツリーを再帰的に走査する

 XML構造におけるタグは、他のタグ(ツリーの枝)を含むものと、子タグを1つも含まないもの(=リーフ(葉)タグ)のどちらかに分類されます。そのため、任意のノードから開始してそれぞれの枝を末端の葉までたどっていけば、ツリー全体や部分ツリーを再帰的に走査できます。次の例では、与えられたルートノード($node)から任意のXML部分ツリーを走査し、見つかった各ノードの名前と値を出力します。

function getNodesInfo($node)
{
   if ($node->hasChildNodes())
   {
      $subNodes = $node->childNodes;
      foreach ($subNodes as $subNode)
      {
         if (($subNode->nodeType != 3) || 
            (($subNode->nodeType == 3) &&
            (strlen(trim($subNode->wholeText))>=1)))   
         {
            echo "Node name: ".$subNode->nodeName."\n";
            echo "Node value: ".$subNode->nodeValue."\n";
         }
         getNodesInfo($subNode);         
      }
   }      
}   

 上の例では、次の条件判定に基づいて空のテキストノードを削除し、出力を整形しています。

if (($subNode->nodeType != 3) || 
   (($subNode->nodeType == 3) &&
   (strlen(trim($subNode->wholeText))>=1)))

 このコードは、処理中のノードがテキストノード以外(nodeType != 3)か、テキストノードでかつ空でないテキストを持つかをチェックするものです。こうしなくても定義済みのpreserveWhiteSpaceプロパティをFALSEに設定すれば、余計な空白は取り除かれます。このデフォルト値はTRUEです。

 次の例では、テストのためにBook.xml文書のルートノードを再帰関数getNodesInfoに渡してDOMツリー全体のタグと値を出力します。

<?php
//Create a document instance 
$doc = new DOMDocument();
//Load the Book.xml file
$doc->load( 'Book.xml' );
  
//Setting the objects tree root 
$root = $dom->firstChild;
// Recursive function to list all nodes of a subtree
function getNodesInfo($node)
{
   if ($node->hasChildNodes())
   {
      $subNodes = $node->childNodes;
      foreach ($subNodes as $subNode)
      {
         if (($subNode->nodeType != 3) || 
            (($subNode->nodeType == 3)  
            &&(strlen(trim($subNode->wholeText))>=1)))   
         {
         echo "Node name: ".$subNode->nodeName."\n";
         echo "Node value: ".$subNode->nodeValue."\n";
      }
      getNodesInfo($subNode);         
      }
   }      
}   
//The getNodesInfo function call
getNodesInfo($root);
?>

 図1に出力の一部を示します。

図1 文書の内容: Book.xmlファイルを再帰メソッドgetNodesInfoで処理して得られた出力の一部
図1 文書の内容: Book.xmlファイルを再帰メソッドgetNodesInfoで処理して得られた出力の一部

新しいノードを追加する

 DOMNodeインターフェースには、ノードを作成するメソッドや、作成したノードをDOMツリーに挿入するメソッドが用意されています。新しいノードを作成するには、createElementメソッドかcreateTextNodeメソッドを使います。作成したノードをDOMツリーに挿入するには、appendChildメソッドかinsertBeforeメソッドを使います。appendChildメソッドは指定した子ノードのリストの最後に新しい子ノードを追加し、insertBeforeメソッドは指定したノードの前に新しい子を挿入します。

 次に、これらのメソッドのプロトタイプを示します。

createElementメソッド
DOMElement createElement(string $name [, string $value ])

 このメソッドはDOMElementクラスのインスタンスを生成します。引数$nameは新しい要素に付けるタグ名、引数$valueは要素の値です。DOMElement->nodeValueプロパティを使えば、この値を後で設定することもできます。

createTextNodeメソッド
DOMText createTextNode(string $content)

 このメソッドはDOMTextクラスのインスタンスを生成します。引数$contentは新しいテキストノードに与えるテキストコンテンツです。

appendChildメソッド
DOMNode DOMNode::appendChild(DOMNode $newnode)

 この関数は引数$newnodeを既存の子ノードリストの最後に付加します。または指定したノードを持つ新しい子ノードリストを作成します。

insertBeforeメソッド
DOMNode DOMNode::insertBefore(DOMNode $newnode [,DOMNode $refnode])

 このメソッドは$refnodeで指定した参照ノードの前に引数$newnodeを挿入します。$refnodeを省略した場合、新しいノードはノードの子ノードリストの前に付加されます。

 次の例では<bibliography>ノードを作成し、ツリーの最後に付加します。

//Create a new element 
$newElement = $dom->createElement('bibliography','Martin Didier, Professional XML');
// Add it to the root using the appendChild method
//The appendChild function call
appendNewChild($root,$newElement);
//This function appends a new child node
function appendNewChild($currentNode, $node)
{
   $currentNode->appendChild($node);
}

 この結果をgetNodeInfo()メソッドで処理すると、図2のような出力が得られます。

図2 付加されたノード: 新しいノード<bibliography>とそのコンテンツが文書の最後に付加されている
図2 付加されたノード: 新しいノード<bibliography>とそのコンテンツが文書の最後に付加されている

 次の例では、新しい子<foreword><publisher>ノードの前に追加します。

//create a new <foreword> element
$newElement = $dom->createElement('foreword',
   'What I love about this book is that it '.
   'grew out of just such a process, '.
   'and shows it on every page.');
//Set the reference node
$allContents = $dom->getElementsByTagName('publisher');
$contents = $allContents->item(0);
//Call the insertNewChild function 
insertNewChild($contents,$newElement);
//This function inserts a new child 
//as the first child of $currentNode 
function insertNewChild($currentNode, $node)
{
   $currentNode->insertBefore(
      $node, $currentNode->firstChild);   
}

 変更後の文書をgetNodesInfoで処理すると新しいノードが表示されます(図3を参照)。

図3 ノードの挿入: 新しい子ノード<foreward>が<publisher>ノードの前に挿入されている
図3 ノードの挿入: 新しい子ノード<foreward>が<publisher>ノードの前に挿入されている

次のページ
ノードを複製する

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Octavia Andreea Anghel(Octavia Andreea Anghel)

経験豊富なPHP開発者。現在は、国内外のソフトウェア開発コンテストに参加するプログラミングチームの主任トレーナーを務める。国レベルの教育プロジェクト開発のコンサルティングも担当している。共著書に『XML technologies?XML in Java』があり、XML部分の執筆を担当。PHPやXML...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4278 2009/08/27 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー