Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][XML] Parsowanie niedoskonałego dokumentu
Forum PHP.pl > Forum > PHP
wNogachSpisz
Witam, mam taki oto kod HTML:

  1. <p>
  2. <div><input type="text"></div>
  3. </p>
  4. <p>
  5. <div></div>
  6. </p>
  7. </body>
  8. </html>


Szukam sposobu aby swobodnie przezeń traversować. Niestety, kod nie jest prawidłowym XMLelem ani HTMLem. Po pierwsze w paragrafach nie mogą znajdować się elementy blokowe i dom:document podczas ładowania dokumentu wyrzuca DIV'y na koniec BODY, w efekcie obiekt DOM jest inny niż mogłoby wynikać z kodu HTML i staje się praktycznie bezużyteczny. Natomiast SimpleXML informuje że element input jest nieprawidłowo zakończony, oczywiście ma racje.

Jak zatem ugryść taki dokument?

Z góry dzięki za pomoc.
szagi3891
Spróbuj tego : http://php.net/manual/en/domdocument.loadhtml.php

Ta funkcja wczytuje kod html do obiektu DOMDocument.
wNogachSpisz
Cytat(szagi3891 @ 13.02.2012, 00:32:47 ) *
Spróbuj tego : http://php.net/manual/en/domdocument.loadhtml.php

Ta funkcja wczytuje kod html do obiektu DOMDocument.

Rozumiem że czytanie pytań boli, ale może zrobisz wyjątek i zadasz sobie ten trud. Tylko ten jeden raz, proszę, zrób to dla mnie.

Stwierdziłem że najlepiej pogodzić się ze zmianami jakie wprowadza DOM:Document. Czyli robie tak ze ładuje nieprawidłowy HTML przez loadHTML, potem zapisuje przez saveHTML i trawersuje po takim jaki został zwrócony. Nie wiem dlaczego od razu na to nie wpadłem tongue.gif
viking
Możesz przepuścić zawsze przez html tidy. A input w HTML5 jest prawidłowy.
wNogachSpisz
Cytat(viking @ 13.02.2012, 06:53:26 ) *
Możesz przepuścić zawsze przez html tidy. A input w HTML5 jest prawidłowy.

Nie natąpi żaden postęp, przeciwnie, program się skomplikuje i zwolni.
Na domiar złego nie ma pewności, że tidy zmodyfikuje każdy dokument w ten sam sposób co DOM:Document.
Także albo czegoś nie rozumiem, albo to co proponujesz nie ma najmniejszego sensu.
Methestel
Jak na moje oko to przedewszystkim musisz dojść do postaci XML-a. Jak już będziesz miał XML-a to już będzie z górki. Będziesz mógł przestawiac/wywalać/dodawać elementy jak tylko będziesz chciał.

Swego czasu napisałem klasę do naprawiania zepsutych XML-i. XML-e które otrzymywałem były urwane (czyli najczęściej tagi nie były podomykane). Rozwiązałem ten problem w taki oto sposób:

  1. class MalformedXML {
  2. private static $tags = array();
  3.  
  4. private static function tagText($parser, $str) {
  5. echo $str;
  6. }
  7.  
  8. private static function tagStart($parser, $tagName, $attr) {
  9. array_push(self::$tags, $tagName);
  10. $t = '<'.$tagName;
  11. foreach($attr as $key => $value) {
  12. $t .= ' '.$key.'="'.$value.'"';
  13. }
  14. echo $t.'>';
  15. }
  16.  
  17. private static function tagEnd($parser, $tagName) {
  18. echo '</'.$tagName.'>';
  19. array_pop(self::$tags);
  20. }
  21.  
  22. public static function fix (&$xml) {
  23. $xml = str_replace("\n", '', $xml);
  24. $xml = str_replace("\r", '', $xml);
  25. //Jeśli ostatni znacznik został urwany w połowie to go usuwamy
  26. $xml = preg_replace('/^(.*)<[^>]*$/s', '$1', $xml);
  27. //Wywalamy wszystkie pojedyńcze znaczniki z początku dokumentu
  28. $xml = preg_replace('/^(<[^>]*\/>)*(.*)$/s', '$2', $xml);
  29. $xml = trim($xml);
  30. $xml = str_replace('&', '&amp;', $xml);
  31. $parser = xml_parser_create();
  32. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
  33. xml_set_character_data_handler($parser, array('MalformedXML', 'tagText'));
  34. xml_set_element_handler($parser, array('MalformedXML', 'tagStart'), array('MalformedXML', 'tagEnd'));
  35.  
  36. xml_parse($parser, "<root>$xml</root>");
  37.  
  38. //Domykamy niedomknięte tagi
  39. while(!empty(self::$tags)) {
  40. echo '</'.array_pop(self::$tags).'>';
  41. }
  42.  
  43. $doc = new DOMDocument('1.0', 'utf-8');
  44. $doc->loadXML(ob_get_contents());
  45.  
  46. if ($doc->documentElement == null) {
  47. throw new Exception("Nie udalo się naprawić");
  48. }
  49. $xml = $doc->saveXML($doc->documentElement);
  50. $xml = str_replace('</root>', '', $xml);
  51. $xml = str_replace('<root>', '', $xml);
  52. return $xml;
  53. }
  54. }
  55.  
  56. $str = '<html>
  57. <body>
  58. <p>
  59. <div><input type="text"></div>
  60. </p>
  61. <p>
  62. <div></div>
  63. </p>
  64. </body>
  65. </html>';
  66.  
  67. echo MalformedXML::fix($str);
  68. //Wynik: <html><body><p><div><input type="text"/></div></p></body></html>


Klasa ta nie jest dokładnie przetestowana, prawdopodobnie będziesz musiał ją dostosować do swoich potrzeb.

To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.