Autor | Zpráva | ||
---|---|---|---|
Fisir Profil |
#1 · Zasláno: 26. 8. 2014, 19:31:33
Ahoj.
Mám text formátovaný pomocí BB kódů. Ty postupně parsuji, mohou být jak řádkové ( [>i] , [>b] , …) tak i blokové ([>li] , [>h] , …). Potud je to OK. Ale nemám tagy pro ohraničení odstavců. (A ani je nechci přidávat, snižuje to komfort.) Jsem ve stavu, kdy mám všechy BB kódy zpracované a mám vyrobené HTML.
Nyní však potřebuji samostatné bloky textu přeměnit na odstavce (uzavřít je do elementu p ). A tady je problém. Jednoduchý regulární výraz typu nahraď všechna dvojitá odřádkování za </p><p> použít nemůžu, protože se v kódu vyskytují právě třeba ty seznamy (<li> ).
Pokoušel jsem se toho dosáhnout použitím třeba HTMLPurifieru, ale to je kanón na vrabce, protože šíleně zpomalí načítání a já z něj potřebuji právě jen tu jednu funkci. Pak jsem zkusil jakousi funkci, která mi ovšem do odstavce obalila i konstrukce typu <h2>Bla<a name="bla>#bla</a></h2> .
Nevíte o nějakém řešení, knihovně, …? |
||
Str4wberry Profil |
#2 · Zasláno: 26. 8. 2014, 19:47:27
Menší kanón na vrabce je Texy!.
Jinak přesně proč vadí odstavec v položce seznamu? |
||
Fisir Profil |
#3 · Zasláno: 26. 8. 2014, 19:56:35
Reaguji na Str4wberryho:
„Jinak přesně proč vadí odstavec v položce seznamu?“ Asi jsem se špatně vyjádřil. Ze druhé zmíněné varianty vylezlo toto: <p><ul></p> <li>položka seznamu</li> <p></ul></p> |
||
Jan Tvrdík Profil |
#4 · Zasláno: 26. 8. 2014, 19:56:55
Fisir:
Buď si můžeš postavit AST z bbcode, nebo DOM z výsledného HTML a nad tím pak pustit inteligentní algoritmus na vytváření těch odstavců. |
||
Joker Profil |
#5 · Zasláno: 26. 8. 2014, 22:37:21
Primitivnější, ale možná účinná metoda by byla nejdřív nahradit ty ostatní značky a požrat odřádkování a potom udělat odstavce.
Koukám, jak se ten problém řeší v RS na Péhápku. A jestli koukám dobře, prostě ty „přebytečné“ odstavce následně odstraní. Jinak při nahrazování BBCode bude asi lepší do kódu vkládat jen <p> než </p><p> , ukončovací značka odstavce není povinná a ten výraz s ní bude do kódu vkládat nadbytečné ukončovací značky (protože ne vždycky je v tu chvíli nějaký odstavec vůbec otevřený).
|
||
Jan Tvrdík Profil |
#6 · Zasláno: 26. 8. 2014, 23:03:15
Joker:
„Koukám, jak se ten problém řeší v RS na Péhápku“ Na to moc nekoukej, protože zrovna tam je to vyřešené špatně. |
||
Fisir Profil |
#7 · Zasláno: 27. 8. 2014, 17:35:45
Děkuji.
Poradíte mi, jak se dají v DOMDocumentu najít takové čistě textové nebo inline nody? |
||
Jan Tvrdík Profil |
#8 · Zasláno: 27. 8. 2014, 17:43:54
|
||
Fisir Profil |
Dobře. Mám tohle:
$textnodes = $xpath->query('//text()'); foreach($textnodes as $textnode){ if($textnode->parentNode->nodeName === 'body' and !empty($textnode->nodeValue)){ $lines = explode("\n", $textnode->nodeValue); $replacement = array(); foreach($lines as $line){ $replacement = $dom->createElement('p', rtrim($line, "\n\r")); $textnode->parentNode->insertBefore($replacement, $textnode); } $textnode->parentNode->removeChild($textnode); } } Což mi zajistí, že se mi samostatné bloky textu obalí do odstavce. Teď se mi ale nedaří zajistit, aby se do odstavce obalovaly i inline elementy. Nemůžu najít žádný selektor, který by mi vybral inline elementy. Tak nic, tohle je taky blbost. Nějak to nefunguje na všem. |
||
Jan Tvrdík Profil |
Fisir:
„odstavce obalovaly i inline elementy“ Čemu říkáš inline elementy? Ty, co mají ve výchozím display: inline ? Jako třeba <img> ?
„Tak nic, tohle je taky blbost. Nějak to nefunguje na všem.“ Neměl bys konkrétní příklad, kdy to nefunguje? Já bych řekl, že na to jdeš docela dobře, ač to samozřejmě není dotažené. Co něco jako function createParagraphs($html) { $whitelist = [ 'a', 'b', 'body', 'del', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i', 'ins', 'small', 'span', 'strong', ]; $document = new DOMDocument(); $document->loadHTML($html); $xpath = new DOMXPath($document); foreach ($xpath->query('//text()') as $textNode) { $parent = $textNode->parentNode; if (in_array($parent->nodeName, $whitelist, TRUE)) { $lines = explode("\n", $textNode->nodeValue); foreach ($lines as $line) { $line = rtrim($line); if ($line !== '') { $p = $document->createElement('p', $line); $parent->insertBefore($p, $textNode); } } $parent->removeChild($textNode); } } return $document->saveHTML(); } |
||
Fisir Profil |
#11 · Zasláno: 28. 8. 2014, 14:50:29
Reaguji na Jana Tvrdíka:
Použil jsem tvoji funkci, jako vstup jsem ji dal: <h2>Kapitola 1</h2> Tohle je <strong>jenom</strong> testovací <em>text</em>. Nic tu není ke čtení. Další text… <strong>Vážně ne.</strong> <pre>Zato je tu <span class="css-property">nějaký</span> kód. Kód, kód.</pre> Výsledek: <h2><p>Kapitola 1</p></h2> <p>Tohle je</p> <strong><p>jenom</p></strong><p> testovací</p> <em><p>text</p></em><p>.</p> <p>Nic tu není ke čtení.</p> <p>Další text…</p> <strong><p>Vážně ne.</p></strong><pre>Zato je tu <span class="css-property"><p>nějaký</p></span> kód. Kód, kód.</pre> Jestliže jsem použil tu svou, vyšlo toto: <h2>Kapitola 1</h2> <p></p> <p>Tohle je </p> <strong>jenom</strong><p> testovací </p> <em>text</em><p>.</p> <p></p> <p>Nic tu není ke čtení.</p> <p></p> <p>Další text…</p> <p></p> <p></p> <strong>Vážně ne.</strong><p></p> <p></p> <p></p> <pre>Zato je tu <span class="css-property">nějaký</span> kód. Kód, kód.</pre> Optimální výsledek by měl být: <h2>Kapitola 1</h2> <p>Tohle je <strong>jenom</strong> testovací <em>text</em>.</p> <p>Nic tu není ke čtení.</p> <p>Další text…</p> <p><strong>Vážně ne.</strong></p> <pre>Zato je tu <span class="css-property">nějaký</span> kód. Kód, kód.</pre> „Čemu říkáš inline elementy? Ty, co mají ve výchozím display: inline ? Jako třeba <img> ?“
Ano, přesně ty. Momentálně bych tedy potřeboval zajistit, aby to „ignorovalo“ inline elementy – neukončilo to při jejich přítomnosti odstavec ale zahrnulo je do něj. |
||
Fisir Profil |
#12 · Zasláno: 30. 8. 2014, 13:39:23
Vyřešil jsem další problém s vytvářením odstavců. V případě, že vstup byl pouze a jen text (žádné další elementy), automaticky se obalil do odstavce. Ale celý, tudíž ho potom funkce nechytala. Obalil jsem tedy vstup do
div#container a nyní kontroluji, zda je právě on rodič. Když ano, rozsekám obsah text nodu po řádkách a obalím je do odstavce.
Při použití mojí původní funkce (která se nakonec jeví jako lepší, je s ní méně potíží) už odstraňuji prázdné elementy. Problém s rozdělením odstavce u inline elementů stále přetrvává. |
||
Jan Tvrdík Profil |
Fisir:
To mi připomíná, že jsem to řešení sice ve čtvrtek napsal, ale zapomněl jsem ho sem poslat =) function createParagraphs(DOMElement $body) { $inlineTags = ['a', 'b', 'del', 'em', 'i', 'img', 'ins', 'small', 'span', 'strong']; $create = TRUE; $document = $body->ownerDocument; for ($node = $body->firstChild; $node; $node = $next) { $next = $node->nextSibling; if ($node instanceof DOMText) { $children = explode("\n", $node->nodeValue); $body->removeChild($node); $node = $next; } elseif ($node instanceof DOMElement && in_array($node->nodeName, $inlineTags, TRUE)) { $children = [$node]; } else { $children = []; $create = TRUE; } foreach ($children as $child) { if ($child !== '') { if ($create) { $p = $body->insertBefore($document->createElement('p'), $node); $create = FALSE; } $p->appendChild(is_string($child) ? $document->createTextNode($child) : $child); } else { $create = TRUE; } } } } |
||
Fisir Profil |
#14 · Zasláno: 3. 9. 2014, 18:25:53
Reaguji na Jana Tvrdíka:
Jo, díky, já už jsem to vyřešil tak, že jsem nejdřív převedl blokové BB kódy, vyrobil odstavce a až pak proběhl převod těch řádkových. |
||
Jan Tvrdík Profil |
#15 · Zasláno: 3. 9. 2014, 19:46:05
Fisir:
To nebude fungovat moc spolehlivě, ne? Třeba v následujícím případě to udělá odstavec uvnitř <i> .
[i] A B [/i] |
||
Fisir Profil |
#16 · Zasláno: 3. 9. 2014, 20:46:18
Reaguji na Jana Tvrdíka:
Hm, ani já si nejsem příliš jistý, jak by se v tomto případě měl parser zachovat, ale myslím, že takovéhle konstrukce to snad ani nepotká. Každopádně, ta tvá funkce funguje nějakým (pro mne) záhadným způsobem, protože odstavce zastavuje až na začátku dalšího blokového elementu a někdy je rozdělí i u řádkového. Asi to nemá cenu dál řešit. |
||
Časová prodleva: 10 let
|
0