PHPのDOM操作で困っています。

次のようなHTML、PHPコードで、<li>要素が"foo"の場合に、その"children"配下をremoveChildしたいのですが、"foo"だけでなく"hoge"配下の"children"まで削除されてしまいます。
どうすれば意図したような結果が得られますか?

[DOM操作したいHTML]
<ul>
<li class="item-1"><a href="http://example.com/hoge">hoge</a>
<ul class="children">
<li class="item-2"><a href="http://example.com/hoge/001">hogehoge</a></li>
<li class="item-3"><a href="http://example.com/hoge/002">hogehogehoge</a></li>
</ul>
</li>
<li class="item-4"><a href="http://example.com/foo">foo</a>
<ul class="children">
<li class="cat-item-5"><a href="http://example.com/foo/001">foofoo</a></li>
<li class="cat-item-6"><a href="http://example.com/foo/002">foo</a></li>
</ul>
</li>
</ul>

[PHPコード]
$doc = new DOMDocument();
$doc->loadXML($temp);
echo $doc->saveXML($doc);
$a = $doc->getElementsByTagName("a");
for($_cnt = 0; $_cnt < $a->length; $_cnt++){
$target = $a->item($_cnt);
if($target->parentNode->parentNode->getAttribute("class") == "children"){
if(trim( $a->item($_cnt - 1)->nodeValue ) != "foo"){
$target->parentNode->parentNode->parentNode->removeChild( $target->parentNode->parentNode );
}
}
}
echo $doc->saveXML($doc);

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2009/05/19 19:22:18
  • 終了:2009/05/20 09:39:59

ベストアンサー

id:tdoi No.2

tdoi回答回数174ベストアンサー獲得回数752009/05/20 00:09:18

ポイント40pt

まだ、目的が見えていないので、はずしているかもしれませんが、これが、望む挙動でしょうか?

$doc = new DOMDocument();
$doc->loadXML($temp);
echo $doc->saveXML($doc);
$a = $doc->getElementsByTagName("a");
for($_cnt = 0; $_cnt < $a->length; $_cnt++){
  $anchor = $a->item($_cnt);
  if (trim($anchor->nodeValue) == "foo") {
	$target = $anchor->parentNode;
	$children = $target->childNodes;
	for ($i = 0; $i < $children->length; ++$i) {
	  $node = $children->item($i);
	  if ($node->nodeName == 'ul' && $node->getAttribute("class") == "children") {
		$target->removeChild($node);
	  }
	}
  }
 }
echo $doc->saveXML($doc);

もし、違うようであれば、期待する結果を示してもらえますか?

http://dummy

その他の回答(2件)

id:tdoi No.1

tdoi回答回数174ベストアンサー獲得回数752009/05/19 20:27:14

ポイント30pt

やりたいことがよく分かっていませんが、ソースから判断すると、

aタグの中身がfooでかつ、そのaタグを含むliタグを含むulタグのclass属性がchildrenであれば、そのulタグ以下のノードを削除するということでよいですか?


それであれば、以下のtypoだけではないでしょうか?

if(trim( $a->item($_cnt - 1)->nodeValue ) != "foo"){

が、

if(trim( $a->item($_cnt - 1)->nodeValue ) == "foo"){

ですよね?

コメントあけてもらえれば、補足します。


何かの参考になれば。

http://dummy

id:P-mako

ご指摘ありがとうございます。

たしかに質問文には誤りがありました。

ただし、これは質問文をシンプルにするためのリライト時に、

修正し忘れた箇所で、意図した結果はやはり得られない状態です。

正確に訂正しますと、children配下をremoveしようと試みている

コードはご指摘の条件文のelseに書いています。

2009/05/19 23:29:53
id:tdoi No.2

tdoi回答回数174ベストアンサー獲得回数752009/05/20 00:09:18ここでベストアンサー

ポイント40pt

まだ、目的が見えていないので、はずしているかもしれませんが、これが、望む挙動でしょうか?

$doc = new DOMDocument();
$doc->loadXML($temp);
echo $doc->saveXML($doc);
$a = $doc->getElementsByTagName("a");
for($_cnt = 0; $_cnt < $a->length; $_cnt++){
  $anchor = $a->item($_cnt);
  if (trim($anchor->nodeValue) == "foo") {
	$target = $anchor->parentNode;
	$children = $target->childNodes;
	for ($i = 0; $i < $children->length; ++$i) {
	  $node = $children->item($i);
	  if ($node->nodeName == 'ul' && $node->getAttribute("class") == "children") {
		$target->removeChild($node);
	  }
	}
  }
 }
echo $doc->saveXML($doc);

もし、違うようであれば、期待する結果を示してもらえますか?

http://dummy

id:suenaga3 No.3

suenaga3回答回数19ベストアンサー獲得回数52009/05/20 00:59:07

ポイント10pt

今は手元に環境がないのでちょっと確認できないのですが、

ループ文がちょっと危険な感じがします。

提示された例だと、Aタグが6個あるので、6回ループしますが、

6回目のループ時に(5個目、6個目のAタグが消えた後に)

$a->item(4)、および $a->item(5) を参照することになります。

ですがその時、すでにそのタグオブジェクトがないので、動作が

どうなるのか分かりません。

そのあたりで怪しい挙動をしているのかもしれません。

それが原因だとした場合には、

ループを抜けるまでは削除を行わずに配列で確保して、後から

改めて削除するというのはどうでしょう。

http://dummy

id:P-mako

ご指摘ありがとうございます。

たしかにそういう観点も考慮したほうが良いですね。

2009/05/20 09:39:26

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

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません