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

【PHP8.x】DOMAttr::previousSiblingプロパティの使い方

previousSiblingプロパティの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

previousSiblingプロパティは、DOMAttrクラスに属し、現在のノードの直前の兄弟ノードを保持するプロパティです。このプロパティは、DOM (Document Object Model) の一般的な設計において、現在のノードと同じ親を持つノードの中で、直前に位置するノードを参照するために利用されます。

しかし、DOMAttrはHTMLやXML要素の属性を表すための特殊なノードです。属性ノードは、通常のDOMツリー構造において要素ノードの子として直接配置されるわけではなく、要素ノードが持つ属性のリストの一部として扱われます。このため、DOMAttrオブジェクトは、一般的な要素ノードやテキストノードのように、共通の親ノードを持つ「兄弟ノード」という概念が適用されません。

したがって、PHPのDOM拡張機能では、DOMAttrオブジェクトのpreviousSiblingプロパティにアクセスしても、常にnullが返されます。これは、DOMAttrがDOMツリー内の兄弟関係を持たないことによる設計上の挙動です。もし、属性値を取得したい場合はnodeValueプロパティを、属性名を取得したい場合はnameプロパティを使用してください。DOMAttrオブジェクトに対して、DOMツリー上の位置関係を把握するためにこのプロパティを利用することはできませんので、ご留意ください。

構文(syntax)

1<?php
2$dom = new DOMDocument();
3$element = $dom->createElement('example');
4$attr = $dom->createAttribute('id');
5$attr->value = 'myid';
6$element->setAttributeNode($attr);
7
8$previousSiblingNode = $attr->previousSibling;
9
10var_dump($previousSiblingNode);
11?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

DOMNode|null

このプロパティは、現在の属性ノードの直前に位置する兄弟ノードを返します。直前の兄弟ノードが存在しない場合は、nullを返します。

サンプルコード

PHP DOMAttr::previousSibling は null を返す

1<?php
2
3/**
4 * DOMAttr::previousSibling プロパティの動作を示すサンプルコードです。
5 *
6 * DOMAttr オブジェクトの previousSibling プロパティは、常に null を返します。
7 * これは、XML/HTML の仕様上、属性ノード自体には兄弟ノードが存在しないためです。
8 * システムエンジニアを目指す初心者の方は、DOMAttr が要素の子ではなく、
9 * 要素に付随する特殊なノードである点を理解することが重要です。
10 */
11function demonstrateDomAttrPreviousSibling(): void
12{
13    // 新しい DOM ドキュメントを作成します。
14    $dom = new DOMDocument('1.0', 'UTF-8');
15
16    // ルート要素 'book' を作成し、ドキュメントに追加します。
17    $bookElement = $dom->createElement('book');
18    $dom->appendChild($bookElement);
19
20    // 'book' 要素に 'isbn' という名前の属性を追加します。
21    // setAttributeNode() メソッドは、追加された DOMAttr オブジェクトを返します。
22    $isbnAttr = $bookElement->setAttributeNode(new DOMAttr('isbn', '978-4-87311-828-5'));
23
24    echo "--- DOMAttr::previousSibling の動作 ---" . PHP_EOL;
25    echo "対象の属性ノード名: " . $isbnAttr->name . PHP_EOL;
26    echo "対象の属性ノード値: " . $isbnAttr->value . PHP_EOL;
27
28    // DOMAttr オブジェクトの previousSibling プロパティにアクセスします。
29    // 属性ノードには兄弟ノードが存在しないため、このプロパティは常に null を返します。
30    $previousNode = $isbnAttr->previousSibling;
31
32    echo "DOMAttr::previousSibling の結果: ";
33    if ($previousNode === null) {
34        echo "null" . PHP_EOL;
35        echo "(理由: 属性ノードには兄弟ノードが存在しません)" . PHP_EOL;
36    } else {
37        // このパスはDOMAttr::previousSiblingでは通常実行されません。
38        echo "予期せぬノードが検出されました: " . $previousNode->nodeName . PHP_EOL;
39    }
40}
41
42// サンプル関数を実行します。
43demonstrateDomAttrPreviousSibling();

PHPのDOMAttr::previousSiblingプロパティは、DOMツリー内で現在の属性ノードの直前にある兄弟ノードを取得しようとするものです。しかし、XMLやHTMLの仕様において、属性ノード(DOMAttr)は要素の子ノードとは異なり、要素に付随する特殊なノードであるため、独立した兄弟ノードを持つことはありません。したがって、このプロパティにアクセスしても、常にnullが返されます。

このプロパティは引数を取りません。戻り値の型はDOMNodeまたはnullと定義されていますが、DOMAttr::previousSiblingの場合、実際には常にnullが返されるため、このプロパティから有効なDOMNodeオブジェクトが返されることはありません。

上記のサンプルコードでは、まずDOMDocumentを作成し、book要素にisbn属性を追加しています。そして、追加されたDOMAttrオブジェクト($isbnAttr)に対してpreviousSiblingプロパティにアクセスしています。実行結果が示す通り、このプロパティは期待通りnullを返します。これは、属性ノードが要素のコンテンツ(子ノード)とは別の構造を持つことを明確に示しています。システムエンジニアを目指す初心者の方は、DOMAttrがDOMツリー内でどのように位置づけられるかを正しく理解することが重要です。

DOMAttr::previousSiblingプロパティは、常にnullを返します。これは、XMLやHTMLの仕様において、属性ノード自体には兄弟ノードが存在しないためです。初心者のシステムエンジニアの方々が特に注意すべき点は、属性ノードが要素の子ノードとは異なり、要素に付随する特殊なノードであるという点です。そのため、他のDOMNodeオブジェクトが持つpreviousSiblingプロパティのように兄弟ノードの存在を期待すると、意図しない動作となります。この特性を理解し、属性ノードの扱い方に注意してください。

DOMAttr::previousSibling で前の属性を取得する

1<?php
2
3/**
4 * DOMAttr::previousSibling プロパティの使用例を示します。
5 *
6 * DOMAttr オブジェクトの場合、previousSibling は、その属性が所属する要素の
7 * 属性リスト内での前の属性ノードを返します。
8 * これは、要素の兄弟ノード(DOMElement の兄弟)とは異なる点に注意してください。
9 *
10 * @see https://www.php.net/manual/ja/class.domattr.php
11 * @see https://www.php.net/manual/ja/class.domnode.php#domnode.props.previoussibling
12 */
13function demonstrateDomAttrPreviousSibling(): void
14{
15    // 新しい DOM ドキュメントを作成
16    $dom = new DOMDocument('1.0', 'UTF-8');
17    $dom->formatOutput = true; // 出力を整形するために設定
18
19    // ルート要素を作成し、ドキュメントに追加
20    $rootElement = $dom->createElement('product');
21    $dom->appendChild($rootElement);
22
23    // 要素に複数の属性を設定
24    // 属性の順序は、previousSibling や nextSibling に影響を与えます
25    $rootElement->setAttribute('id', 'P1001');
26    $rootElement->setAttribute('category', 'Electronics');
27    $rootElement->setAttribute('status', 'In Stock');
28    $rootElement->setAttribute('price', '99.99');
29
30    echo "--- 'product' 要素の属性を検査 ---" . PHP_EOL;
31
32    // 'price' 属性を取得
33    // DOMElement->attributes は DOMNamedNodeMap を返します
34    $priceAttr = $rootElement->attributes->getNamedItem('price');
35
36    if ($priceAttr instanceof DOMAttr) {
37        echo "現在の属性: '" . $priceAttr->name . "' (値: '" . $priceAttr->value . "')" . PHP_EOL;
38
39        // previousSibling プロパティにアクセス
40        $previousAttr = $priceAttr->previousSibling;
41
42        if ($previousAttr instanceof DOMAttr) {
43            echo "前の属性ノードが見つかりました: '" . $previousAttr->name . "' (値: '" . $previousAttr->value . "')" . PHP_EOL;
44
45            // さらにその前の属性ノードを取得してみる
46            $previousOfPreviousAttr = $previousAttr->previousSibling;
47            if ($previousOfPreviousAttr instanceof DOMAttr) {
48                echo "その前の属性ノード: '" . $previousOfPreviousAttr->name . "' (値: '" . $previousOfPreviousAttr->value . "')" . PHP_EOL;
49            } else {
50                echo "属性 '" . $previousAttr->name . "' には、前の属性ノードがありません。" . PHP_EOL;
51            }
52        } else {
53            echo "属性 '" . $priceAttr->name . "' には、前の属性ノードがありません。" . PHP_EOL;
54        }
55    } else {
56        echo "属性 'price' が見つからないか、DOMAttr オブジェクトではありません。" . PHP_EOL;
57    }
58
59    echo PHP_EOL . "--- 前の属性ノードが存在しない場合の例 ---" . PHP_EOL;
60
61    // 'id' 属性を取得 (この例では最初の属性)
62    $idAttr = $rootElement->attributes->getNamedItem('id');
63
64    if ($idAttr instanceof DOMAttr) {
65        echo "現在の属性: '" . $idAttr->name . "' (値: '" . $idAttr->value . "')" . PHP_EOL;
66        $previousIdAttr = $idAttr->previousSibling;
67
68        if ($previousIdAttr instanceof DOMAttr) {
69            echo "前の属性ノードが見つかりました: '" . $previousIdAttr->name . "'." . PHP_EOL;
70        } else {
71            // 最初の属性なので、previousSibling は null を返す
72            echo "期待通り、属性 '" . $idAttr->name . "' には前の属性ノードがありません。" . PHP_EOL;
73        }
74    }
75}
76
77// 関数を実行
78demonstrateDomAttrPreviousSibling();

PHP 8におけるDOMAttr::previousSiblingプロパティは、XMLやHTMLドキュメントの構造を操作する際に、特定の属性の前に存在する別の属性を取得するために使用されます。このプロパティはDOMAttrクラスのインスタンスが持つもので、引数は必要ありません。

サンプルコードでは、まずproductという要素にidcategorystatuspriceの複数の属性を設定しています。その後、price属性を取得し、そのpreviousSiblingプロパティにアクセスすることで、直前に設定されたstatus属性を取得しています。さらにstatus属性のpreviousSiblingを辿ると、category属性が取得できる様子が示されています。

DOMAttr::previousSiblingが指す「前の兄弟」とは、あくまで同じ要素に属する属性リスト内での前の属性ノードのことです。要素自体の兄弟要素を取得するDOMNodepreviousSiblingとは異なる点に注意が必要です。もし、現在の属性がその要素にとって最初の属性である場合、前の属性ノードは存在しないため、このプロパティはnullを返します。サンプルコードの後半では、最初の属性であるid属性に対してpreviousSiblingを試み、期待通りnullが返されることを確認しています。

このプロパティの戻り値はDOMNode型、または前の属性が存在しない場合はnullとなります。通常、このコンテキストではDOMAttrオブジェクトとして扱われます。これにより、XMLやHTMLの属性情報を効率的に走査したり、特定の属性の位置関係を把握したりすることが可能になります。

DOMAttr::previousSiblingは、その属性が所属する要素内の「属性リスト」において、前の属性ノードを返します。これは、HTMLやXML文書における「要素そのものの兄弟ノード」とは異なるため混同しないよう注意が必要です。

このプロパティの戻り値はDOMAttrオブジェクトかnullのいずれかです。属性リストの先頭にある属性には前の属性ノードが存在しないためnullが返されます。そのため、必ずinstanceof DOMAttrで戻り値の型を確認し、nullでないことをチェックしてから利用することが重要です。

要素に属性を追加するsetAttributeの呼び出し順序が、previousSiblingnextSiblingが参照する属性の順序に影響を与える点も理解しておくと良いでしょう。

関連コンテンツ

関連プログラミング言語