Php simplexml xpath contient () pour trouver d'autres éléments référencés par cet élément
Question
On me donne XML dans le format suivant, et je l'ai analysé avec le simplexml de PHP.
<?xml version="1.0" encoding="UTF-8"?>
<ManageMyBooking>
<BookingInfo>
<PartyDetails>
<Passenger>
<PaxNo>1</PaxNo>
<Title>Mrs</Title>
<Surname>Murphy</Surname>
</Passenger>
<Passenger>
<PaxNo>2</PaxNo>
<Title>Mr</Title>
<Surname>Murphy</Surname>
</Passenger>
<Passenger>
<PaxNo>3</PaxNo>
<Title>Miss</Title>
<Surname>Murphy</Surname>
</Passenger>
</PartyDetails>
<Accommodation>
<Units>
<Unit>
<UnitNo>1</UnitNo>
<UnitDesc>...</UnitDesc>
<PaxAssociated>1|2</PaxAssociated>
</Unit>
<Unit>
<UnitNo>2</UnitNo>
<UnitDesc>...</UnitDesc>
<PaxAssociated>3</PaxAssociated>
</Unit>
</Units>
</Accommodation>
</BookingInfo>
</ManageMyBooking>
Je traverse les unités (chambres) ainsi:
// $Accommodation is a SimpleXML Object defined earlier, and able to provide relevant info
<? foreach ($Accommodation->Units as $Units) {
foreach ($Units->Unit as $Unit) {
// (room/unit details echoed out here)
foreach ($Unit->xpath('//Passenger[contains(PaxAssociated,./PaxNo)]') as $RoomPax) { ?>
<?= $RoomPax->Title $RoomPax->Surname" ?><br />
<?= "$RoomPax->Title $RoomPax->Surname" ?><br />
<? }
}
} ?>
Dans une tentative de montrer les noms des passagers (PAX) dans chaque pièce.
Mais Ce XPath ne trouve personne, et ce qui suit obtient tout le monde.
//Passenger[contains(PaxNo,./PaxAssociated)]
Ce qui est particulièrement frustrant, c'est que j'ai utilisé avec succès XPath ailleurs dans le même PHP dans un but très similaire, sans problème.
Toute aide / conseils / suggestions sera très appréciée.
EDIT: Pour l'exhaustivité, et pour répondre à une question de plusieurs personnes: ce qui suit fonctionne ailleurs dans le code (mais pas à 100% correctement compte tenu de la correspondance possible sur «22» vs «2».
//Flight[contains(PaxAssociated,./PaxNo)]
La solution
Cette:
//Passenger[contains(PaxNo,./PaxAssociated)]
est: trouvez n'importe quel <Passenger>
avec un enfant <PaxNo>
qui la valeur contient la valeur de l'enfant <PaxAssociated>
. Cela ne fonctionnerait qu'avec une telle structure de données (que vous n'avez clairement pas):
<ManageMyBooking>
<BookingInfo>
<PartyDetails>
<Passenger>
<PaxNo>1|2</PaxNo> <!-- note the exchanged value! -->
<PaxAssociated>1</PaxAssociated>
</Passenger>
</PartyDetails>
</BookingInfo>
</ManageMyBooking>
C'est donc mal sur plusieurs comptes. Ce que vous moyenne est probablement une expression dynamique de XPath, comme ceci:
foreach ($Units->Unit as $Unit) {
$XPath = "//Passenger[contains('". $Unit->PaxAssociated . "', PaxNo)]";
foreach ($Unit->xpath($XPath) as $RoomPax) {
// ...
}
}
Cela fonctionne au premier coup d'œil, mais il n'est pas sûr de l'échec, car "22" contient également "2". Donc faire un contains()
seul ne t'a pas partout. Correct serait:
$XPath = "//Passenger[contains('|". $Unit->PaxAssociated ."|', concat('|', PaxNo, '|'))]";
De cette façon, vous vérifiez "| 22 |" contre "| 2 |", qui reviendrait faux.