Jump to content

RemexHtml/cs

From mediawiki.org
This page is a translated version of the page RemexHtml and the translation is 100% complete.

Úvod

RemexHtml je parser pro HTML 5, napsaný v PHP.

RemexHtml si klade za cíl:

  • Modularitu a flexibilitu.
  • Rychlost, na rozdíl od elegance. Například někdy používáme přímý přístup k členům místo procházení přístupových objektů a ručně vkládáme kód citlivý na výkon.
  • Robustnost, zaměřenou na výkon O(N) v nejhorším případě.

RemexHtml obsahuje následující moduly:

  • Kompatibilní preprocesor a tokenizátor. Tím se vygeneruje proud událostí tokenu.
  • Konstrukce stromu v souladu s předpisy, včetně zotavení z chyb. Tím se generuje proud událostí mutace stromu.
  • Rychlý integrovaný HTML serializátor, kompatibilní s algoritmem serializace HTML fragmentů.
  • Konstrukce DOMDocumentu.

RemexHtml v současné době postrádá:

  • Podporu kódování. Očekává se, že vstup bude v platném kódování UTF-8.
  • Skriptování.
  • Serializace XHTML.
  • Přesné dodržování specifikovaného generování chyb analýzy.

RemexHtml se snaží být v souladu s doporučením W3C HTML 5.1, s výjimkou drobných oprav chyb přenesených zpět. Rozhodli jsme se implementovat standard W3C namísto nejnovějšího návrhu WHATWG, protože naše aplikace potřebuje více stability než úplnosti funkcí.

RemexHtml prochází všemi testy html5lib, s výjimkou počtu chyb při analýze a testů, které odkazují na budoucí verzi standardu.

Instalace

V MediaWiki

RemexHtml je v MediaWiki k dispozici jako závislost pro tvorbu jádra od verze MediaWiki 1.29. Jeho původním použitím byla náhrada za HTML Tidy. Výstup z analyzátoru wikitextu je odeslán do HTML analyzátoru RemexHtml a vyčištěn podle specifikace HTML 5 tag soup. Komponenta Tokenizer se nyní používá také pro odstraňování značek v Sanitizeru.

Používá se také pro postprocessing HTML v rozšířeních Collection , TEI a Wikibase .

Všude jinde

Nainstalujte balíček wikimedia/remex-html z Packagistu:

composer require wikimedia/remex-html

Používá se sémantické verzování. Číslo hlavní verze se zvýší pro každou změnu, která naruší zpětnou kompatibilitu.

Přehled architektury

Úplnou referenční dokumentaci naleznete v dokumentaci vygenerované ze zdroje (nebo v samotném zdroji).

RemexHtml používá model pipeline. Každý producent událostí volá připojený objekt zpětného volání, když má událost připravenou k vytvoření. Fáze pipeline jsou:

Tokenizer
Vytváří proud tokenů z HTML. Provádí tokenizaci, jak je popsáno v kapitole tokenizace ve specifikaci HTML.
Dispatcher
Sleduje režim vkládání [1] a předává události tokenu obslužné rutině specifické pro aktuální režim vkládání. Každý režim vkládání má svou vlastní třídu s metodami pro každý typ tokenu.
TreeBuilder
Pomocná třída pro režimy vkládání. Sleduje stav procesu konstrukce stromu, přijímá požadavky na mutaci stromu od tříd režimu vkládání a odesílá události mutace stromu.

Ve specifikaci HTML je algoritmus konstrukce stromu představován jako úzce integrovaný s vytvářením datové struktury DOM. Hlavní inovací RemexHtml je oddělení konstrukce stromu na fázi, která generuje proud událostí mutace stromu, a fázi, která skutečně vytváří datovou strukturu. RemexHtml dokáže přímo serializovat proud událostí mutace stromu, aniž by bylo nutné ukládat celý DOM do paměti.

Serializer
Vytváří HTML z proudu událostí mutace stromu.
DOMBuilder
Vytváří nativní PHP DOMDocument z proudu událostí mutace stromu.

Při použití Serializátoru existuje poslední fáze pipeline:

Formatter
Rozhraní Formatter převádí objekty SerializerNode na řetězce. Je to pomocník pro Serializér, který umožňuje snadnou úpravu detailů vygenerovaného HTML. Serializátor je komplexní a stavový, zatímco podtřídy Formatter jsou obecně bezstavové, s výjimkou konfigurace.

RemexHtml také nabízí:

DOMSerializer
Utilita pro serializaci DOM obsaženého v DOMBuilderu s rozhraním podobným Serializátoru.
PropGuard
Mnoho tříd RemexHtml používá vlastnost PropGuard, která zabraňuje náhodnému přiřazení nedeklarovaných vlastností. To pomáhá odhalit zmatek vývojářů ohledně typů tříd. Pokud existuje naléhavá potřeba použít ve vaší aplikaci nedeklarované vlastnosti, lze PropGuard globálně zakázat pomocí přepínače PropGuard::$armed = false.
TokenGenerator
Třída, která poskytuje stream tokenů prostřednictvím rozhraní generátoru namísto streamu událostí. Vytváří si vlastní tokenizátor. Využívání událostí tokenů tímto způsobem je méně efektivní, ale pro některé případy použití může být pohodlnější.

Existují volitelné fáze pipeline poskytující ladicí funkce:

DispatchTracer
Tato třída se nachází mezi Tokenizerem a Dispatcherem. Hlásí všechny události tokenů a hlásí přechody režimů vkládání v rámci Dispatcheru. Zprávy protokolu se odesílají do funkce zpětného volání.
TreeMutationTracer
Toto přeposílá události mutace stromu přicházející z TreeBuilderu a hlásí tyto události zpětnému volání.
DestructTracer
Tato třída přeposílá události mutace stromu a hlásí, kdy je objekt Element vygenerovaný třídou TreeBuilder zničen. To pomáhá identifikovat úniky paměti.

RemexHtml model konfigurovatelné pipeline poskytuje velkou flexibilitu. Aplikace mohou podtřídovat třídy kanálu poskytované RemexHtml nebo si napsat vlastní od nuly a implementovat příslušné rozhraní pro příjem událostí. Nebo mohou vložit vlastní fáze kanálu mezi standardní fáze RemexHtml.

Pro jednoduché případy použití je však k dispozici značné množství standardního vybavení. T217850 navrhuje přidání zjednodušené metody pro konstrukci standardního pipeline, ale ta dosud nebyla implementována.

Příklady

Vytvoření DOMu ze vstupního textu

use Wikimedia\RemexHtml\DOM\DOMBuilder;
use Wikimedia\RemexHtml\TreeBuilder\TreeBuilder;
use Wikimedia\RemexHtml\TreeBuilder\Dispatcher;
use Wikimedia\RemexHtml\Tokenizer\Tokenizer;

function parseHtmlToDom( $input ) {
	$domBuilder = new DOMBuilder();
	$treeBuilder = new TreeBuilder( $domBuilder );
	$dispatcher = new Dispatcher( $treeBuilder );
	$tokenizer = new Tokenizer( $dispatcher, $input );
	$tokenizer->execute();
	return $domBuilder->getFragment();
}

Ve výše uvedeném příkladu kódu je kanál konstruován pozpátku, od konce k začátku. Konstruktor každé fáze pipeline obdrží následující fázi pipeline. Poté, co je pipeline plně zkonstruován, $tokenizer->execute() způsobí, že celý vstupní text bude analyzován a vyslán pipelinem, který nakonec dosáhne DOMBuilderu. Po provedení je vytvořený dokument dostupný prostřednictvím $domBuilder->getFragment().

Změnit cíle odkazů

use Wikimedia\RemexHtml\HTMLData;
use Wikimedia\RemexHtml\Serializer\HtmlFormatter;
use Wikimedia\RemexHtml\Serializer\Serializer;
use Wikimedia\RemexHtml\Serializer\SerializerNode;
use Wikimedia\RemexHtml\Tokenizer\Tokenizer;
use Wikimedia\RemexHtml\TreeBuilder\Dispatcher;
use Wikimedia\RemexHtml\TreeBuilder\TreeBuilder;

function changeLinks( $html ) {
	$formatter = new class extends HtmlFormatter {
		public function element( SerializerNode $parent, SerializerNode $node, $contents ) {
			if ( $node->namespace === HTMLData::NS_HTML
				&& $node->name === 'a'
				&& isset( $node->attrs['href'] )
			) {
				$node = clone $node;
				$node->attrs = clone $node->attrs;
				$node->attrs['href'] = 'http://example.com/' . $node->attrs['href'];
			}
			return parent::element( $parent, $node, $contents );
		}
	};

	$serializer = new Serializer( $formatter );
	$treeBuilder = new TreeBuilder( $serializer );
	$dispatcher = new Dispatcher( $treeBuilder );
	$tokenizer = new Tokenizer( $dispatcher, $html );
	$tokenizer->execute();
	return $serializer->getResult();
}

Tento příklad upravuje HTML dokument za běhu, mění atributy href uvnitř tagů ‎<a> a vrací HTML řetězec. Dělá to tak, že vytvoří podtřídu HtmlFormatter, což je relativně snadný způsob, jak se napojit na reserializaci. Klonuje objekty SerializerNode a Attributes, aby se zabránilo změně dokumentu, jak ho vidí Serializer, protože je možné, že tato funkce bude na každém uzlu volána vícekrát a my nechceme před název domény přidávat vícekrát.

Alternativně jsme mohli použít jako příznak SerializerNode::$snData, abychom se vyhnuli dvojitému prefixu:

if ( !$node->snData ) {
	$node->snData = true;
	$node->attrs['href'] = 'http://example.com/' . $node->attrs['href'];
}

Výkon

Lze povolit různé možnosti, které zlepšují výkon, potenciálně na úkor správnosti:

  • Tokenizer
    • ignoreErrors – tím se chyby analýzy jednoduše neodstraní tak, jak jsou generovány. V některých případech volí efektivnější algoritmus, který implicitně ignoruje chyby. Pokud nejsou vyžadovány chyby při analýze, mělo by být toto vždy nastaveno.
    • skipPreprocess – specifikace HTML vyžaduje, aby byl vstup předzpracován pro normalizaci zakončení řádků a odstranění řídicích znaků. Pokud jsou konce řádků ve vaší aplikaci již normalizovány a nevadí vám, aby se do výstupu šířily kontrolní znaky, lze tuto možnost povolit pro malé zlepšení výkonu.
    • ignoreNulls – povolení této možnosti způsobí, že se do výstupu přenesou všechny nulové znaky. Specifikace HTML vyžaduje komplexní, kontextově závislé zpracování nulových znaků, kdykoli se objeví ve vstupu. Pokud tedy aplikace jednoduše odstraní ze vstupu nulové znaky a povolí tuto možnost, výsledek nebude splňovat standardy, ale výkon se mírně zlepší.
    • ignoreCharRefs – toto je agresivní a zřídka užitečná možnost optimalizace, která ignoruje odkazy na znaky a propouští je beze změny. Je třeba jej spárovat se speciálním serializátorem, který bude z textových uzlů vygenerovat holé ampersandy místo toho, aby je escapoval.
  • TreeBuilder
    • ignoreNulls, ignoreErrors – Stejné jako odpovídající možnosti tokenizátoru


O výjimkách TokenizerError

Pokud RemexHtml vyvolá výjimku TokenizerError, například "pcre.backtrack_limit exhausted", obvykle se nejedná o chybu v RemexHtml. Buď by se mělo zvýšit příslušné nastavení konfigurace, nebo by se měla omezit velikost vstupu. Nastavení INI souboru pcre.backtrack_limit by mělo být alespoň dvojnásobné oproti vstupní velikosti.

Související odkazy


Externí odkazy