Virtuemartのシステムタイププラグインのプラグインを書いています。以前のバージョン(VM2.x)では、Div
をクラスで単純に管理しており、内部にDiv
構造体がないため、私の要件にはpreg_replace
で十分です。しかし、新しいバージョンでは、デフォルトのDiv構造を変更し、Div
内部にDiv
が追加されました。したがって、preg_replace
はDiv
コンテンツ全体を置き換えることができません。
PHPDom
とXpath
を使用して管理していましたが、一部のテンプレートフレームワーク(T3)
では、プラグインを有効にするとエラーが返されます。
"0 - String could not be parsed as XML"
同じプラグインはGantry
およびその他のフレームワークで正常に動作します。古いバージョンでは、次のコードを試しましたが、すべてのテンプレートで正常に動作しました。
$buffer = preg_replace('<div class="ClassNeedstoReplace">([^`]*?)<\/div>/','my custom content',$buffer);
Vm3では、次のコードを使用しています。
$docs = new DOMDocument();
libxml_use_internal_errors(true);
$docs->resolveExternals = true;
$docs->loadHTML($buffer);
if($getRelatedProduct != '')
$element = $docs->createElement('div', $getRelatedProduct);
$xpath = new DOMXPath($docs);
$query = '//div[@class="'.$class_name.'"]';
$entries = $xpath->query($query);
foreach ($entries as $entry) {
$entry->parentNode->replaceChild($element, $entry);
}
$docs->recover = true;
libxml_clear_errors();
JResponse::setBody(htmlspecialchars_decode($docs->saveHTML()));
bcozクラスのすべてのインスタンスを置き換える必要があります。
私はプラグインをテストするために別の拡張機能(VM3)が必要であることを知っています。デバッガーにとっては難しいですが、単に私の要件はすべてのクラスインスタンスを私のものに置き換えることです。
preg_replace
を使用してレイアウトを壊さずにDiv構造内のDivを置き換える方法はありますか?
Div構造は
<div class="product-fields">
<div class="product-field product-field-type-R">
<span class="product-fields-title-wrapper"><span class="product-fields-title"><strong>Related Products</strong></span>
<span title="" class="hasTooltip" data-original-title="<strong>Related Products</strong><br />COM_VIRTUEMART_RELATED_PRODUCTS_TIP"><img alt="Tooltip" src="/j34/media/system/images/tooltip.png"></span></span>
<span class="product-field-display"><a target="blank" title="Test Product 1" href="/j34/index.php/shops/c1/t1-detail">Test Product 1</a></span><span class="product-field-desc">Custom prototype for related products</span> </div>
</div>
「product-field product-field-type-R
」を交換しようとしています。「product-fields
」の中に複数ある可能性があります
誰かが何かを理解できるようになることを願っています:)
他の可能な解決策:
質問にはgreyの詳細が含まれているため、解決策を投稿しますthinkは、DOMDocumentと直接XPathクエリを使用して、希望どおりに動作します。あなたの質問には生成された要素が1つしかないようで、1つ以上の不要な要素を削除する必要があるため、私の解決策では最初の要素以外のすべての不要な要素を削除し、最初の不要な要素を作成された要素に置き換えます。
ループは、クラス値<div>
およびproduct-field
を含み、product-field-type-R
のクラス値を含む直接の親<div>
を含むすべてのproduct-fields
タグを反復します。 contains
は、新しいクラス値が追加されても壊れないため、柔軟性が向上します。
コード:( デモ )
$html = /* your valid incoming html */;
$getRelatedProduct = "Flashy, shiny, new";
libxml_use_internal_errors(true);
$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$element = $dom->createElement('div', $getRelatedProduct);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query("//div[contains(@class, 'product-fields')]/div[contains(@class, 'product-field') and contains(@class, 'product-field-type-R')]");
for ($i = $nodes->length - 1; $i >= 0; --$i) { // when removing nodes from DOM, work in reverse order for stability
$node = $nodes->item($i);
if ($i) {
//$trailing_whitespace = $node->nextSibling;
$node->parentNode->removeChild($node); // remove any qualifying element that IS NOT the first element
//$trailing_whitespace->parentNode->removeChild($trailing_whitespace); // optionally remove line returns after removed tags
} else {
$node->parentNode->replaceChild($element, $node); // replace the first element with the generated element
}
}
echo $dom->saveHTML();
DomDocumentとXPathを使用すると、このソリューションが正規表現よりも堅牢になります。サードパーティがクラス属性値を再構築することを決定した場合でも、目的の要素は一致するためです。