人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

php5 DomDocumentでHTMLを読ませてfirefoxで行っているように
tableにtbody等を補完するプログラムを作っています
が激しく遅いので高速に動くように調整をしたいです。

宜しくお願いします。

注意)
基本はプログラム修正で高速化したいですが
他の方法(PHPの別のライブラリ、PEAR、PECL)を駆使してもいいです。
レンタルサーバなのでFirefoxのHTMLパーサ使えば、というのはなしで

以下現状)

//tdの親はtr
$cnt += setHtmlFill($x,'//td[name(..)!="tr"]','tr');
//thの親はtr
$cnt += setHtmlFill($x,'//th[name(..)!="tr"]','tr');
//trの親はtbody or thead
$expression = '//tr[name(..)!="tbody" and name(..)!="thead"]';
$cnt += setHtmlFill($x,$expression,'tbody');
//tbodyの親はtable
$cnt += setHtmlFill($x,'//tbody[name(..)!="table"]','table');

private function setHtmlFill($x,$path,$tag) {
$cnt = 0;

while ($es = $x->query($path)) {
if (!$es->length) {
break;
}
$cnt++;

$e = $es->item(0);
$parent = $e->parentNode;

$add = $x->document->createElement($tag);
$childs = $parent->childNodes;

$del = array();
foreach ($childs as $child) {
$add->appendChild($child->cloneNode(true));
$del[] = $child;
}
foreach ($del as $child) {
$child->parentNode->removeChild($child);
}
$parent->appendChild($add);
}

return $cnt;
}

●質問者: hisugawa
●カテゴリ:インターネット ウェブ制作
✍キーワード:ADD AS CNT Es Expression
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● youku554
●27ポイント

このあたり

http://pg.thumbnailcloud.net/looklike_mysql%E3%80%80tips/91368_0...

◎質問者からの返答

php5での質問でしたが、mysql関連のリンクですね

mysqlのSQL文の補完とphp5のDomDocumentの話で関連があるか判別できませんでした

php5+domでのtbody補完、又はphp5でのtbody補完等で関連があるなら

その点を教えてください、無いなら解答として理解できません。


2 ● nake
●27ポイント

Keith Devens - PHP XML Libraryを使えばたぶんできると思います。

http://techblog.ecstudio.jp/tech-tips/xml_unserializer.html

http://keithdevens.com/software/phpxml

◎質問者からの返答

xml array を参考にしてと言うことですね

http://jp2.php.net/manual/ja/ref.xml.php

この辺を参考にすれば高速にtbody補完できるかも

確認してみます


3 ● tobeoscontinue
●26ポイント

>激しく遅いので高速に動くように調整をしたいです。

小さなデータでは確認できなかったのでコードから考えられるものを列挙してみました。

$x->query($path)を減らす。

$cnt += setHtmlFill($x,'//td[name(..)!="tr"]','tr');

$cnt += setHtmlFill($x,'//th[name(..)!="tr"]','tr');

$cnt += setHtmlFill($x,'//tbody[name(..)!="table"]','table');

はあまりマッチしないと思われるので外してみる。

$x->query($path)は重い処理と思われるので。


$x->query($path)では全てを列挙しているのに、$es->item(0)と最初のものしか使っていない。

そのため数回の$x->query($path)を実行している。

cloneNodeではなく挿げ替え

$child->cloneNode(true)は重そうと思われるので挿げ替えるようにする。

function setHtmlFill($x,$path,$tag) {
 $cnt = 0;

 $es = $x->query($path);
 $add = NULL;
 foreach ($es as $e) {

 $parent = $e->parentNode;
 if ($add == NULL || !$add->parentNode->isSameNode($parent)) {
 $add = $x->document->createElement($tag);
 $parent->appendChild($add);
 $cnt++;
 }
 $add->appendChild($parent->removeChild($e));
 }
 return $cnt;
}

$esに格納されている子は連続して同一の親であると仮定しています。

そうでない場合は$parentに$addがあるかどうかを調べる必要があるのでもっと長くなります。


tableにtbodyを補完するということであれば"table"タグを列挙して子が"tr"であれば"tbody"へ挿げ替えるとした方がオーバーヘッドが少ないように思います。

// $parentタグを列挙して子が$childであれば$middleへ挿げ替える
function insertTag($doc, $parent, $middle, $child)
{
 $list = $doc->getElementsByTagName($parent);
 foreach ($list as $table)
 if ($table->hasChildNodes()) {
 $childs = $table->childNodes;
 $add = $doc->createElement($middle);
 $i = 0;
 // $tableをremoveChild()していると$childsの状態はダイナミックに変更されるのでforは使えない
 while ($i < $childs->length)
 if ($childs->item($i)->nodeName == $child)
 $add->appendChild($table->removeChild($childs->item($i)));
 else $i++;
 if ($add->hasChildNodes())
 $table->appendChild($add);
 }
}

insertTag($doc, 'table', 'tbody', 'tr');

echo $doc->saveHTML();

大きなデータが無いので速度については未確認です。

また親(table)の直下が子(tr)など実際のデータとはそぐわない場合があるかもしれません。

◎質問者からの返答

ありがとうございます

table-tbody以外は多すぎで時間がかかるので

確認対象をtable-tbodyに絞りました

時間を計っていませんが大幅に短縮できました。

$cnt += $this->insertTag($d,'table',array('tbody','thead','tfoot'));

function insertTag($d, $parent, $middle) {

//if (!is_array($middle)) {

//$wk = array();

//$wk[] = $middle;

//$middle = $wk;

//}

$es = $d->getElementsByTagName($parent);

$mod = 0;

foreach ($es as $e) {

if ($e->hasChildNodes()) {

$childs = $e->childNodes;

$add = $d->createElement($middle[0]);

$i = 0;

//$eをremoveChild()していると

//$childsの状態はダイナミックに変更されるのでforは使えない

while ($i < $childs->length) {

if (!in_array($childs->item($i)->nodeName,$middle)) {

$add->appendChild($e->removeChild($childs->item($i)));

} else {

$i++;

}

}

if ($add->hasChildNodes()) {

$e->appendChild($add);

$mod++;

}

}

}

return $mod;

}

追記:

2番目の方の情報を元に

xmlreaderまわりを確認してみましたが

高速にはなりませんでした、saxが高速でもdomを全部phpスクリプトで作るのは

それ以上に時間がかかってしまいました。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ