I need to check if Team1 exists in the XML feed. If Team1 appears twice in the XML feed, I need to output only the first instance. So far I can only output both instances. How do I accomplish this?
$str = <<<'XML'
<DATAS>
<DATA>
<VISITOR>Team6</VISITOR>
<HOME>Team7</HOME>
</DATA>
<DATA>
<VISITOR>Team1</VISITOR>
<HOME>Team2</HOME>
</DATA>
<DATA>
<VISITOR>Team3</VISITOR>
<HOME>Team1</HOME>
</DATA>
<DATA>
<VISITOR>Team4</VISITOR>
<HOME>Team5</HOME>
</DATA>
</DATAS>
XML;
$data = new SimpleXMLElement($str);
$found = false;
foreach ($data->DATA as $item) {
$teamh = $item->HOME;
$teamv = $item->VISITOR;
if ($teamh == 'Team1' || $teamv == 'Team1') {
$found = true;
echo 'Home Team: ' . $data->DATA->HOME . "
";
echo 'Away Team: ' . $data->DATA->VISITOR . "
";
}
}
Use XPath. Selecting nodes on a DOM tree is easy with it. (SimpleXML uses a DOM in the background). Here are to methods for it SimpleXMLElement::xpath()
and DOMXpath::evaluate()
.
Select all event data:/DATAS/DATA
Only if VISITOR or HOME is "Team1":/DATAS/DATA[VISITOR='Team1' or HOME='Team1']
Count them:count(/DATAS/DATA[VISITOR='Team1' or HOME='Team1'])
Limit to the first found node:/DATAS/DATA[VISITOR='Team1' or HOME='Team1'][1]
SimpleXMLElement::xpath()
always returns an array of SimpleXMLElement objects. So it can not directly execute the count(...)
Xpath expression.
You can of course use the PHP function count()
on the return value.
count($datas->xpath("/DATAS/DATA[VISITOR='Team1' or HOME='Team1']"));
If you only want to output the first event data for a team if it exists you will not need the count. Limiting the result in XPath will return a list/array with a single element or an empty list.
$datas = simplexml_load_string($str);
$eventCount = count($datas->xpath("/DATAS/DATA[VISITOR='Team1' or HOME='Team1']"));
echo "Team1 is included $eventCount time(s) in the feed.
";
$events = $datas->xpath("/DATAS/DATA[VISITOR='Team1' or HOME='Team1'][1]");
foreach ($events as $event) {
echo "Visitor: {$event->VISITOR}, Home: {$event->HOME}
";
}
$dom = new DOMDocument();
$dom->loadXml($str);
$xpath = new DOMXPath($dom);
$eventCount = $xpath->evaluate("count(/DATAS/DATA[VISITOR='Team1' or HOME='Team1'])");
echo "Team1 is included $eventCount time(s) in the feed.
";
$events = $xpath->evaluate("/DATAS/DATA[VISITOR='Team1' or HOME='Team1'][1]");
foreach ($events as $event) {
$visitor = $xpath->evaluate('string(VISITOR)', $event);
$home = $xpath->evaluate('string(HOME)', $event);
echo "Visitor: $visitor, Home: $home
";
}
This is how to accomplish task 1, check if and how often Team1 is in the feed:
$xml = simplexml_load_string($x); // assume XML in $x
$team1 = $xml->xpath("/DATAS/DATA[VISITOR='Team1' or HOME='Team1']");
echo "Team1 is included " . count($team1) . " time(s) in the feed.";
This examples uses xpath()
to select all <DATA>
nodes having Team1 as either <VISITOR>
or <HOME>
. The result is an array of SimpleXML
Elements that can be counted.
see it working: https://eval.in/230136
For task 2, having only Team1 output once (in contrast to every Team only once), this is a looping way:
$team1count = 0;
foreach ($xml->DATA as $event) {
$t[0] = $event->VISITOR;
$t[1] = $event->HOME;
$hasteam1 = in_array('Team1', $t);
if (($hasteam1 AND $team1count == 0) OR (!$hasteam1)) {
echo "Visitor: " . $t[0] . PHP_EOL;
echo "Home: " . $t[1] . PHP_EOL;
}
$team1count = $team1count + $hasteam1;
}
This approach is using a check if Team1 is <VISITOR>
or <HOME>
in the current node, and counting the occurrences of Team1. Teams are echoed if either Team1 is there, but the counter = 0, or if Team1 is not there. Of course, the counter has to be incremented if Team1 was there.
see it working: https://eval.in/230152
But wait, there's another solution, let's build on what we did for task 1:
// same code as above:
$xml = simplexml_load_string($x); // assume XML in $x
$team1 = $xml->xpath("/DATAS/DATA[VISITOR='Team1' or HOME='Team1']");
Now, we simply delete all <DATA>
nodes with Team1 but the 1st from the XML:
$c = 0;
foreach ($team1 as $event) {
if ($c > 0) unset($event[0]);
$c++;
}
$team1
is an array containing all nodes with team1, so we iterate over it. We don't delete the 1st one, but all the other ones by counting with $c
and do unset()
only for $count > 0
.
unset($event[0])
deletes a <DATA>
node from the XML tree.
Now, we simply have to run over the XML and output all the remaining nodes:
foreach ($xml->DATA as $event)
echo "Visitor: " . $event->VISITOR . ", Home: " . $event->HOME . PHP_EOL;
See all of this in action: https://eval.in/230157