Autor Zpráva
Nailen
Profil
Chtěl bych se naučit zpracování XML feedu. Pár návodů jsem už četl a jednoduché příklady zkoušel. Jak je ale něco složitějšího tak se zaseknu.
Poradil by mi někdo na tomto jednoduchém příkladu jak se přistupuje k následujícím strukturovaným datům?

Mám toto XML:

<channel id="ČT1 HD">
  <display-name lang="cs">ČT1 HD</display-name>
  <icon src="../ct1-hd.png"/>
</channel>

<channel id="ČT2 HD">
  <display-name lang="cs">ČT2 HD</display-name>
  <icon src="../ct2-hd.png"/>
</channel>

<programme start="20210220043000 +0000" stop="20210220050000 +0000" channel="ČT1 HD">
  <title lang="cs">Události v regionech</title>
  <desc lang="cs">Hlavní regionální zpravodajská relace České televize. Souhrn nejdůležitějších událostí v krajích České republiky.</desc>
  <credits>
    <director>František Karvánek</director>
    <actor>Jitka Sluková</actor>
    <actor>Miloš Zeman</actor>
  </credits>
  <date>2007</date>
  <category lang="cs">Publicistický</category>
  <icon src="https://www.o2tv.cz/img/epg/ct1_hd/29154984/profi_cover.jpg"/>
  <country lang="cs">Česká Republika</country>
</programme>

<programme start="20210220052500 +0000" stop="20210220062000 +0000" channel="ČT1 HD">
  <title lang="cs">Polopatě</title>
  <desc lang="cs">Nový moderní hobby magazín Filipa Čapky.</desc>
  <credits>
    <actor>Filip Čapka</actor>
  </credits>
  <date>2013</date>
  <category lang="cs">Publicistický</category>
  <icon src="https://www.o2tv.cz/img/epg/ct1_hd/29162615/profi_cover.jpg"/>
  <country lang="cs">Česká Republika</country>
</programme>

Když provedu tento příkaz:

$xml = simplexml_load_file($url) or die("Can't connect to URL");
?><pre><?php print_r($xml); ?></pre><?php

Tak dostanu toto:

[channel] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [id] => ČT1 HD
                        )

                    [display-name] => ČT1 HD
                    [icon] => SimpleXMLElement Object
                        (
                            [@attributes] => Array
                                (
                                    [src] => .../ct1-hd.png
                                )

                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [id] => ČT2 HD
                        )

                    [display-name] => ČT2 HD
                    [icon] => SimpleXMLElement Object
                        (
                            [@attributes] => Array
                                (
                                    [src] => .../ct2-hd.png
                                )

                        )
        
                )

[programme] => Array
        (
    [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [start] => 20210220043000 +0000
                            [stop] => 20210220050000 +0000
                            [channel] => ČT1 HD
                        )

                    [title] => Události v regionech
                    [desc] => Hlavní regionální zpravodajská relace České televize. Souhrn nejdůležitějších událostí v krajích České republiky.
                    [credits] => SimpleXMLElement Object
                        (
                            [director] => František Karvánek
                            [actor] => Array
                                (
                                    [0] => Jitka Sluková
                                    [1] => Miloš Zeman
                                )

                        )

                    [date] => 2007
                    [category] => Publicistický
                    [icon] => SimpleXMLElement Object
                        (
                            [@attributes] => Array
                                (
                                    [src] => .../profi_cover.jpg
                                )

                        )

                    [country] => Česká Republika
                )
                
         [3] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [start] => 20210220052500 +0000
                            [stop] => 20210220062000 +0000
                            [channel] => ČT1 HD
                        )

                    [title] => Polopatě
                    [desc] => Nový moderní hobby magazín Filipa Čapky.
                    [credits] => SimpleXMLElement Object
                        (
                            [actor] => Filip Čapka
                        )

                    [date] => 2013
                    [category] => Publicistický
                    [icon] => SimpleXMLElement Object
                        (
                            [@attributes] => Array
                                (
                                    [src] => ../profi_cover.jpg
                                )

                        )

                    [country] => Česká Republika
                )       
                

Potom když bych ty jednotlivé hodnoty chtěl vypsat třeba pomocí tohoto, tak netuším, jak to správně nadefinovat

foreach ($xml->channel as $channel) {
  printf(...

Chtěl bych například na řádky pod sebe vypsat následující informace:

channel =
icon =
start =
stop =
title =
desc =
director =
actor =
date =

Trochu se ztrácím v těch objektech, polích a podpolích. Podaří se mi vždy vypsat jen část.

Předem díky za vysvětlení
Keeehi
Profil
Zas tak složitý to není.
foreach($xml->programme as $programme) {
    echo "channel = " .$programme->attributes()["channel"]."\n";
    echo "icon = " .($programme->icon->attributes()["src"])."\n";
    echo "start = " .$programme->attributes()["start"]."\n";
    echo "stop = " .$programme->attributes()["stop"]."\n";
    echo "title = " .$programme->title."\n";
    echo "desc = " .$programme->desc."\n";
    echo "director = " .implode(", ", $programme->credits->xpath('director'))."\n";
    echo "actor = " .implode(", ", $programme->credits->xpath('actor'))."\n";
    echo "date = " .$programme->date."\n\n";
}

Důležité je vědět, zda máš v proměnné objekt a nebo pole objektů. A to je vlastně celé. Ano, když člověk nedává pozor tak se v tom dá lehce ztratit. Stačí však použít var_dump() a hned víš na čem jsi. Když máš ten objekt (který reprezentuje jeden uzel/tag) tak k přímým potomkům se dostaneš tak, jako kdyby to byly atributy toho objektu. Potomků toho jména však může být více. Pokud použiješ přístup přes jméno potomka jako atribut objekt, dostaneš pouze prvního takového potomka. Pokud chceš pole všech takových potomků, použiješ metodu xpath. Do ní dáš výraz, podle kterého se v podstromu vyhledává. Ten můj je velmi triviální, protože je to velmi jednoduchá úloha ale může to být mnohem složitější. Je to podobné jako jsou třeba CSS selektory, ale mnohem mocnější. No a nakonec, pokud chceš atributy toho uzlu, dostaneš se k nim jako k asociativnímu poli po zavolání metody attributes().
Nailen
Profil
Keeehi:
velice vám děkuji za malou ukázku, jak správně k datům přistupovat. Moc mi to pomohlo, abych se posunul dále.
Keeehi
Profil
Nailen:
Jsem rád ze ti to pomohlo. Nebyl jsem si jistý zda jsem to popsal dostatečně srozumitelně v takto krátkém textu.
Nailen
Profil
Keeehi:
chtěl bych vás poprosit o doplňující radu. Narazil jsem na další strukturu v XML, kterou nevím jak načíst. Prvně jsem si myslel, že na to použiji implode viz váš předchozí příklad, ale je to úplně jiná struktura a nevím jak na ni.

V rámci XML je něco takovéhoto:

<IMGURL_ALTERNATIVE>https://www...1.jpg</IMGURL_ALTERNATIVE>
<IMGURL_ALTERNATIVE>https://www...2.jpg</IMGURL_ALTERNATIVE>
<IMGURL_ALTERNATIVE>https://www...3.jpg</IMGURL_ALTERNATIVE>

Někdy tento element tam není vůbec. Někdy je tam jen jeden obrázek a jindy jich je tam několik.

Zkusil jsem toto:
echo "IMGURL_ALTERNATIVE_1 = " .implode(", ", $programe->xpath('IMGURL_ALTERNATIVE'))."\n";

V IMGURL_ALTERNATIVE_1 jsou následně všechny linky oddělené čárkou. Tyto linky bych chtěl samostatně zapsat do DB. Znamená to, že to musím rozřezat, nebo existuje nějaký zápis jak to načíst do pole a pak už jen přistupovat k jednotlivým položkám?

Předem díky za radu.
anonym_
Profil *
Ty obrázky by měly být v poli v $programe->xpath('IMGURL_ALTERNATIVE');, ne?

Pokud ano, pak to vidím nějak takto (píši narychlo, tak kdyby tam byl syntax error, tak si ho oprav, jde o princip).
$imgs = $programe->xpath('IMGURL_ALTERNATIVE');
if (count($imgs)) {
    // jestli jsou nejake obrazky, projdeme je cyklem
    foreach ($imgs as $img) {
        $values[] = '(?)';
        $vars[] = $img;
    }
    
    // vznikne query "INSERT ... VALUES ('link1'), ('link 2'), ('link 3')"
    $sql = "INSERT INTO table (...) VALUES " . implode(',', $values);
    
    $db->query($sql, $vars);
}
Keeehi
Profil
Tu podmínku bych napsal
if ($imgs !== false && count($imgs) > 0) {
Je to přesnější, ale ten obyčejný count bude asi taky fungovat.
anonym_
Profil *
Keeehi:
Psal jsem to ve zkratce (PHP mě neživí).

Ta tvoje podmínka je jasná, jen si myslím, že pokud bude count nula, `count($imgs)` převedený na bool bude false. A tím pádem je ta první část podmínky zbytečná. Domnívám se, nezkoušel jsem (nevím, jak bych rychle vytvořil validní vstup pro ověření a snad nemystifikuji).

Druhá otázka je, co se stane, když tam ten IMG tag vůbec nebude. To by asi mělo být celé v podmínce, jestli ten tag vůbec existuje (abych nematchoval něco, co není).
blaaablaaa
Profil
anonym:
xpath může vracet i false, v takovém případě by count skončil warningem.
Keeehi
Profil
anonym:
Ten check na false je tam kvůli tomu, že xpath může vrátit pole a nebo false. Pokud by vrátil false a to se nacpalo jako vstup do count, tak to může být v určitých verzích PHP problém. V 5 - 7.1 to projde, 7.2 - 7.4 to generuje warning a v osmičkové verzi už dokonce fatal error.

To co je tam "zbytečné" je to > 0 protože automatické přetypování na bool to zařídí. Nicméně to že to tam je ničemu nevadí, naopak je z toho jasně vidět, k čemu to slouží.
Nailen
Profil
anonym:
dobrý večer, děkuji za odpověď. Začátek chápu, ale ztrácím se v tom konci. Jak mám nadefinovat ty tečky mezi table a values? Ještě to trochu rozepíšu.

obrázků je pokaždé jiný počet. Maximálně jsou čtyři. Kromě těch obrázků budu ukládat i další parametry a netuším jak ten SQL dotaz udělat dynamický podle aktuálního počtu obrázků.

jednou ten SQL dotaz bude vypadat takto:

query "INSERT INTO table (nazev, img1, img2, img3, img4, status) VALUES ('nazev', 'link1', 'link 2', 'link 3', 'status')"

a podruhé zase třeba takto

query "INSERT INTO table (nazev, status) VALUES ('nazev', 'status')"

a pak třeba takto:

query "INSERT INTO table (nazev, img1, status) VALUES ('nazev', 'link1', 'status')"

Snad je srozumitelné co potřebuji vyřešit. Děkuji


Keeehi:
Díky za vysvětlení. Tuto část zvládám. problém nastává u toho konce viz můj poslední příspěvek. Děkuji
lionel messi
Profil
Nailen:

obrázků je pokaždé jiný počet. Maximálně jsou čtyři. Kromě těch obrázků budu ukládat i další parametry a netuším jak ten SQL dotaz udělat dynamický podle aktuálního počtu obrázků.

Položil by som si otázku, či je tento databázový návrh skutočne správny. Nebolo by lepšie mať jednu tabuľku, kde bude nazev a status a potom druhú tabuľku table_images (názov je, samozrejme, schématický), kde bude každý obrázok mať jeden vlastný riadok a bude sa tam ukladať názov obrázka (ak je to unikátny kľúč, ak nie, treba do tabuľky table pridať id) a jeho link?

K meritu veci:

$imgs = $programe->xpath('IMGURL_ALTERNATIVE');
if ($imgs !== false && count($imgs) > 0) {
    // jestli jsou nejake obrazky, projdeme je cyklem
    foreach ($imgs as $img) {
        $values[] = '(?)';
        $vars[] = $img;
    }
    
    $col_names_for_links = [];
    
    for ($i = 1; $i<= count($imgs);$i++) {
      $col_names_for_links[] = "img".$i;
    }
    
    $col_names_for_links_comma_separated = implode(",", $col_names_for_links);
    
    // vznikne query "INSERT ... VALUES ('link1'), ('link 2'), ('link 3')"
    $sql = "INSERT INTO table (nazev, $col_names_for_links_comma_separated". ($col_names_for_links_comma_separated ? "," : "") ."status) VALUES " . implode(',', $values);
    
    $db->query($sql, $vars);
}
anonym_
Profil *
Nailen:
Zapomen na ten kód o příspěvek výše od lionela messiho (bude fungovat, ale brrr) a řiď se radou v témže příspěvku výše.

Tzn. ty indexovane sloupce imgX zahod, nová tabulka bude mít dva sloupce: id_produktu, link. Každý obrázek pak bude mít sólo radek. Pokud záleží na pořadí obrázku, přidej sloupec pozice.
Nailen
Profil
souhlasím s vámi, že správně by bylo mít dvě tabulky a každý obrázek svůj řádek, svoje ID. Toto bych zvládl udělat a neřešil bych to tu. Potřebuji ale vyřešit něco jiného a toto je jen názorný příklad na kterém se to snažím vysvětlit, abych pochopil jak s těmito daty pracovat.
Všem děkuji za rady.
Keeehi
Profil
Když budeš mít tu samostatnou tabulku, tak to bude vypadat takto. Kolik bude obrázků je pak úplně jedno.
$imgs = $programe->xpath('IMGURL_ALTERNATIVE');
if (if ($imgs !== false && count($imgs) > 0) {) {
    foreach ($imgs as $img) {
        $values[] = '(?, ?, ?)';
        $vars[] = "name";
        $vars[] = $img;
        $vars[] = "enabled";
    }
    
    $sql = "INSERT INTO table (nazev, img, status) VALUES " . implode(',', $values);
    
    $db->query($sql, $vars);
}

Pokud bys místo jednoho dotazu pro vložení všech obrázků volal dotaz pro každý obrázek samostatně, tak je to sice není tak optimální, ale zase to celkem jednoduše pochopíš
$imgs = $programe->xpath('IMGURL_ALTERNATIVE');
if (if ($imgs !== false && count($imgs) > 0) {) {
    foreach ($imgs as $img) {
        $sql = 'INSERT INTO table (nazev, img, status) VALUES ("name", ?, "enabled")';
        $db->query($sql, [$img]);
    }
}

Tam kde je otazník, na to místo se prostě nahradí ta hodnota z pole. Nahrazovat to za pořád stejný řetězec (name a enabled) je trochu zbytečné, ale v reálu to jméno se bude asi měnit, tak jsem chtěl ukázat, že tam těch otazníků může být více. V druhé ukázce, jsem chtěl naopak ukázat, že pokud se bude vkládat, pořád ta stejná hodnota, nemusíš ji tam dostávat skrz otazníky ale můžeš ji mít už v tom vstupním sql.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0