XML parsen in array en deze array uitlezen
Ik doe het volgende:
---------------------------------------------------
function xml2php($file) {
$xml_parser = xml_parser_create();
if (!($fp = fopen($file, "r"))) {
die("unable to open XML");
}
$contents = fread($fp, filesize($file));
fclose($fp);
xml_parse_into_struct($xml_parser, $contents, $arr_vals);
xml_parser_free($xml_parser);
return $arr_vals;
}
$Resultaat = xml2php("test.xml");
echo '<pre>'.print_r($Resultaat, true).'</pre>';
-----------------------------------------------------
Test.xml bevat het volgende:
-----------------------------------------------------
<results Query="phpfreakz" TopDoc="0" Matches="1" Last="1" ThisPage="1" LastPage="1" xP="phpfreakz." xDB="default">
<hits>
<hit relevance="100%" modtime="" id="gfg1o78" score="10" soort="gf" groep="Testen is beter ddds" toegang="S" titel="Dit is een test" tekst="test voorbeeld test phpfreakz" aantal="1" aanmaakdatum="20050907" lbdatum="20050907" example="" />
</hits>
</results>
-----------------------------------------------------
Nu krijg ik het volgende resultaat:
-----------------------------------------------------
Array
(
[0] => Array
(
[tag] => RESULTS
[type] => open
[level] => 1
[attributes] => Array
(
[QUERY] => phpfreakz
[TOPDOC] => 0
[MATCHES] => 1
[LAST] => 1
[THISPAGE] => 1
[LASTPAGE] => 1
[XP] => phpfreakz.
[XDB] => default
)
[value] =>
)
[1] => Array
(
[tag] => HITS
[type] => open
[level] => 2
[value] =>
)
[2] => Array
(
[tag] => HIT
[type] => complete
[level] => 3
[attributes] => Array
(
[RELEVANCE] => 100%
[MODTIME] =>
[ID] => gfg1o78
[SCORE] => 10
[SOORT] => gf
[GROEP] => Testen is beter ddds
[TOEGANG] => S
[TITEL] => Dit is een test
[TEKST] => test voorbeeld test phpfreakz
[AANTAL] => 1
[AANMAAKDATUM] => 20050907
[LBDATUM] => 20050907
[EXAMPLE] =>
)
)
[3] => Array
(
[tag] => HITS
[value] =>
[type] => cdata
[level] => 2
)
[4] => Array
(
[tag] => HITS
[value] =>
[type] => cdata
[level] => 2
)
[5] => Array
(
[tag] => HITS
[type] => close
[level] => 2
)
[6] => Array
(
[tag] => RESULTS
[value] =>
[type] => cdata
[level] => 1
)
[7] => Array
(
[tag] => RESULTS
[type] => close
[level] => 1
)
)
-----------------------------------------------------
Mijn vragen zijn de volgende:
- De xml (in het voorbeeld test.xml) wordt normaal gesproken dynamisch gegenereerd. De xml is namelijk het resultaat van een zoekactie in een externe zoekdatabase (Xapian/Omega). De url van waar de xml wordt aangevraagd is als volgt:
"http://localhost/cgi-bin/omega?DB=default&P=" . htmlentities(urlencode($T)) . "&FMT=xml"
Hierin zijn $T de zoektermen. Het probleem hiermee is dat het genereren van de xml prima verloop als ik met de header functie naar de betreffende pagina ga:
header("location: http://localhost/cgi-bin/omega?DB=default&P=" . htmlentities(urlencode($T)) . "&FMT=xml");
Als ik echter de url in een var zet en vervolgens de functie xml2php aanroep:
$Url = "http://localhost/cgi-bin/omega?DB=default&P=" . htmlentities(urlencode($T)) . "&FMT=xml"
$Resultaat = xml2php($Url);
dan geeft de in xml2php gebruikte functie filesize een foutmelding en wordt de uitvoering van xml2php afgebroken. Probleem is denk ik dat de url niet als bestand wordt gezien, omdat het een door het CGI-programma (Omega) gegenereerde XML-feed betreft. Hoe los ik dit op?
- Voor het uitlezen van de array moet ik nu verwijzen naar cijfers. Ik moet dan dus eerst kijken in de print welk nummer bij welk tag hoort en vervolgens hard in de code het cijfer opnemen. Dit is niet erg handig, omdat ik in eerste instantie alles op moet zoeken en in tweede instantie omdat ik bij het later wijzigen van de XML-template alle cijfers die ik voor het uitlezen van de array in mijn code heb opgenomen moet gaan aanpassen. Kan dit niet eenvoudiger? Graag zou ik meteen de namen van de tags in mijn array krijgen zonder dat op het eerste niveau nummers komen. Hoe kan ik dit het beste voor elkaar krijgen?
Ik gebruikte eerder onderstaande functie, maar die werkt niet met alle leestekens (er ontstaan regelmatig fouten in de array):
-------------------------------------------------------------
function xml2array ($name, $xml, $Echar='.', $Achar='/', $discardempty=true)
{
static $Result, $A, $E, $Discard;
//if ((strlen ($xml) < 256) && is_file ($xml))
if (strlen ($xml) < 256)
$xml = file_get_contents ($xml);
if ($name == '') {
$Result = array ();
$A = $Achar;
$E = $Echar;
$Discard = $discardempty;
}
$ReElements = '/<(\w+)\s*([^\/>]*)\s*(?:\/>|>(.*)<\/\s*\\1\s*>)/s';
$ReAttributes = '/(\w+)=(?:"|\')([^"\']*)(:?"|\')/';
preg_match_all ($ReElements, $xml, $elements);
foreach ($elements[1] as $ie => $xx) {
if ( $attributes = trim($elements[2][$ie])) {
preg_match_all ($ReAttributes, $attributes, $att);
foreach ($att[1] as $ia => $xx)
$Result[$name.$E.$elements[1][$ie].$A.$att[1][$ia]] = $att[2][$ia];
}
if (preg_match ($ReElements, $elements[3][$ie]))
xml2array ($name ? $name.$E.$elements[1][$ie] : $elements[1][$ie], $elements[3][$ie]);
else if (!$Discard || $elements[3][$ie])
$Result[$name.$E.$elements[1][$ie]] = $elements[3][$ie];
}
return $Result;
}
---------------------------------------------
Een erg lang verhaal geworden dus, ik hoop dat iemand er iets mee kan. Alvast bedankt!
Daar zijn (minimaal) twee redenen voor:
1) De array is opgebouwd in de tag-volgorde. Als je hem nu gaat indiceren op tag, raak je die volgorde kwijt.
2) Een tag kan meer dan eens voorkomen (zowel vanwege open/close als vanwege herhaling). Ook dat raak je kwijt als je op tag gaat indiceren.
Wat betreft je eerste vraag zou ik de URL eerst naar een tmp-bestand wegschrijven en vervolgens het tmp-bestand voeren aan xml2php()