Komentáře k článku

XMLReader – když se zamotáme do SAX

PHP logo

V minulém dílu seriálu o práci s XML soubory v jazyce PHP jsme probírali rozhraní SAX. V dnešním pokračování je na řadě rozhraní XMLReader, které je do určité míry podobné (zpracovává XML soubor po částech), ale používá opačný směr toku událostí a dovoluje zjednodušit kód výsledné aplikace.

Zpět na článek

11 komentářů k článku XMLReader – když se zamotáme do SAX:

  1. brablc

    No nevim

    Byl jsem na Webexpu a poprve slysel o XMLReader a tesil se na pokracovani clanku o XML tady, ale ted jsem trosku rozpacity.

    I tenhle jednoduchy priklad ukazuje, ze to ma koncepcni chyby. Element link se poprve vyskytuje zde: /rss/channel/i­mage/link. Takze prvni nalezeni tohoto elementu se tiskne jeste predtim nez mame title z /rss/channel/title takze H1 mame ve vysledku 2× a jako premii PHP Notice.

    To by se dalo nejak opravit, ale z ceho me mrazi je ten vnoreny „while ($reader->read())“. Porad jsem marne hledal misto, kde se to opousti po ukonceni elementu item a nenasel. Ono to fakt bezi furt dal. Takze pokud bude jednomu itemu chybet title, tak se tam vesele natiskne ten predchozi.

    1. Jiří KosekAutor příspěvku

      Re: No nevim

      V článku je jen primitivná ukázka využití XMLReaderu.

      Nic vám nebrání udělat si dokonalejší logiku zpracování. Např. mazat $title v okamžiku, kdy narazíte na koncový tag elementu item.

      Další varianta je zapnout validaci a parser pak havaruje v případě, kdy narazí na položky bez názvu – ten je v RSS povinný (pamatuju-li si to dobře).

      Nicméně obecně v proudových parserech jako SAX a XMLReader si každopádně musíte držet nějakou stavovou informaci. Rozdíl je v tom, že v XMLReaderu ji nepotřebujete tolik a navíc pro obsluhu podelementů můžete do sebe cykly volající $reader->read() zanořovat (a vyskočit z nich při nalezení koncového tagu), čímž se vše zase zjednoduší.

      1. Jakub Vrána

        Re: No nevim

        Validace v tomto případě nepomůže, protože kód závisí na pořadí jednotlivých značek (které v RSS není určeno) a navíc na absenci povolených značek (konkrétně <image>).

        Sám píšeš, že u proudových parserů je potřeba si držet informaci o stavu. Zásadní chybu příkladů (u minulého a tohoto článku) vidím v tom, že si tento stav nedrží. Příklady pak vůbec neodpovídají skutečnému použití.

        1. Jiří KosekAutor příspěvku

          Re: No nevim

          Ten příklad není psán jako obecná čtečka RSS, ale jako čtečka XML formátu z prvního dílu seriálu – počítá se se pevným pořadím elementů (což obecně RSS nemá a je to přiznejme si spíše prasárna tohoto formátu).

          Obecně formáty, ve kterých se přenášejí velká data a je potřeba používat proudové zpracování mají pevné pořadí podelementů, takže tam tenhle problém odpadá.

          Ty příklady jsou trochu umělé a trochu zjednodušené, aby se ukázalo použití rúzných API pro řešení stejné úlohy. Samozřejmě v praxi si pro danou úlohu vyberete nejvhodnější prostředek. Konvertovat RSS do HTML čímkoliv jiným než XSLT je čirý masochismus.

          Jinak obsluhu toho, aby se nezpracovával link uvnitř jiných elementů, lze jednoduše vyřešit tím, že tyto elementy se na začátku cyklu přeskočí:

          // přeskočíme image a textinput, protože může obsahovat link, který nás nezajímá
          if ($reader->nodeType == XMLReader::ELEMENT && in_array($reader->name, array(„image“, „textinput“)))
          $reader->next();

          1. peter

            Re: No nevim

            SAX a XMLReader su v podstate skoro to iste. Osobne si myslim, ze SAX je z hladiska spracovania lepsi a z hladiska kodu prehladnejsi. Samozrejme pre dobreho programatora. :)
            XMLReader mi pripada ako dorbeny neskor pre tych, ktori nevedia pochopit ako moze fungovat SAX. :)

    2. Jakub Vrána

      Re: No nevim

      Koncepční chyba není v XMLReaderu, ale v příkladu. Osobně mi přijde vhodnější všechno načítat v jednom while cyklu a kontext si sledovat v proměnné. Ukázka RSS importu pomocí XMLReaderu je na http://www.clipboard.cz/4ng. Má pouze to omezení, že očekává značky <item> až za <link> a <title> celého zdroje. Pokud by to tak nebylo, pak bychom výstup nemohli rovnou vypisovat, ale museli bychom si ho ukládat do dočasné proměnné.

      1. brablc

        Re: No nevim

        On je cely ten XMLReader divny:

        $xml->nodeType == XMLReader::ELEMENT
        $xml->nodeType == XMLReader::EN­D_ELEMENT
        $xml->nodeType == XMLReader::TEXT

        Takze uzavreny element je typ uzlu?

        A tenhle priklad je uz natolik nepochopitelny, ze muze byt i spravne. Nicmene pouziti jednoho $xml->read() asi uplne rusi veskere vyhody XMLReaderu. Zatim rikam zlaty SAX (samozrejme ze pro pripad RSS je zlaty simplexml_load_fi­le).

        1. Jiří KosekAutor příspěvku

          Re: No nevim

          ELEMENT ~ počáteční tag

          END_ELEMENT ~ koncový tag

          (viz tabulka na straně 165 ve knize).

          To pojmenování může vypadat trochu divně, ale všichni to okopírovali z .NETu (http://msdn.microsoft.com/…odetype.aspx) – ten použil jmenné konvence tak, aby se to hodně krylo s DOMem.

          1. Jakub Vrána

            Re: No nevim

            Důležitá je ještě vlastnost isEmptyElement, která umožňuje rozpoznat prázdné elementy (<x/>). Ty totiž END_ELEMENT nemají.

      2. Jiří KosekAutor příspěvku

        Re: No nevim

        To držení všech předků na zásobníku a jejich porovnávání je hrozně pomalé (jasně na RSS to nevadí, ale XMLReader je určena na velké objemy dat a tam by to bylo znát).

        1. Jakub Vrána

          Re: No nevim

          Zásadně pomalejší to není. Kontext si nějak držet musíme, takže kromě vlastního zásobníků zbývá rekurzivní funkce. Udělal jsem ji co nejchytřeji (do rekurze vstupuje jen když potřebuje změnit kontext) a výsledky jsou tyto:

          0.98 s – porovnávání pole s kontextem
          0.91 s – chytrá rekurzivní funkce

          Jedná se o medián ze tří pokusů při načítání titulku z exportu Wikipedie. Zdrojový kód je na http://www.clipboard.cz/5ng. Dlužno ale podotknout, že pokud bychom kontextů chtěli rozlišovat více, tak by se kód dramaticky zesložitil. Např. RSS import bych v tom psát opravdu nechtěl.

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=3103