J'écris un plugin pour Virtuemart, son plugin de type System. Dans leur ancienne version (VM2.x), ils géraient la Div
simplement avec une classe et il n'y avait pas de structure interne Div
, donc preg_replace
suffit pour mon besoin. Mais sur la nouvelle version, ils ont changé la structure Div par défaut maintenant Div
à l'intérieur Div
est là. Alors preg_replace
est incapable de remplacer le contenu entier Div
.
J'avais l'habitude de le gérer avec PHPDom
et Xpath
mais dans certains frameworks de templates (T3)
lorsque mon plugin activé, retourne une erreur.
"0 - String could not be parsed as XML"
le même plugin fonctionne bien avec Gantry
et d'autres frameworks. L'ancienne version, j'ai essayé le code suivant et cela fonctionne très bien sur tous les modèles.
$buffer = preg_replace('<div class="ClassNeedstoReplace">([^`]*?)<\/div>/','my custom content',$buffer);
Maintenant, dans Vm3, j'utilise les codes suivants.
$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 toutes les instances de la classe doivent être remplacées.
Je sais que pour tester le plug-in, il fallait une autre extension (VM3). C'est difficile pour les débogueurs. Mais, mon exigence est simplement de remplacer toute l'instance de classe par la mienne.
y a-t-il un moyen de remplacer Div à l'intérieur de la structure Div sans casser les dispositions en utilisant preg_replace
??
La structure de div est
<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>
J'essaie de remplacer "product-field product-field-type-R
"il se peut qu'il y en ait plus d'un à l'intérieur" product-fields
"
J'espère que quelqu'un pourra trouver quelque chose :)
Autres solutions possibles:
Il y a quelques détails gris dans votre question, je vais donc poster une solution que je pense fera comme vous voulez en utilisant DOMDocument et une requête directe XPath. Comme votre question ne semble comporter qu'un seul élément généré et que vous devez supprimer un ou plusieurs éléments indésirables, ma solution supprimera tous les éléments indésirables, à l'exception du premier, puis remplacera le premier élément indésirable par l'élément créé.
La boucle va itérer tous les <div>
balises contenant des valeurs de classe: product-field
et product-field-type-R
ET avoir un parent direct <div>
qui contient une valeur de classe de product-fields
. contains
offre une flexibilité accrue car il ne sera pas cassé si de nouvelles valeurs de classe sont ajoutées.
Code: ( Demo )
$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();
L'utilisation de DomDocument & XPath rend cette solution plus robuste que regex car même si les tierces parties décident de restructurer les valeurs d'attribut de classe, les éléments souhaités seront toujours mis en correspondance.