Итерируя через XML с SimpleXML и XPath, результат находится в неправильном порядке
Мои переменные.
$xmlFile = 'xml.xml';
$xmlFileLoad = simplexml_load_file($xmlFile);
$xmlFileLoad->registerXPathNamespace("oi", "http://www.openimmo.de");
$immobilie = $xmlFileLoad->xpath('//oi:immobilie');
$zustand_angaben_letztemodernisierung = $xmlFileLoad->xpath('/oi:openimmo/oi:immobilie/oi:zustand_angaben/oi:letztemodernisierung');
$zustand_angaben_zustand = $xmlFileLoad->xpath('/oi:openimmo/oi:immobilie/oi:zustand_angaben/oi:zustand/@zustand_art');
$zustand_angaben_alter = $xmlFileLoad->xpath('/oi:openimmo/oi:immobilie/oi:zustand_angaben/oi:alter/@alter_attr');
$zustand_angaben_erschliessung = $xmlFileLoad->xpath('/oi:openimmo/oi:immobilie/oi:zustand_angaben/oi:erschliessung/@erschl_attr');
$zustand_angaben_altlasten = $xmlFileLoad->xpath('/oi:openimmo/oi:immobilie/oi:zustand_angaben/oi:altlasten');
$zustand_angaben_baujahr = $xmlFileLoad->xpath('/oi:openimmo/oi:immobilie/oi:zustand_angaben/oi:baujahr');
XML-файл (укороченная версия)
<?xml version="1.0" encoding="utf-8"?>
<openimmo xmlns="http://www.openimmo.de"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.openimmo.de openimmo.xsd">
<immobilie>
<zustand_angaben>
<altlasten>keine</altlasten>
</zustand_angaben>
</immobilie>
<immobilie>
<zustand_angaben>
<altlasten>keine</altlasten>
</zustand_angaben>
</immobilie>
<immobilie>
<zustand_angaben>
<altlasten>keine</altlasten>
</zustand_angaben>
</immobilie>
<immobilie>
<zustand_angaben>
<baujahr>ca. 1900</baujahr>
<altlasten>nein</altlasten>
</zustand_angaben>
</immobilie>
<immobilie>
<zustand_angaben>
<baujahr>ca. 1989</baujahr>
<zustand zustand_art="ERSTBEZUG" />
<alter alter_attr="ALTBAU" />
<altlasten>keine</altlasten>
</zustand_angaben>
</immobilie>
</openimmo>
мой show.php
<?php
include("variables.php");
$i = 0;
foreach ($immobilie as $immo) {
echo "Immobilie $i<br />";
if(isset($zustand_angaben_zustand[$i])) {
echo $zustand_angaben_zustand[$i] . "</br>";
}
if(isset($zustand_angaben_alter[$i])) {
echo $zustand_angaben_alter[$i] . "</br>";
}
if(isset($zustand_angaben_erschliessung[$i])) {
echo $zustand_angaben_erschliessung[$i] . "</br>";
}
if(isset($zustand_angaben_altlasten[$i])) {
echo $zustand_angaben_altlasten[$i] . "</br>";
}
if(isset($zustand_angaben_baujahr[$i])) {
echo $zustand_angaben_baujahr[$i] . "</br>";
}
echo "<br /><br />";
$i++;
}
?>
когда я выполняю код, результат будет следующим
Immobilie 0
ERSTBEZUG
ALTBAU
keine
5
A
5
A++
ca. 1900
Immobilie 1
keine
ca. 1989
Immobilie 2
keine
Immobilie 3
nein
Immobilie 4
keine
но я хочу его в том же порядке, что и в xml, поэтому в Immobilie 0 есть только keine, Immobilie 1 и 2, третий 1900 и nein и, наконец, Immobilie 4 со всеми свойствами в xml...
Что я делаю неправильно?
2 ответа
Используйте выражения XPath, относящиеся к текущему immobilie
элемент вместо:
$i = 0;
foreach ($immobilie as $immo) {
$immo->registerXPathNamespace("oi", "http://www.openimmo.de");
$zustand_angaben_letztemodernisierung = $immo->xpath('./oi:zustand_angaben/oi:letztemodernisierung');
$zustand_angaben_zustand = $immo->xpath('./oi:zustand_angaben/oi:zustand/@zustand_art');
$zustand_angaben_alter = $immo->xpath('./oi:zustand_angaben/oi:alter/@alter_attr');
$zustand_angaben_erschliessung = $immo->xpath('./oi:zustand_angaben/oi:erschliessung/@erschl_attr');
$zustand_angaben_altlasten = $immo->xpath('./oi:zustand_angaben/oi:altlasten');
$zustand_angaben_baujahr = $immo->xpath('./oi:zustand_angaben/oi:baujahr');
echo "Immobilie $i<br />";
if(isset($zustand_angaben_zustand[0])) {
echo $zustand_angaben_zustand[0] . "</br>";
}
if(isset($zustand_angaben_alter[0])) {
echo $zustand_angaben_alter[0] . "</br>";
}
if(isset($zustand_angaben_erschliessung[0])) {
echo $zustand_angaben_erschliessung[0] . "</br>";
}
if(isset($zustand_angaben_altlasten[0])) {
echo $zustand_angaben_altlasten[0] . "</br>";
}
if(isset($zustand_angaben_baujahr[0])) {
echo $zustand_angaben_baujahr[0] . "</br>";
}
echo "<br /><br />";
$i++;
}
eval.in demo
Когда вы выполняете запросы xpath параллельно, все они располагаются рядом друг с другом.
Для вашего конкретного примера вам еще не нужен xpath, документ выглядит как идеальная работа для SimpleXMLElement, вы можете извлекать данные непосредственно из него.
Если вы просматриваете интересующие вас объекты (здесь, скорее всего, каждый элемент immobilie), а затем извлекаете данные (отфильтровываете неустановленные элементы), это может работать аналогично следующему примеру:
$xml = simplexml_load_string($string);
foreach ($xml->immobilie as $immobilie) {
$angaben = $immobilie->zustand_angaben;
$data = [
'letzte_modernisierung' => $angaben->letztemodernisierung,
'zustand_art' => $angaben->zustand['zustand_art'],
'alter' => $angaben->alter['alter_attr'],
'erschliessung' => $angaben->erschliessung['erschl_attr'],
'altlasten' => $angaben->altlasten,
'baujahr' => $angaben->baujahr,
];
echo " * Immobilie:\n";
foreach(array_filter($data) as $label => $wert) {
echo " - $label: $wert\n";
}
}
Выход (также: онлайн-демо):
* Immobilie:
- altlasten: keine
* Immobilie:
- altlasten: keine
* Immobilie:
- altlasten: keine
* Immobilie:
- altlasten: nein
- baujahr: ca. 1900
* Immobilie:
- zustand_art: ERSTBEZUG
- alter: ALTBAU
- altlasten: keine
- baujahr: ca. 1989
Xpath совсем не плох, для такого сценария, как у вас, я бы порекомендовал вам использовать DOMDocument вместо SimpleXMLElement, поскольку он более гибок с Xpath благодаря методу оценки, который есть в DOMXpath.
В любом случае вы можете продолжить чтение этого вопроса, в котором показан один DOMDocument и одно решение на основе SimpleXMLElement для извлечения данных на основе Xpath из документов XML: