Autor Zpráva
Yuhů
Profil
Mám xml soubor a potřebuju PHP skript, který mi z něj něco přečte a vypíše na stránku.

XML soubor se jmenuje kočička.xml a má tento obsah:


<?xml version="1.0" encoding="UTF-8"?>
<zvířátko>
<druh>
kočička
</druh>
<vlastnost>
krásná a chytrá
</vlastnost>
</zvířátko>


A teď potřebuju (pokud možno co nejkratší) php skript, jehož výsledkem bude toto:

kočička:<br> krásná a chytrá

Díky
Leo
Profil
PHP ma nejaky XML parsovaci udelatka:

http://cz2.php.net/manual/cs/ref.xml.php

Nebo regularni vyrazy, Leo
Yuhů
Profil
Tuhle stránku znám, ale nepochopil jsem z ní vůbec nic. Ty příklady jsou tam moc komplikovaný. Potřebuju jednoduchej příklad, kterej mi vypíše kočička krásná a chytrá. Nechci tunu teorie. Jsem si jistý, že to jde jednoduše, před třemi lety jsem to uměl.
Leo
Profil
Myslis s pouzitim toho expatu? Leo
Leo
Profil
Mel jsi tenkrat o tom honem neco napsat a ted bys to mel jako najity :-) Leo
Leo
Profil
Neco jako

$text = "obsah toho souboru";

$rv = "/<druh>(.*)<\/druh>.*<vlastnost>(.*)<\/vlastnost>/si";
preg_match_all($rv,$text,$shoda,PREG_PATTERN_ORDER);
echo trim($shoda[1][0]).'<br>'.trim($shoda[2][0]);

Leo
Pachollini
Profil
Na takovouhle jednoduchost asi regulární výraz, ale principiálně to řeší XSLT, kde by to spravil následující styl:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">


<xsl:template match="/">
<xsl:apply-templates select="//zvířátko"/>
</xsl:template>

<xsl:template match="zvířátko">
<xsl:value-of select="druh">:<br />
<xsl:value-of select="vlastnost">
</xsl:template>

</xsl:stylesheet>


Který se dá volat na jdenom řádku, jenom si musíš napsat funkci, viz např. http://seky.nahory.net/2004/07/xslt-rss-ctecka/
PHP XML parser bych tady asi nedoporučoval, je příliš složitý, když, tak v nejhorším DOM, ale ten má jiné nevýhody. Chceš-li, pošli přesnější popis problému, ev. mailem.
Leo
Profil
Pokud si napisu fci, tak se pak da cokoliv volat na jednom radku :-) Leo
Yuhů
Profil
OK, dotaz jsem evidentně položil blbě. Potřebuju to načíst do proměnných.

XSLT transformace je samozřejmá, děkuju, ale měl jsem uvést hned, že to tak nechci dělat. Potřebuju to do proměnných, ne rovnou na výstup.

Regulární výrazy jsou také funkční, ale nechci to prasit tímhle stylem, potřebuju principiálně čistší metodu. Prostě potřebuju zavolat parser a dostat z něj nějaké hodnoty, nejlépe do objektu.
Pachollini
Profil
Podle mě je ten dotaz položený moc obecně. Můžeš si vytvořit DOM reprezentaci XML (za předpokladu, že máš příslušné rozšíření), načíst zvířata pomocí get_elements_by_tagname("zvíře") a pak přiřadit textové nody potomků.

Druhá možnost je hnát xml parserem, asi takto:

class c_xml_parser

{
var
$context=array() // pole se současným stromovým kontextem
,$parser // PHP xml parser
,$error // pole s kódy chyby
;

function c_xml_parser(
$xml // xml, které se má parsovat
)
{
$this->parser=xml_parser_create("UTF-8");
xml_parser_set_option($this->parser,XML_OPTION_CASE_FOLDING,false);

xml_set_element_handler($this->parser,array(&$this,"handle_start_tag "),array(&$this,'handle_end_tag'));
xml_set_character_data_handler($this->parser,array(&$this,"handle_te xt"));
$result=xml_parse($this->parser,$xml);
if(!$result)
{
$this->error["code"]=xml_get_error_code($this->parser);
$this->error["string"]=xml_error_string($this->parser);
$this->error["line"]=xml_get_current_line_number($this->parser);
$this->error["column"]=xml_get_current_column_number($this->parser) ;
$this->error["index"]=xml_get_current_byte_index($this->parser);
}
xml_parser_free($this->parser);
}

function handle_start_tag($parser,$name,$attr)
{
$this->context[]=$name;
}

function handle_end_tag($parser,$name)
{
array_pop($this->context);
}

function handle_text($parser,$text)
{
// funkce pro zpracování textu, podle kontextu např:
switch($this->context[count($this->context)-1])
{
case "zvířátko":
// ...
break;
case "vlastnosti":
// ...
break;
default:
// ...
}
}
}


Ale možná nosím dříví do lesa...
Yuhů
Profil
Tohohle jsem se bál, nebaví mě to chápat. Na můj vkus je to moc složitý.

Takže díky, navrhnu tu aplikaci asi bez XML.

Ale ještě to zkusím s doplňujícím dotazem pro někoho, kdo ten příklad prostudoval a pochopil:

Dal by se prosím ten předchozí příklad brutálně promazat na něco, co ještě funguje, ale už se z toho nedá nic smazat? Nemusí tam být ani ošetření chyb.

A pokud jsem málo konkrétní, tak jako vstup chci zadat xml soubor a na výstupu chci jednu proměnnou $zvire a v ní mít obsah tagu <zvíře>.

Hlavně ať to prosím nedělá nic víc. (Oželím i chytrou a krásnou.) A ano, myslím, že to chci přes DOM.
Hugo
Profil
Yuhů

Obavam se, ze uz to moc nepromazes. Ale IMHO to neni moc slozity. Delal sem na stranky nasi katedry editaci udaju pro zamestnance a studenty, kde jsem tyto funkce pouzival. Myslim, ze kdyz si projdes ty priklady v PHP manualu, tak se to da pochopit.
Hugo
Profil
Nevim jestli ti to pomuze, ale velmi strucne jsem to popsal na strance
http://hugo.aktualne.cz/php_learn/xml/working.php
llook
Profil
Ty XML funkce fungujou asi takhle:
1. Vytvoříš parser - xml_parser_create
2. Pro všechny typy prvků které chceš odchytávat (elementy, znakový data...) si vytvoříš handlery - funkce, který zpracovávaj daný prvek. Ty zaregistruješ v parseru, funkcema xml_set_<něco>_handler
3. Parsuješ - xml_parse
Parser prochází dokument a pokaždý když narazí na prvek, pro který má zaregistrovaný handler, patřičný handler zavolá a předá mu informace o tom prvku.

Zadání z prvního příspěvku by se řešilo celkem jednoduše asi takhle:

/** tady si budu pamatovat poslední otevřený element */
$lastOpened = '';

function startTag($parser, $name, $attribs) {
global $lastOpened;
$lastOpened = $name;
}
function endTag($parser, $name) {
}
function characterData($parser, $data) {
global $lastOpened;
switch ($lastOpened) {
case 'druh':
$druh = $data;
break;
case 'vlastnost':
$vlastnost = $data;
break;
default:
// nezájem
break;
}
}
// 1. vytvořim parser
$parser = xml_parser_create('UTF-8');
// 2. zaregistruju handlery
xml_set_element_handler('startTag', 'endTag');
xml_set_character_data_handler('characterData');
// 3. parsuju
xml_parse($parser, file_get_contents('kocicka.xml'), true);

U složitějších případů se dost vyplatí zapouzdřit to všechno do objektu, jako handler můžeš registrovat i metodu.
Leo
Profil
"A pokud jsem málo konkrétní, tak jako vstup chci zadat xml soubor a na výstupu chci jednu proměnnou $zvire a v ní mít obsah tagu <zvíře>."

Ale to prece snadno muzes i u toho regularniho vyrazu :-) Klidne si pro to napis funkci / metodu, kde v nazvu bude xml abys mel klid na dusi :-) Pokud to vadi treba ten trim tak ten se da vyresit upravou toho regularu, Leo
MiHor
Profil *
a tohle by Ti nepomohlo

<?php
$pars = xml_parser_create();
xml_parse_into_struct($pars,$xml,$vals,$index);
print_r($vals);
?>

předpokládá se že v $xml je Tvoje XML
v poli $vals jsou hodnoty
v $index jsou i odkazy na jednotlivé tagy ale to nejspíš zahodíš

není to úplně přesně to co si asi chtěl, ale myslím že je to hodně blízko a pokud programuješ už si to z toho jedním cyklem vybagruješ úplně jednoduše
Yuhů
Profil
llooku, díky za vysvětlení, od Tebe jsem to konečně pochopil

MiHore, jestli ta funkce xml_parse_into_struct() funguje (ještě jsem to nestihnul otestovat), tak to je přesně to, co jsem měl úplně původně na mysli. Jdu si najít nějaký příklad použití.
Honza Hučín
Profil
Shodou okolností jsem teď potřeboval přesně to samé, co Yuhů. Z popisu xml_parse_into_struct se zdá, že to je velmi užitečná, a přitom jednoduchá funkce.

Já se ale vrátím k postupu Ilooka, protože ten použiju. Je skvěle vysvětlený, dovolím si ovšem opravit pár nepřesností. Třeba se to bude hodit někomu dalšímu, tak ať nemusí vychytávat drobnosti.

- Ve funkci characterData je potřeba předat hodnotu proměnných $druh a $vlastnost ven, takže by mělo být global $lastOpened, $druh, $vlastnost; (anebo vrátit returnem).

- Pokud jsou elementy odděleny odřádkováním, vezme parser i to odřádkování a zavolá na to handler characterData s předchozím tagem. takže na výstupu Yuhůova příkladu bude $druh dvakrát: jednou "kočička", jednou odřádkování. Spraví to podmínka if (strlen(trim($data))) v handleru characterData.

- parser defaultně uvádí názvy elementů velkými písmeny, takže buď se musí v characterData změnit case 'DRUH' apod., anebo se musí přenastavit chování parseru příkazem xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);

- handlery se registrují s prvním parametrem rovným id parseru, tedy např. xml_set_element_handler($parser, 'startTag', 'endTag');

Zde je funkční příklad použití:

<?

$soubor = 'karolina.xml';
$nadpisy = Array();
$odstavce = Array();
$lastOpened = '';

function startTag($parser, $name, $attribs) {
global $lastOpened;
$lastOpened = $name;
}
function endTag($parser, $name) {
}
function characterData($parser, $data)
{
global $lastOpened,$nadpisy,$odstavce;
if (strlen(trim($data)))
{
switch ($lastOpened) {
case 'nadpis':
$nadpisy[] = $data;
break;
case 'odst':
$odstavce[] = $data;
break;
default:
// nezájem
break;
}
}
}
// 1. vytvořim parser
$parser = xml_parser_create();
xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,false);
// 2. zaregistruju handlery
xml_set_element_handler($parser,'startTag', 'endTag');
xml_set_character_data_handler($parser,'characterData');
// 3. parsuju
xml_parse($parser, file_get_contents($soubor), true);
xml_parser_free($parser);

foreach($nadpisy as $value)
echo "<h2>".$value."</h2>";

foreach($odstavce as $value)
echo "<p>".$value."</p>";

?>
OBr
Profil *
Honza Hučín
Nádhera. Tohle jsem přesně potřeboval. Mockrát děkuju.
szucs
Profil
A teď potřebuju (pokud možno co nejkratší) php skript, jehož výsledkem bude toto:

kočička:<br> krásná a chytrá



<?
$xmlDoc ="<zvířátko><druh>kočička</druh><vlastnost>krásná a chytrá</vlastnost></zvířátko>";
$XmlP = xml_parser_create();
xml_parse_into_struct($XmlP,$xmlDoc,$vals,$index);
xml_parser_free($XmlP);
echo $vals[1]['value'];
echo '<br>';
echo $vals[2]['value'];
?>
szucs
Profil
Prave sa ucim xml
Pouzil som priklad od p. Hucina

Toto je analyzovany subor

<?xml version='1.0'?>
<art>
<heading>Nejaky nadpis</heading>
<para>Text prvniho odstavce.</para>
<para>Text druheho odstavce.</para>
<para>Text tretiho odstavce.</para>
</art>

<?
$soubor = 'skuska.xml';
$heading = Array();
$para = Array();
$lastOpened = '';

function startTag($parser, $name, $attribs) {
global $lastOpened;
$lastOpened = $name;

}
function endTag($parser, $name) {
}
function characterData($parser, $data)
{
global $lastOpened,$nadpisy,$odstavce;
if (strlen(trim($data)))
{

switch ($lastOpened) {
case 'heading':
$heading[] = $data;

break;
case 'para':
$para[] = $data;
echo $para[0];
break;
default:
// nezájem
break;
}
}
}
// 1. vytvořim parser
$parser = xml_parser_create();
xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,false);
// 2. zaregistruju handlery
xml_set_element_handler($parser,'startTag', 'endTag');
xml_set_character_data_handler($parser,'characterData');
// 3. parsuju
xml_parse($parser, file_get_contents($soubor), true);
xml_parser_free($parser);

print_r($para);
foreach($heading as $value)
echo "<h2>".$value."</h2>";

foreach($para as $value)
echo "<p>".$value."</p>";

?>

Ked som sidal vypis print_r($para);
dostal som prazdne pole

Ked som si v casti switch na skusku dal vypisat
echo heading[0]
tak mi vypisal spravne
Nejaky nadpis

Niekde dalej sa mi tie polia vyprazdnia, nechapem preco
szucs
Profil
uz to mam, zabudol som opravit
global $lastOpened,$nadpisy,$odstavce;
na global $lastOpened,$heading,$para;
ash
Profil *
Dá sa to aj takto:


<?
$xmldata ='<fauna><zviratko><druh>kocicka</druh><vlastnost>krasna a chytra</vlastnost></zviratko><zviratko><druh>pes</druh><vlastnost>skar edy a hlupy</vlastnost></zviratko></fauna>';

$xml = simplexml_load_string($xmldata);

foreach ($xml->zviratko as $zver) echo $zver->druh.'='.$zver->vlastnost.'<br/>';
?>
Toto téma je uzamčeno. Odpověď nelze zaslat.