@blog.justoneplanet.info

日々勉強

PHP DOM

以下のXMLを使用してサンプルコードを解説する。

<?xml version="1.0"?>
<library xmlns:lib="http://sample.com/library">
    <book isbn="0111222333">
        <lib:title>She sells seashells</lib:title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>
</library>

■読込

ファイルパスを指定

<?php
$dom = new DomDocument();
$dom->load('test.xml');
?>

文字列をDOMとして読込

<?php
$dom = new DomDocument();
$dom->loadXML($str);
?>

HTMLファイルとして読込

<?php
$dom = new DomDocument();
$dom->loadHTMLFile('test.html');
?>

HTMLとして読込

<?php
$dom = new DomDocument();
$dom->loadHTML($str);
?>

各メソッドについて

ファイルからの読込 文字列からの読込
XML DomDocument::load DomDocument::loadXML
HTML DomDocument::loadHTMLFile DomDocument::loadHTML

■保存

ファイルへの保存

<?php
$dom = new DomDocument();
$dom->load('test.xml');
if($is_xhtml){
    $dom->save('test.xml');
}
else{
    $dom->saveHTMLFile('test.html');
}
?>

データとして格納

<?php
$dom = new DomDocument();
$dom->load('test.xml');
if($is_xhtml){
    $data = $dom->saveXML();
}
else{
    $data = $dom->saveHTML();
}
?>

各メソッドについて

ファイルに保存 データとして返す
XML DomDocument::save DomDocument::saveXML
HTML DomDocument::saveHTMLFile DomDocument::saveHTML

■DOMにおけるXPath

以下のようにDomXPathオブジェクトを通して、DomDocumentオブジェクトに対するxpathを実行する。

<?php
$dom = new DomDocument();
$dom->load('test.xml');
$xpath = new DomXPath($dom);
$result = $xpath->query('/library/book/title/text()');
foreach($result as $title){
    print($title->data);
}
/*
Eight apes ate eight apples
Strike
Shine
*/
?>

以下のように、名前空間を使うこともできる。

<?php
$dom = new DomDocument();
$dom->load('test.xml');
$xpath = new DomXPath($dom);
$xpath->registerNamespace('lib', 'http://sample.com/library');
$result = $xpath->query('//lib:title/text()');
foreach($result as $book){
    print($book->data);
}
/*
She sells seashells
*/
?>

■XMLドキュメントの操作

以下のようにして、要素を追加することができる。documentElementはドキュメントのルートの要素を示す。

<?php
$dom = new DomDocument();
$dom->load('test.xml');

$book = $dom->createElement('book');
$book->setAttribute('isbn', '0123456789');

$title = $dom->createElement('title');
$txt = $dom->createTextNode('PHP');

$title->appendChild($txt);
$book->appendChild($title);

$author = $dom->createElement('author', 'Jane');
$book->appendChild($author);

$publisher = $dom->createElement('publisher', 'amazon');
$book->appendChild($publisher);

$dom->documentElement->appendChild($book);
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book isbn="0111222333">
        <title>She sells seashells</title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>
<book isbn="0123456789"><title>PHP</title><author>Jane</author><publisher>amazon</publisher></book></library>
*/
?>

各メソッドについて

DomElement DomDocument::createElement(string $name[, string $value])
新しい要素ノードを生成する。第二引数で要素の値を指定することもできる
DomAttr DomElement::setAttribute(string $name, string $value)
新しい属性を追加する
DomNode DomNode::appendChild(DomNode $node)
子要素を追加する
DomText DomNode::createTextNode(string $content)
新しいテキストノードを生成する

個人的にこのあたりはJavaScriptで馴染んでいるので覚えやすい。

■要素の移動

特定の要素の前に移動する場合は、以下のようにDomNode::insertBeforeメソッドを使用する。

<?php
$dom = new DomDocument();
$dom->load('test.xml');
$xpath = new DomXPath($dom);
$result = $xpath->query('/library/book');
$xpath->item(1)->paentNode->insertBefore($result->item(1), $result->item(0));
print($dom->saveXML());
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="0111222333">
        <title>She sells seashells</title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>  
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>
</library>
*/
?>

要素の最後尾に移動する場合は、以下のようにDomNode::appendChildメソッドを使用する。

<?php
$dom = new DomDocument();
$dom->load('test.xml');

$xpath = new DomXPath($dom);
$result = $xpath->query('/library/book');
$result->item(1)->parentNode->appendChild($result->item(0));
print($dom->saveXML());
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>
    <book isbn="0111222333">
        <title>She sells seashells</title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>
</library>
*/
?>

但し、上述のメソッドはノードをコピーしない。従って、複製を挿入したい場合は、DomNode::cloneNodeメソッドを使用し、複製してから挿入しなければならない。

<?php
$dom = new DomDocument();
$dom->load('test.xml');

$xpath = new DomXPath($dom);

$result = $xpath->query('/library/book');
$elm = $result->item(0)->cloneNode();
$result->item(1)->parentNode->appendChild($elm);
print($dom->saveXML());
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book isbn="0111222333">
        <title>She sells seashells</title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>
    <book isbn="0123456789">

        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>

        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>

<book isbn="0111222333"/></library>
*/
?>

各メソッドについて

DomNode DomNode::insertBefore(DomNode $node[, DomNode $refnode])
第一引数で指定したノードが、第二引数で指定したノードの前に挿入される。
DomNode DomNode::appendChild(DomNode $node)
DomNodeの最後尾に、引数で指定したノードを挿入する。
DomNode DomNode::cloneNode(bool $recursive=false)
DomNodeを複製する。引数にtrueを指定すると子ノードまで含めた複製が生成される。デフォルトはfalse。

■要素の削除

要素を削除するには、以下のようにDomNode::removeChildメソッドを使用する。また、属性を削除するには、DomNode::removeAttributeメソッド使用する。さらに、要素内のテキストを削除したい場合は、DomCharacterData::deleteDataメソッドを使用する。

<?php
$dom = new DomDocument();
$dom->load('test.xml');

$xpath = new DomXPath($dom);
$result = $xpath->query('/library/book');

$result->item(0)->parentNode->removeChild($result->item(0));
$result->item(1)->removeAttribute('isbn');

$result = $xpath->query('/library/book/publisher/text()');
$result->item(0)->deleteData(0, $result->item(0)->length);
print($dom->saveXML());
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book>
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher></publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>
</library>
*/
?>

各メソッドについて

DomNode DomNode::removeChild(DomNode $node)
DomNode内から、引数で指定したノードを削除する。
bool DomElement::removeAttribute(string $name)
DomNodeの、引数で指定した属性を削除する。
void DomCharacterData::deleteData(int $offset, int $count)
DomCharacterDataを対象として、第一引数で指定したオフセット値から、第二引数で指定した文字数分削除する。

■DOMにおける名前空間の扱い方

以下のように、要素や属性に名前空間を指定した記述をした後で、名前空間とそのURIを示す属性を要素に追加することで、名前空間を扱うことができる。

<?php
$dom = new DomDocument();
$node = $dom->createElement('ns1:somenode');
$node->setAttribute('ns2:someattribute', 'somevalue');
$node2 = $dom->createElement('ns3:anothernode');
$node->appendChild($node2);

$node->setAttribute('xmlns:ns1', 'http://sample.org/ns1');
$node->setAttribute('xmlns:ns2', 'http://sample.org/ns2');
$node->setAttribute('xmlns:ns3', 'http://sample.org/ns3');

$dom->appendChild($node);
print($dom->saveXML());
/*
<?xml version="1.0"?>
<ns1:somenode ns2:someattribute="somevalue" xmlns:ns1="http://sample.org/ns1" xmlns:ns2="http://sample.org/ns2" xmlns:ns3="http://sample.org/ns3">
    <ns3:anothernode/>
</ns1:somenode>
*/
?>

但し、以下のようにDomNode::createElementNSメソッドや、DomNode::setAttributeNSを使用すると、自ノードと親ノードに名前空間とそのURIを示す属性が自動的に付加される。

<?php
$dom = new DomDocument();

$node = $dom->createElementNS('http://sample.org/ns1', 'ns1:somenode');
$node->setAttributeNS('http://sample.org/ns2', 'ns2:someattribute', 'somevalue');

$node2 = $dom->createElementNS('http://sample.org/ns3', 'ns3:anothernode');
$node3 = $dom->createElementNS('http://sample.org/ns1', 'ns1:someothernode');

$node->appendChild($node2);
$node->appendChild($node3);

$dom->appendChild($node);

print($dom->saveXML());
/*
<?xml version="1.0"?>
<ns1:somenode xmlns:ns1="http://sample.org/ns1" xmlns:ns2="http://sample.org/ns2" xmlns:ns3="http://sample.org/ns3" ns2:someattribute="somevalue">
    <ns3:anothernode xmlns:ns3="http://sample.org/ns3"/>
    <ns1:someothernode/>
</ns1:somenode>
*/
?>

出力されるXMLは若干違うものの、後者のコードの方が短くシンプルにはなる。

■SimpleXMLとの相互変換

SimpleXMLからDOMへの変換

以下のように、dom_import_simplexml関数を使用してSimpleXMLからDOMへ変換が行える。

<?php
$xml = new SimpleXMLElement('test.xml', null, true);
$node = dom_import_simplexml($xml);

$dom = new DomDocument();
$dom->importNode($node, true);
$dom->appendChild($node);

print($dom->saveXML());
?>

DOMからSimpleXMLへの変換

以下のように、simplexml_import_dom関数を使用してDOMからSimpleXMLへ変換が行える。

<?php
$dom = new DomDocument();
$dom->load('test.xml');
$xml = simplexml_import_dom($dom);
print($xml->asXML());
?>

コメントはまだありません»

No comments yet.

RSS feed for comments on this post.TrackBack URL

Leave a comment