I\'m using xpath to grab information from a document, the only issue is I havn\'t been able to combine them into 1 for loop so the information displays correctly on the page. My
Use the context node argument of $xpath->evaluate()
...
Your code with these adjustments:
<?php
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->load('http://mdoerrdev.com/xml/updates-mits.xml');
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('MITS', "http://www.mitsproject.org/namespace");
$units = $xpath->evaluate("//ILS_Unit[@FloorplanID='550584']/Unit");
echo "<table>";
echo "<tr><th>Marketing Name</th><th>Market Rent</th></tr>";
foreach($units as $unit) {
$marketingName = $xpath->evaluate("string(MITS:MarketingName)", $unit);
$marketRent = $xpath->evaluate("string(MITS:Information/MITS:MarketRent)", $unit);
echo "<tr>";
echo " <td>" . $marketingName . "</td>";
echo " <td>" . $marketRent . "</td>";
echo "</tr>";
}
echo "</table>";
?>
Yields this output with MarketingName and MarketRent displayed together rather than separately per your request:
I couldn't resist to give this another try to apply a model on some XML source. I opted for SimpleXMLElement
for this answer. It is merely transparent and has mostly only implications on the xpath expressions. It should be possible to translate the same interface to DOMDocument
.
$unitPrototype = new XPrototype(
"//ILS_Unit[@FloorplanID='550584']/Unit",
[
'name' => 'MITS:MarketingName',
'price' => 'MITS:Information/MITS:MarketRent'
]
);
$units = new XList('http://mdoerrdev.com/xml/updates-mits.xml', $unitPrototype);
foreach ($units as $unit) {
echo
$unit->name, " ",
$unit->price, "\n";
}
The source of the used types like XPrototype
and XList
is on Github: XObjects.php.
This depends a bit on what you're trying to achieve. You can combine two xpath expressions by using the Union operator (pipe |
):
$unitName = $xpath->evaluate("
(
//ILS_Unit[@FloorplanID='550584']/Unit/MITS:MarketingName
|//ILS_Unit[@FloorplanID='550584']/Unit/MITS:Information/MITS:MarketRent
)
");
Which then would return all evaluated nodes in document order:
<div class="unit-name">
1265.0000
C-304
1265.0000
C-308
1255.0000
C-204
1255.0000
C-208
1230.0000
C-102
1230.0000
C-103
</div>
Which is probably not what you're looking for. Instead you want to either evaluate over both results the same time, which can be achieved with a MultipleIterator:
$unitName = $xpath->evaluate("//ILS_Unit[@FloorplanID='550584']/Unit/MITS:MarketingName");
$unitPrice = $xpath->evaluate("//ILS_Unit[@FloorplanID='550584']/Unit/MITS:Information/MITS:MarketRent");
$it = new MultipleIterator();
$it->attachIterator(new IteratorIterator($unitName));
$it->attachIterator(new IteratorIterator($unitPrice));
foreach($it as $value) {
list($name, $price) = $value;
echo " * ", $name->nodeValue, " ", $price->nodeValue, "\n";
}
Output:
* C-304 1265.0000
* C-308 1265.0000
* C-204 1255.0000
* C-208 1255.0000
* C-102 1230.0000
* C-103 1230.0000
This is probably more what you're looking for. Also for what you do, SimpleXMLElement might be more easy to use because it already allows to output nodes in string context.
Additionally there is another concept that directly maps shallow objects to an underlying XML document and it has been outlined here:
It is quite an interesting concept. IIRC I wrote something similar like applying one xpath query onto all nodes of another one, but I don't find it right now.