Jak dostat HTML z HTML DOMu v PHP
V PHP není možné získat na bajt přesně původní obsah HTML elementu, který byl
naparsován jako DOMDocument
nebo SimpleXMLElement
. Když ho z nějakých
důvodů potřebujete včetně podružností jako uvozovky nebo ukončovací lomítka
void elementů, máte smůlu.
Existuje několik metod, jak serializovat DOM uzel. Každý se chová trochu jinak, ale žádný nevrátí původní bajty.
$html = "<img id=x src=x>"; $dom = new DOMDocument; $dom->loadHTML($html); $el = $dom->getElementById('x'); echo $el->c14n(), "\n"; // <img src="x"></img> echo $el->ownerDocument->saveHTML($el), "\n"; // <img src="x"> echo $el->ownerDocument->saveXML($el), "\n"; // <img src="x"/> echo simplexml_import_dom($el)->asXML(), "\n"; // <img src="x"/>
Metoda c14n()
je úplně k ničemu, provádí XML kanonizaci a té za oběť padnou
nepárové tagy. <br>
skončí jako <br></br>
, což je v HTML nesmysl.
saveXML
v DOMu a asXML
v SimpleXML vytvoří validní XML.
saveHTML
vynechává ukončovací lomítka void elementů, ale všechno
ostatní normalizuje a nesnaží se o žádnou minifikaci.
Když chcete obsah HTML tagu včetně tagu samotného (něco na způsob outerHTML
z JavaScriptu), je to snadné:
$html = "<span id=x> asd <br> asd </span>"; $dom = new DOMDocument; $dom->loadHTML($html); $el = $dom->getElementById('x'); function outerHTML(DOMNode $el): string { return $el->ownerDocument->saveHTML($el); } echo outerHTML($el), "\n"; // <span id="x"> asd <br> asd </span>
Pokud potřebujete innerHTML
, tedy HTML obsah elementu bez ohraničujícího
tagu, jde to takhle:
function innerHTML(DOMNode $el): string { $res = ''; foreach ($el->childNodes as $ch) { $res .= $ch->ownerDocument->saveHTML($ch); } return $res; } echo innerHTML($el), "\n"; // asd <br> asd
Tohle všechno píšu proto, že se někdo ptal, jestli se tohle dá posledně uvedený
manévr provést v knihovně Matcher. I když pro innerHTML
není žádná
speciální podpora, dá se toho snadno dosáhnout řetězením.
$m = Matcher::multi( '//div[@class="second"]', function ($node) { return innerHTML($node); } )->fromHTML();
V tomto případě je první argument multi
matcheru XPath cesta, která
vyprodukuje kolekci DOMNode
elementů. Na každý z nich je posléze aplikována
funkce předaná jako druhý argument a hotovo.
K tématu: