[PHP/X(HT)ML] X(HT)ML parser begrijpt me niet

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • kikker81
  • Registratie: Mei 2007
  • Laatst online: 28-08 15:59
Na heel wat jaar geen aandacht besteed te hebben aan PHP ben ik er sinds kort weer mee bezig.
De onderstaande code zal dus ook allesbehalve perfect zijn maar ik hoop dat jullie de bedoeling ervan begrijpen.
Wat ik probeer te maken is een parser die een XHTML bestand opent en aan de hand van het ID van de tags, deze eventueel leegmaakt (tussen de tags) en de content uit de database er inzet.
Dit gaat in principe ook goed zoals ook te zien op http://85.17.199.46/~olcea/, er gaat alleen één ding fout en dat zijn tags zonder afsluiting (img, br enzo). Hij maakt dus van <img ... /> <img ...></img>. Nu zou ik dus een lijst van dit soort tags in een array kunnen zetten en vervolgens bij elke tag kijken of ie afgesloten moet worden of niet, maar dat vind ik nogal lomp, en ik zie eigenlijk geen andere oplossing hiervoor.
Iemand anders een idee?

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
include '../application/models/content.php';
class IndexController extends Zend_Controller_Action 
    {
    public function indexAction()
        {
        global $tags, $result, $contentitems, $data, $parseddata;
        $content = new GetContent();
//      haal de content die bij de pagina hoort op uit de database      
        $result = $content->getAdapter()    ->select()  
                                            ->from('blocks', 'tid')
                                            ->joinUsing('content', 'cid')
                                            ->where('pid = ?', 'Home')
                                            ->query()
                                            ->fetchAll();
                                            
        $xml_file = "templates/olcea1.0/index.html";
        
        $counter = 0;

        function startTag($parser, $data, $attribs)
            {
            global $current_tag, $current_id, $dbcontent, $counter, $parseddata, $result, $replacetag, $tagcontent;
            $tagAttribs = FALSE;
//          level in de document tree + 1
            $counter++;
//          als tag niet binnen de te vervangen content valt 
            if (!$replacetag)
                {
                $parseddata .= "<" . strtolower($data);
//              als het aantal attributen in de tag geen 0 is
                if (count($attribs) != 0)
                    {
                    foreach ($attribs as $attrKey => $attrValue)
                        {
                        $tagAttribs .= " " . strtolower($attrKey) . "=\"" . $attrValue . "\"";
                        }
                    $parseddata .= $tagAttribs;
                    }
                $parseddata .= ">";
//                  als het attribuut ID bestaat in de tag
                if (array_key_exists('ID', $attribs)) 
                    {
                    $attribsId = $attribs['ID'];
                    foreach ($result as $key => $value)
                        {
                        foreach ($result[$key] as $key2 => $value2)
                            {
//                          als het attribuut ID uit de tag overeenkomt met de ID van de content uit de database
//                          plaats de content uit de database
                            if ($value2 == $attribs['ID'])
                                {
                                $tagcontent = $result[$key]['content'];
//                              zet bijbehorende content uit de database na de tag
                                $parseddata .= $tagcontent;
                                $newcontentadded = TRUE;
                                $replacetag = $counter;
                                }
                            }
                        }
                    }
                }
            }

        function endTag($parser, $data)
            {
            global $current_tag, $current_id, $dbcontent, $counter, $parseddata, $replacetag, $newcontentadded, $tagcontent;
            if ($replacetag == $counter) 
                {
//              eind tag bereikt
                $replacetag = FALSE;
                $newcontentadded = FALSE;
                }
//          als tag niet binnen de te vervangen content valt 
            if (!$replacetag)
                {
                $parseddata .= "</" . strtolower($data) . ">";
                }
//          level in de document tree -1
            $counter--;
            }

        function tagContents($parser, $data)
            {
            global $parseddata, $replacetag;
//          als de content tussen de tags niet binnen de te vervangen content valt 
            if (!$replacetag)
                {
                $parseddata .= $data;
                }
            }

        function docContents($parser, $data)
            {
            global $parseddata;
            $parseddata .= $data;
            }

        $xml_parser = xml_parser_create();

        xml_set_element_handler($xml_parser, "startTag", "endTag");
        xml_set_character_data_handler($xml_parser, "tagContents");
        xml_set_default_handler($xml_parser, "docContents");

        $fp = fopen($xml_file, "r") or die("Could not open file");
        $data = fread($fp, filesize($xml_file)) or die("Could not read file");

        if(!(xml_parse($xml_parser, $data, feof($fp))))
            {
            die("Error on line " . xml_get_current_line_number($xml_parser));
            }

        xml_parser_free($xml_parser);
        fclose($fp); 
        $this->view->template = $parseddata;
        $this->render();
        }
    }

Acties:
  • 0 Henk 'm!

  • Face_-_LeSS
  • Registratie: September 2004
  • Niet online
Wat is het doel hiervan? Wanneer het gaat om templates parsen zou ik gewoon een bestaan de templateparser gebruiken.

Acties:
  • 0 Henk 'm!

  • kikker81
  • Registratie: Mei 2007
  • Laatst online: 28-08 15:59
Face_-_LeSS schreef op vrijdag 04 april 2008 @ 14:03:
Wat is het doel hiervan? Wanneer het gaat om templates parsen zou ik gewoon een bestaan de templateparser gebruiken.
Het doel ervan is dat ik geen code in het HTML bestand hoef toe te voegen.
Ik weet dat het wellicht wat omslachtig is, maar ik ben er nou eenmaal mee begonnen dus nu wil ik 'm ook afmaken, om er van te leren zegmaar...

Acties:
  • 0 Henk 'm!

  • Face_-_LeSS
  • Registratie: September 2004
  • Niet online
In dat geval zou ik gewoon de "self-closing" tags in een array zetten en controleren of de desbetreffende voorkomt in die array. Dat is niet zo vies hoor.

Acties:
  • 0 Henk 'm!

  • kikker81
  • Registratie: Mei 2007
  • Laatst online: 28-08 15:59
Face_-_LeSS schreef op vrijdag 04 april 2008 @ 14:29:
In dat geval zou ik gewoon de "self-closing" tags in een array zetten en controleren of de desbetreffende voorkomt in die array. Dat is niet zo vies hoor.
Heb ik nu ook gedaan, het waren er toch ook niet zoveel dus het was wel te overzien.
Ik had het vermoeden dat dit niet de snelste manier van parsen zou zijn, maar dat valt zo te zien nog mee (0.00832 sec) of valt dat niet te beoordelen bij een pagina met zo weinig content?

Acties:
  • 0 Henk 'm!

  • Face_-_LeSS
  • Registratie: September 2004
  • Niet online
Ik weet niet hoe veel content je pagina bevat maar om het goed te kunnen testen zou ik het een paar honderd keer uitvoeren met verschillende pagina's van verschillende grootte. Vervolgens het gemiddelde berekenen en dan kijken of het acceptabel is :)

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
kikker81 schreef op vrijdag 04 april 2008 @ 15:50:
[...]


Heb ik nu ook gedaan, het waren er toch ook niet zoveel dus het was wel te overzien.
Ik had het vermoeden dat dit niet de snelste manier van parsen zou zijn, maar dat valt zo te zien nog mee (0.00832 sec) of valt dat niet te beoordelen bij een pagina met zo weinig content?
Ik denk dat het de snelheid weinig beïnvloed, maar je zal de parser zo moeten schrijven dat hij bij een self-closing tag de starttag ook als eindtag kan markeren. Je moet dus niet verder dan de start tagzoeken, maar beginnen bij de starttag met zoeken.
Vervolgens kijk je naar de clausule dat het zowel mogelijk is om de tag direct af te sluiten (door aan het einde de / te plaatsen), of deze open te laten en dus verder de tree te doorlopen om naar de eindtag te zoeken.

Op deze manier kan je afaik selfclosingtags identificeren :)

Acties:
  • 0 Henk 'm!

  • kikker81
  • Registratie: Mei 2007
  • Laatst online: 28-08 15:59
mithras schreef op vrijdag 04 april 2008 @ 16:13:
[...]
Ik denk dat het de snelheid weinig beïnvloed, maar je zal de parser zo moeten schrijven dat hij bij een self-closing tag de starttag ook als eindtag kan markeren. Je moet dus niet verder dan de start tagzoeken, maar beginnen bij de starttag met zoeken.
Vervolgens kijk je naar de clausule dat het zowel mogelijk is om de tag direct af te sluiten (door aan het einde de / te plaatsen), of deze open te laten en dus verder de tree te doorlopen om naar de eindtag te zoeken.

Op deze manier kan je afaik selfclosingtags identificeren :)
Hmm, ja zoiets dacht ik ook, maar ik gebruik de XML parser van PHP en die pakt automatisch de naam van de tag en de attributes, maar hij ziet geen verschil tussen /> en </div> als closing tag.
Ik heb het nu gedaan zoals Face_-_LeSS ook al aangaf, gewoon de self closing tags in een array gezet...
In ieder geval bedankt voor de reacties! Als iemand nog wat opvalt aan de code hoor ik het graag, ik heb lang geen php gedaan en destijds prutste ik ook altijd maar wat ;).

Acties:
  • 0 Henk 'm!

  • Face_-_LeSS
  • Registratie: September 2004
  • Niet online
Het detecteren van de close tag is inderdaad netter alleen wanneer het om html gaat kan het voorkomen dat een self-closing tag (hr, br, img, meta, input en link) niet ge "self-closed" wordt door een "/".

Wanneer de html van je zelf is is dat niet zo'n punt want dan moet je gewoon zorgen dat er overal een "/" aan het einde van de open-tag staat maar wanneer de html van een derde komt weet je dat natuurlijk niet.

Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

waarom probeer je niet eens je template in te laden dmv DomDocument->loadHTML ? Dan hoef je niet zelf het wiel uit te gaan vinden :)

http://nl.php.net/manual/...-domdocument-loadhtml.php

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • kikker81
  • Registratie: Mei 2007
  • Laatst online: 28-08 15:59
SchizoDuckie schreef op zaterdag 05 april 2008 @ 19:45:
waarom probeer je niet eens je template in te laden dmv DomDocument->loadHTML ? Dan hoef je niet zelf het wiel uit te gaan vinden :)

http://nl.php.net/manual/...-domdocument-loadhtml.php
8)7 waarom heb ik die niet gevonden...
Dit ziet er interessant uit! Ga er gelijk mee aan de slag...

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
28
29
30
31
include '../application/models/content.php';
class IndexController extends Zend_Controller_Action 
    {
    public function indexAction()
        {
//      haal de content die bij de pagina hoort op uit de database  
    
        $result = $content->getAdapter()    ->select()  
                                            ->from('blocks', 'tid')
                                            ->joinUsing('content', 'cid')
                                            ->where('pid = ?', 'Home')
                                            ->query()
                                            ->fetchAll();
 
        $template = new DOMDocument();
        $template->validateOnParse = true;
        $template->loadHTMLFile("templates/olcea1.0/index.html");
        
        foreach ($result as $key => $value)
            {
            $result[$key]['tid'];
            if ($template->getElementById($result[$key]['tid']))
                {
                $element = $template->getElementById($result[$key]['tid']);
                $textNode = $template ->createCDataSection($result[$key]['content']);
                $element->appendChild($textNode);
                }
            }
        $this->view->template = $template->saveHTML();
        }
    }


edit: bovenstaand dus de code die exact hetzelfde doet als die in de eerste post, ietsje minder code nodig ;)

[ Voor 56% gewijzigd door kikker81 op 07-04-2008 10:40 ]


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

't is inderdaad een heilige functie waar nog veel te weinig over gepost is :P Beter toch zo die code :D _O_

Stop uploading passwords to Github!

Pagina: 1