Pár postřehů k DOM API v PHP 5. Jde o funkce pro parsování, generování a manipulaci s XML a HTML soubory. Chování se může v různých verzích lišit.
$dom = new DOMDocument();
// konfigurace pro načtení
$dom->preserveWhiteSpace = false;
$dom->load('input.xml');
// konfigurace pro uložení
$dom->formatOutput = true;
$dom->encoding = 'utf-8';
$dom->save('output.xml');
Načtení XML souboru
- metody
$dom->load($fileName)
,$dom->loadXML($string)
- konfigurační vlastnosti:
$dom->resolveExternals
– načíst externí entity z DTD deklarace? Výchozí: false$dom->strictErrorChecking
– throws DOMException on errors? Výchozí: true$dom->validateOnParse
– načíst a validovat oproti DTD? Vychozí: false$dom->preserveWhiteSpace
– zachovat redundantní white space? Výchozí: true$dom->substituteEntities
– zaměnit jmenné entity? Výchozí: false
- validování nebo resolveExternals stahuje DTD – extrémně pomalé!
- aby se nestahovalo DTD:
- ponechat nastavené
resolveExternals = validateOnParse = false
- nebo použít XML Catalogs (nepovedlo se mi rozchodit)
- nebo modifikovat URL v
<!DOCTYPE>
na lokální kopii DTD
- ponechat nastavené
- zpracování DTD je pomalé (tj. i bez stahování)
- načtení XHTML dokumentu trvá cca 50× déle
- validování už pak zpomalí jen mírně
- bez zpracování DTD:
- rozezná jen číselné entity a
< > & "
- je problém s getElementById() (řeší workaround nebo DOMElement->setIdAttributeNode())
- rozezná jen číselné entity a
$dom->encoding
určuje XML deklarace
Uložení XML souboru
- metody
$dom->save($fileName)
,$s = $dom->saveXML()
- generují identický výstup (narozdíl od ukládání HTML)
- konfigurační vlastnosti:
$dom->formatOutput
– generuje „hezčí“ výstup (formátuje podivně)$dom->encoding
– kódování (např.utf-8
,windows-1250
)$dom->standalone
,$dom->version
– XML deklarace
formatOutput
lze povolit jen tehdy, pokud bylo načítáno spreserveWhiteSpace == false
saveXML($node)
s parametrem ignoruje encoding, vždy používá UTF-8
Načtení HTML souboru
- metody
$dom->loadHTMLFile($fileName)
,$dom->loadHTML($string)
- chápe všechny HTML entity
- ignoruje nastavení:
$dom->resolveExternals
(vždy true)$dom->validateOnParse
(vždy false)$dom->preserveWhiteSpace
(vždy true)$dom->substituteEntities
(vždy true)
- je nutné specifikovat kódování meta hlavičkou, jinak použje
ISO-8859-1
, ale vlastnost$dom->encoding
nastaví na null a už nepůjde změnit při ukládání - přepisuje
\r
na
→ odstranit funkcí str_replace - funguje
getElementById()
- nevytváří plnohodnotný DOM, nedoplní např. element body (má volitelné značky)
Uložení HTML souboru
- metody
$dom->saveHTMLFile($fileName)
,$s = $dom->saveHTML()
- negenerují stejný výstup!
- pokud byl vstup načten jako XML (load, loadXML), ukládá špatně prázdné elementy
- ignoruje nastavení:
$dom->formatOutput
(vždy false)$dom->encoding
- saveHTML použije vstupní kódování
- saveHTMLFile použije 7bit ASCII, v meta hlavičce uvádí UTF-8 (není chyba),
Zpracování HTML souboru
// odstraníme \r
$s = file_get_contents('input.html');
$s = str_replace("\r", '', $s);
// parsujeme
$dom = new DOMDocument();
$ok = $dom->loadHTML($s);
// zjistíme obsah <title>
$title = $dom->getElementsByTagName('title')->item(0)->nodeValue;
// nebo šikovněji přes XPath:
$xpath = new DOMXPath($dom);
$title = $xpath->query('//title')->item(0)->nodeValue;
XPath: tutorial, XPather extension
Komentáře
David Grudl #1
Tohle není článek, jen souhrn mých rešerší, sepsaný pro vlastní potřebu. Text nadále doplňuji a upravuji. Budu rád, pokud téma doplníte o další postřehy.
pixy #2
Prefix: mám s tímhle nulové zkušenosti; drobný nápad: nepomohlo by přeuložit nepoužívanější DTD na lokál a přesměrovat PHP na ně?
David Grudl #3
#2 pixy, asi nejsnáze to lze udělat změnou URL v
<!DOCTYPE>
na lokální soubor, zprovoznit XML Catalogs se mi nepodařilo. Nicméně stále je zpracování DTD velmi pomalé – asi 50× prodlouží načtení XHTML souboru.id
zaxml:id
a pak parsovat bez DTD.
marek #4
nevadí že napíšu komentář k nečlánku? :) Co vedlo k napsání komentáře o nečlánku po osmi hodinách od napsání?
David Grudl #5
#4 marku, to je pozůstatek jednoho smazaného komentáře a smazaných reakcí na to, že jsem jej smazal 😉
xom #6
Děkuju za souhrn, velice se to hodí, zvláště, když přemýšlím nad tvorbou PHP OpenXML docx generátoru, který jsem po netu hledal a nějak nenašel – pokud byste někdo o tom generátoru věděl, tak napište, ať nedělám zbytečnou práci (pro tabulkový Excel již existuje PHP Excel
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.