1

I have different XML files where I renamed for each XML file all individual tags, so that every XML file has the same tag name. That was easy because the function was customized for the XML file.

But instand of writing 7 new functions for each XML file now I want to check if a XML file has a specidifed child or not. Because if I want to say:

foreach ($items as $item) {
$node = dom_import_simplexml($item);
$title = $node->getElementsByTagName('title')->item(0)->textContent;
$price = $node->getElementsByTagName('price')->item(0)->textContent;
$url = $node->getElementsByTagName('url')->item(0)->textContent;
$publisher = $node->getElementsByTagName('publisher')->item(0)->textContent;
$category = $node->getElementsByTagName('category')->item(0)->textContent;
$platform = $node->getElementsByTagName('platform')->item(0)->textContent;
}

I get sometimes: PHP Notice: Trying to get property of non-object in ...

For example. Two different XML sheets. One contains publisher, category and platform, the other not:

XML 1:

<products>
  <product>
    <desc>This is a Test</desc>
    <price>11.69</price>
    <price_base>12.99</price_base>
    <publisher>Stackoverflow</publisher>
    <category>PHP</category>
    </packshot>
    <title>Check if child exists? - SimpleXML (PHP)</title>
    <url>http://stackoverflow.com/questions/ask</url>
  </product>
</products>

XML 2:

<products>
  <product>
   <image></image>
    <title>Questions</title>
    <price>23,90</price>
    <url>google.de/url>
    <platform>Stackoverflow</platform>
  </product>
</products>

You see, sometimes one XML file contains publisher, category and platform but sometimes not. But it could also be that not every node of a XML file contains all attributes like in the first!

So I need to check for every node of a XML file individual if the node is containing publisher, category or/and platform.

How can I do that with SimpleXML? I thought about switch case but at first I need to check which childs are contained in every node.

EDIT: Maybe I found a solution. Is that a solution or not?

if($node->getElementsByTagName('platform')->item(0)){
        echo $node->getElementsByTagName('platform')->item(0)->textContent . "\n";
    }

Greetings and Thank You!

Jan
  • 277
  • 1
  • 6
  • 16

2 Answers2

0

One way to rome... (working example)

$xml = "<products>
  <product>
    <desc>This is a Test</desc>
    <price>11.69</price>
    <price_base>12.99</price_base>
    <publisher>Stackoverflow</publisher>
    <category>PHP</category>
    <title>Check if child exists? - SimpleXML (PHP)</title>
    <url>http://stackoverflow.com/questions/ask</url>
  </product>
</products>";
$xml = simplexml_load_string($xml);
#set fields to look for
foreach(['desc','title','price','publisher','category','platform','image','whatever'] as $path){
       #get the first node
       $result = $xml->xpath("product/{$path}[1]");
       #validate and set
       $coll[$path] = $result?(string)$result[0]:null;  
       #if you need here a local variable do (2 x $)
       ${$path} = $coll[$path];
}
#here i do array_filter() to remove all NULL entries
print_r(array_filter($coll));
#if local variables needed do
extract($coll);#this creates $desc, $price

Note </packshot> is an invalid node, removed here.

xpath syntax https://www.w3schools.com/xmL/xpath_syntax.asp

JustOnUnderMillions
  • 3,741
  • 9
  • 12
  • The path should be `$xml->xpath("products/product/{$path}[1]");`. Or I am wrong? – Jan Feb 24 '17 at 12:08
  • @Jan Its about relativ an absolute. Absolute is `/a/b/c` relativ is `b/c` or `c` all will find the same data here. Only beware when you have komplex xml where subnodes are often the same, there you better do absolute pathes instead of relativ once. – JustOnUnderMillions Feb 24 '17 at 12:15
  • I do not get your code. After 1hr trying I maybe found a solution. I updated my question, is that also an solution. – Jan Feb 24 '17 at 13:49
0

Firstly, you're over-complicating your code by switching from SimpleXML to DOM with dom_import_simplexml. The things you're doing with DOM can be done in much shorter code with SimpleXML.

Instead of this:

$node = dom_import_simplexml($item);
$title = $node->getElementsByTagName('title')->item(0)->textContent;

you can just use:

$title = (string)$item->title[0];

or even just:

$title = (string)$item->title;

To understand why this works, take a look at the SimpleXML examples in the manual.

Armed with that knowledge, you'll be amazed at how simple it is to see if a child exists or not:

if ( isset($item->title) ) {
    $title = (string)$item->title;
} else {
    echo "There is no title!";
}
IMSoP
  • 89,526
  • 13
  • 117
  • 169