3

Getting this error

Call to a member function attributes() on a non-object

I have found multiple answers to this on SO, but none of them seem to solve my problem?

Here is the XML:

<Routes>
    <Route type="source" name="incoming">
    </Route>
<Routes>

Here is the PHP:

$doc = new SimpleXMLElement('routingConfig.xml', null, true);
class traverseXML {

    function getData() {
        global $doc;
        $routeCount = count($doc -> xpath("Route")); //this value returns correctly
        $routeArr = array();
        for ($i = 1; $i <= $routeCount; $i++) {

            $name = $doc -> Route[$i] -> attributes() -> name;

            array_push($routeArr, $name);

        }
        return $routeArr;

    }

    }
    $traverseXML = new traverseXML;
    var_dump($traverseXML -> getData());

I understand what the error means, but how is it a non-object? How do I return the name attribute of Routes/Route[1] ?

hakre
  • 193,403
  • 52
  • 435
  • 836
Jared
  • 1,795
  • 6
  • 32
  • 55

1 Answers1

2

Your $doc is <Routes>. Trying to get ->Routes from it is trying to get

<Routes>
    <Routes>

You need to do $doc->Route[$i]. Errors like this are less frequent when you name your variable after the document root:

$Routes = new SimpleXMLElement('routingConfig.xml', null, true);

Also, your XML is invalid. The Routes element is not closed.

In addition, you don't need the XPath. SimpleXML is traversable, so you can foreach over all the routes by doing

foreach ($Routes->Route as $route) {

And attributes() returns an array, so you cannot chain ->name off it but must access it with square brackets. But it's not necessary to use attributes() anyway because you can get attributes from SimpleXmlElements directly via square brackets, e.g.

echo $route['name'];

Here is an example that will print "incoming":

$xml = <<< XML
<Routes>
    <Route type="source" name="incoming"/>
</Routes>
XML;

$routes = simplexml_load_string($xml);

foreach ($routes->Route as $route) {
    echo $route['name'];
}

demo

If you want to do it with XPath, you can collect all the attributes in an array like this:

$routeNames = array_map('strval', $Routes->xpath('/Routes/Route/@name'));

Yes, it's just that one line :)

As for your class:

Don't use global. Forget it exists. If you want to have a class, inject the dependency, e.g. do

class Routes
{
    private $routes;

    public function __construct(SimpleXmlElement $routes)
    {
        $this->routes = $routes;
    }

    public function getRouteNames()
    {
        return array_map('strval', $this->routes->xpath('/Routes/Route/@name'));
    }
}

$routes = new Routes(simplexml_load_string($xml));
print_r($routes->getRouteNames());

demo

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • Thank you! I actually had the right XML document, but screwed up my paste. This is much cleaner than my route. – Jared Sep 04 '12 at 21:51