[PHP] Hoe het beste vast deel van html string strippen?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben bezig een eigen (webbased) RSS reader te bouwen. Nu zijn er veel RSS feeds die allerlei zooi toevoegen aan de posts, bijvoorbeeld "Digg this!" en "Email this story!" links en advertenties, meestal toegevoegd door feedburner. MEer wel dan niet staan die in een vaste structuur, bijvoorbeeld bij Reuters:
code:
1
2
3
4
5
<a href="">Titel</a>: Bericht
<div class="feedflare">
  <!-- een heleboel "Digg this" plaatjes enzo...soms ook divjes
</div>
Nog iets belangrijks...

Nu kan ik zoeken waar de feedflare div begint en daar vandaan alles strippen, maar mooier (en wat stabieler) zou zijn om precies de feedflare div te deleten. Zou er dan "Nog iets belangrijks..." achter die div staan, dan neem ik dat niet weg.

Nu is 1 optie om de hele post te tokenizen en dan die div eruit te halen. Maar ik heb dat nog nooit gedaan. Vandaar twee vragen:
[list]
• heeft iemand (een link naar) een voorbeeld van het tokenizen van een html string?
• is er een eenvoudiger manier hiervoor?
[/list]


Er staat nooit iets belangrijks achter de feedflare div. Wat is de meest eenvoudige manier om naar een bepaald deel te zoeken (bv "<div class="feedflare">) en alles vanaf daar te strippen? Dus "<div class="feedflare">Digg this Email this etc........" verwijderen? Ik kan niet zomaar op "<div" ofzo zoeken, want er kunnen andere divs in de post staan...

[ Voor 15% gewijzigd door Verwijderd op 27-10-2009 11:47 ]


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Je moet maar eens naar php's DOMDocument kijken. Dat object kan html inlezen waarna je in php de dom kan bewerken :)

/edit: ik zeg dat nu wel leuk, maar volgens mij kan DOMDocument alleen uitlezen, niet manipuleren. DOMNode kan wel elementen verwijderen, maar ik weet zou gauw niet of je een DOMDocument met DOMNode kan bewerken. DOMNode kan zelf namelijk geen hmtl inlezen.

[ Voor 47% gewijzigd door mithras op 27-10-2009 11:36 ]


Acties:
  • 0 Henk 'm!

  • Kalentum
  • Registratie: Juni 2004
  • Nu online
mithras schreef op dinsdag 27 oktober 2009 @ 11:32:
/edit: ik zeg dat nu wel leuk, maar volgens mij kan DOMDocument alleen uitlezen, niet manipuleren. DOMNode kan wel elementen verwijderen, maar ik weet zou gauw niet of je een DOMDocument met DOMNode kan bewerken. DOMNode kan zelf namelijk geen hmtl inlezen.
Een DOMDocument is gewoon een DOMNode dus je kan nodes verwijderen.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Sorry! Zie TS...het is allemaal minder moeilijk zo het schijnt :)

P.S. Is dat trouwens geen bugje in de UBB parser van GoT? Als je strikethrough-tags zet om een list, krijg je de list en /list tag te zien (hoewel de bulletpoint wel gerendered worden...)?

[ Voor 61% gewijzigd door Verwijderd op 27-10-2009 11:49 ]


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Verwijderd schreef op dinsdag 27 oktober 2009 @ 11:48:
P.S. Is dat trouwens geen bugje in de UBB parser van GoT? Als je strikethrough-tags zet om een list, krijg je de list en /list tag te zien (hoewel de bulletpoint wel gerendered worden...)?
Je kan niet alle elementen nesten in alle andere elementen :p

Een striketrough wordt gerendered in een <span> element. Inline dus. Daar kan je nooit meer een block element als een ordened/unordened list inzetten. Dus dat doet de parser dan ook netjes en parst alle blockelementen binnen de [s][/s] niet meer.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

De quick 'n dirty methode is met regular expressions de zaak replacen. De goeie methode heeft mithras al genoemd. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 11:41
Als alles vanaf <div class="feedflare"> weg mag/moet, kun je toch ook wel str(r)pos en substr gebruiken?

Acties:
  • 0 Henk 'm!

  • flashin
  • Registratie: Augustus 2002
  • Laatst online: 17-12-2023
Gebruik iets als simplehtmldom ;)

http://simplehtmldom.sourceforge.net/

Werkt perfect voor wat je wilt en is nog aardig snel.


PHP:
1
2
3
4
5
6
7
8
9
10
<?php

// Create DOM from string
$html = str_get_html('blablabla<div id="feedflare">Hello</div>');

$html->find('div[class=feedflare]', 0)->innertext = 'foo';

echo $html; 

?>


@hieronder:
Nou eh sorry hoor heer de Moderator.. Ik geef enkel een alternatieve oplossing die eenvoudiger en sneller te implementeren is dan de standaard library (mithras begreep het in eerste instantie ook niet). Qua performance doet het ding niks onder.
Daarnaast geef je zelf ook een quick maar voornamelijk dirty oplossing..

[ Voor 76% gewijzigd door flashin op 27-10-2009 12:17 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Raynman schreef op dinsdag 27 oktober 2009 @ 12:05:
Als alles vanaf <div class="feedflare"> weg mag/moet, kun je toch ook wel str(r)pos en substr gebruiken?
Hoe vind je precies de bijbehorende sluittag? ;) (Geldt overigens ook voor regular expressions.) Dan kun je dus meteen ook een (stackbased?) parser gaan schrijven. Lijkt me wat overkill. :P DOM-functies gebruiken gaat eenvoudiger zijn en sowieso netter uitzien in de code.
flashin schreef op dinsdag 27 oktober 2009 @ 12:07:
Gebruik iets als simplehtmldom ;)

http://simplehtmldom.sourceforge.net/

Werkt perfect voor wat je wilt en is nog aardig snel.
Waarom een third party library gebruiken als het zoals mithras al aangeeft gewoon in PHP zelf zit? :?

[ Voor 26% gewijzigd door NMe op 27-10-2009 12:08 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

Verwijderd

Ik doe het vaak gewoon met split:

$split = split('</div>', $zooi);
$belangrijk = $split [1];

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 09:51

crisp

Devver

Pixelated

Och, een klein beetje stack-based parsen is niet zo lastig hoor. Even q&d:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$startPos = strpos($html, '<div class="feedflare">');
$endPos = findEndTag('div', $html, $startPos + 1);
$html = substr($html, $startPos, $endPos - $startPos);

function findEndTag($tagName, $html, $startPos)
{
    $re = '/<(\/?)' . $tagName . '(\s[^>]*)?>/i';
    if (preg_match_all($re, $html, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE, $startPos))
    {
        $nestLevel = 1;
        foreach ($matches as $match)
        {
            if ($match[1][0])
            {
                $nestLevel--;
                if ($nestLevel == 0)
                    return $match[0][1] + strlen($match[0][0]);
            }
            else
            {
                $nestLevel++;
            }
        }
    }

    return strlen($html);
}

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
NMe schreef op dinsdag 27 oktober 2009 @ 12:07:
[...]

Hoe vind je precies de bijbehorende sluittag? ;) (Geldt overigens ook voor regular expressions.) Dan kun je dus meteen ook een (stackbased?) parser gaan schrijven. Lijkt me wat overkill. :P DOM-functies gebruiken gaat eenvoudiger zijn en sowieso netter uitzien in de code.
Zolang er geen geneste div tags in kunnen zitten is dat natuurlijk niet zo'n probleem, en zou ik het waarschijnlijk gewoon met een regex oplossen. Mocht het wat complexer worden, dan kun je inderdaad het best gewoon naar een DOM oplossing kijken.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Waarom zo allemaal zelf uitschrijven :? Als php het al in zich heeft, kan je toch veel makkelijker dat gebruiken?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$html = '<a href="">Titel</a>: Bericht
<div class="feedflare">
  een heleboel "Digg this" plaatjes enzo...soms ook divjes
</div>
Nog iets belangrijks...;';

$filter = array(
  'div' => array('class', 'feedflare')
);

$dom = new DOMDocument;
$dom->loadHtml($html);
foreach ($filter as $tag => $options) {
  $list = $dom->getElementsByTagName($tag);
  foreach ($list as $element) {
    if ($element->getAttribute($options[0]) === $options[1]) {
      $element->parentNode->removeChild($element);
    }
  }
} 

echo $dom->saveHTML


Feitelijk maar 10 regels, waarbij je de tagname kan specificeren en het element wat moet matchen. Het kan bij een andere feed net zo goed een <p> element zijn met id="extras" :)

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 09:51

crisp

Devver

Pixelated

mithras schreef op dinsdag 27 oktober 2009 @ 12:33:
[...]
Waarom zo allemaal zelf uitschrijven :? Als php het al in zich heeft, kan je toch veel makkelijker dat gebruiken?
Ik kan wel redenen bedenken om hier een eigen simpel parsertje voor te gebruiken hoor. In de eerste plaats natuurlijk performance, en in de tweede plaats puur controle. DOMDocument is immers een black box; je weet niet wat voor parser er achter hangt en in hoeverre die geschikt is voor alle mogelijke tagsoup die je op het web kan tegenkomen*. Sowieso heb je kans dat bij mallformed input saveHTML() iets heel anders uitpoept dan je er in eerste instantie ingestopt had, en dat kan in bepaalde situaties onwenselijk zijn. Ook het werken met (incomplete) fragments is lastig.

* mijn q&d oplossing is daar evenmin geschikt voor natuurlijk ;)

[ Voor 4% gewijzigd door crisp op 27-10-2009 12:52 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
crisp schreef op dinsdag 27 oktober 2009 @ 12:47:
[...]

Ik kan wel redenen bedenken om hier een eigen simpel parsertje voor te gebruiken hoor. In de eerste plaats natuurlijk performance, en in de tweede plaats puur controle. DOMDocument is immers een black box; je weet niet wat voor parser er achter hangt en in hoeverre die geschikt is voor alle mogelijke tagsoup die je op het web kan tegenkomen*. Sowieso heb je kans dat bij mallformed input saveHTML() iets heel anders uitpoept dan je er in eerste instantie ingestopt had, en dat kan in bepaalde situaties onwenselijk zijn. Ook het werken met (incomplete) fragments is lastig.

* mijn q&d oplossing is daar evenmin geschikt voor natuurlijk ;)
Plus het feit dat je hiervan veel meer kunt leren :) Bedankt voor alle reakties, maar ik ga eens even fijn prutsen met wat crisp heeft geschreven. Een parser bouwen heeft voor mij altijd hokus-pokus geklonken, maar nu heb ik iets om vanuit te gaan :)
Pagina: 1