PHP Simplexml Check If a Child Exists

PHP simpleXML how to check if a nested child exists

the problem with lines like these:

if($xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->citation->CI_Citation->title->children('http://www.isotc211.org/2005/gco'))

is that they are too long and too error-prone. Even SimpleXML allows that kind of "easy" access here, in case it does not find the element somewhere there-in, it will return NULL and then you get the warnings and even the fatal errors.

For you use-case it is much better to use an xpath query to do the job. As you need to access multiple properties representing the meta-data, I suggest to first of all wrap this into a class of it's own, exemplary SimpleXMLElementXpathObject, the there-in used PropertyIterator can be found here.

This type allows you to define the meta-data you look for with a SimpleXMLElement and an array that describes the properties by mapping them to xpath queries:

$metaDef = array(
'title' => 'gmd:identificationInfo//gmd:CI_Citation/gmd:title/gco:CharacterString',
'owner' => 'gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString',
'purpose' => 'gmd:identificationInfo/gmd:MD_DataIdentification/gmd:purpose/gco:CharacterString',
);

As you can see, there is one xpath expression per each key. The keys will be turned into properties. This then allows you to do the mappings on the fly, e.g.:

$meta = new SimpleXMLElementXpathObject($xml, $metaDef);
echo $meta->title, "\n";
echo json_encode($meta, JSON_PRETTY_PRINT), "\n";

Output:

Natuur - Ecologische verbindingszones
{
"title": "Natuur - Ecologische verbindingszones",
"owner": "provincie Frysl\u00e2n",
"purpose": "Beleidsnota \"ecologische verbindingszones in Frysl\u00e2n\" vastgesteld door Provinciale Staten op 4 oktober 2006. Opgenomen in het Streekplan 2007"
}

In case the xpath returns no result, NULL is given. That means the properties are optional, you won't see any warnings or even fatal errors. Just to make it clear: This is basically using the xpath method from SimpleXMLElement so you can also run these queries your own.

A more complete example:

$query = new GeoNetwork_Query();
$query
->setGeometry('POLYGON((5.5963 53.3162,5.5963 53.5766,6.9612 53.5766,6.9612 53.3162,5.5963 53.3162))')
->setLimit(10);

$metaObj = function (GeoNetwork_Resource $resource) {
$metaDef = array(
'title' => 'gmd:identificationInfo//gmd:CI_Citation/gmd:title/gco:CharacterString',
'owner' => 'gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString',
'purpose' => 'gmd:identificationInfo/gmd:MD_DataIdentification/gmd:purpose/gco:CharacterString',
);

return new SimpleXMLElementXpathObject($resource->getIterator(), $metaDef);
};

$resources = new GeoNetwork_UuidIterator($query);
$objects = new DecoratingIterator($resources, $metaObj);
$table = new HtmlTableIterator($objects, ['Title', 'Owner', 'Purpose']);

echo "<table>\n";
foreach ($table as $row) {
echo $row, "\n";
}
echo "</table>\n";

I have limited the output to 10 so that it won't create a too long list (for the query result). You can also limit the $objects by wrapping them in an LimitIterator. Exemplary output from the code above:

<table>
<tr><td>Title</td><td>Owner</td><td>Purpose</td></tr>
<tr><td>Natuur - Ecologische verbindingszones</td><td>provincie Fryslân</td><td>Beleidsnota "ecologische verbindingszones in Fryslân" vastgesteld door Provinciale Staten op 4 oktober 2006. Opgenomen in het Streekplan 2007</td></tr>
<tr><td>CORINE: Veranderingen in landgebruik in Nederland tussen 1986 en 2000.</td><td>Alterra, Wageningen UR</td><td>Het monitoren van landgebruiksveranderingen op Europese schaal volgens een standaard methode.</td></tr>
<tr><td>Viswaterkaart Sportvisserij</td><td>Sportvisserij Nederland</td><td>Elke sportvisser moet exact weten waar die onder welke (bijz.) voorwaarden mag hengelen.</td></tr>
<tr><td>Veiligheidsafstand vuurwerk</td><td>Interprovinciaal Overleg</td><td>Risicokaart</td></tr>
<tr><td>Weggeg convergenties</td><td>Rijkswaterstaat Data en ICT Dienst (RWS DID)</td><td>Ruimtelijke analyses waarbij ligging van infrastructuur van belang is en bereikbaarheidsberekeningen</td></tr>
<tr><td>Beheerkaart Nat Versie januari 2008</td><td>Rijkswaterstaat Data en ICT Dienst (RWS DID)</td><td>De Beheerkaart Nat wordt door de natte districten van Rijkswaterstaat gebruikt ten behoeve van beheer en onderhoud van zijn beheerobjecten van de watersystemenen. Het NIS gebruikt de gegevens om ondermeer de benodigde budgetten te bepalen voor beheer en onderhoud.</td></tr>
<tr><td>Orthofotomozaieken_project</td><td>Rijkswaterstaat Data en ICT Dienst (RWS DID)</td><td>Gebruik als ondergrond</td></tr>
<tr><td>Knelpunten in LAW-routes</td><td>Stichting Wandelnet</td><td>Inventarisatie van knelpunten in LAW-routes voor provincies</td></tr>
<tr><td>Electronische zeekaarten Ned. Cont. Plat usage Harbour</td><td>Dienst der Hydrografie</td><td>Veilige navigatie</td></tr>
<tr><td>Maatregelzone kernenergie</td><td>Interprovinciaal Overleg</td><td>Risicokaart</td></tr>
</table>

In the code above I used classes from here: https://gist.github.com/hakre/94a36e4587214a6e9bc9

Check if xml node exists in PHP

Sounds like a simple isset() solves this problem.

<?php
$s = new SimpleXMLElement('<foo version="1">
<weather section="0" />
<problem_cause data="" />
</foo>');
// var_dump($s) produces the same output as in the question, except for the object id numbers.
echo isset($s->problem_cause) ? '+' : '-';

$s = new SimpleXMLElement('<foo version="1">
<weather section="0" />
</foo>');
echo isset($s->problem_cause) ? '+' : '-';

prints +- without any error/warning message.

How to check if element exists with SimpleXML?

The order of parameter in your code is reversed. Correct is first the object then the property-name:

if (!property_exists($product, 'artnr')) {

And apparently this only works for "real" properties. If the property is implemented using the __get-Method this won't work either.

SimpleXML check if element has children and get child values

You can use xpath's child:: location path to select the article node childs and back up one for the article node like this:

$article_array = $xml->xpath('//article/child::*/..');

This should only return the article nodes that has childs (with id 1177 in your example).

SimpleXML check SimpleXML object exists

Your problem here is that you are testing too far into the chain of -> operators:

if ( $product->Product->LowestOfferListings->LowestOfferListing->Price->LandedPrice->Amount )

In order to even test this, PHP must evaluate each of the -> operators in turn

  1. $product->Product [OK]
  2. $product->Product->LowestOfferListings [OK]
  3. $product->Product->LowestOfferListings->LowestOfferListing [An empty set if there are no prices]
  4. $product->Product->LowestOfferListings->LowestOfferListing->Price [Undefined]
  5. After this, you're already too late.

Additionally, the SimpleXML object won't evaluate to false even if it's an empty list, so you do need to use isset. In order to spot the no-price situation, you therefore need this:

if ( isset($product->Product->LowestOfferListings->LowestOfferListing) )

[Note: I haven't actually tested the above, so I may have gone wrong in some specific, but I'm pretty sure this is your basic problem.]

Php SimpleXML find specific child node in any level in the parent

The only decision I came up with was to use this recursive function

foreach($xml as $prod){
...
$findme = getNode($prod, 'fabric');
...
}

function getNode($obj, $node) {
if($obj->getName() == $node) {
return $obj;
}
foreach ($obj->children() as $child) {
$findme = getNode($child, $node);
if($findme) return $findme;
}
}

Updated

Also as was suggested in comments we can use DOMDocument class like this:

 $dom = new DOMDocument();
$dom->LoadXML($xmlStr);
$nodes = $dom->getElementsByTagName('node');

foreach($nodes as $node)
{
$findme = $node->getElementsByTagName("findme")->item(0);
echo $findme->textContent."\r";
}

PHP SimpleXML has Child

You can use a simple isset() call for that

$node = new SimpleXMLElement('<foo><students>test</students></foo>');

var_dump(isset($node->students));

bool(true)

PHP: Check if XML node exists with attribute

I'd suggest the following (PHP using ext/simplexml and XPath):

$name = 'Shiny Red';
$xml = simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?>
<targets>
<showcases>
<building name="Big Blue" />
<building name="Shiny Red" />
<building name="Mellow Yellow" />
</showcases>
</targets>');
$nodes = $xml->xpath(sprintf('/targets/showcases/building[@name="%s"]', $name);
if (!empty($nodes)) {
printf('At least one building named "%s" found', $name);
} else {
printf('No building named "%s" found', $name);
}


Related Topics



Leave a reply



Submit