3

I'm doing a cURL POST and get the error response back, parse it into an array but having issues with xpath now.

// XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<errors xmlns="http://host/project">
   <error code="30" description="[] is not a valid email address."/>
   <error code="12" description="id[] does not exist."/>
   <error code="3" description="account[] does not exist."/>
   <error code="400" description="phone[] does not exist."/>
</errors>

// Function / Class

class parseXML
{
    protected $xml;

    public function __construct($xml) {
        if(is_file($xml)) {
            $this->xml = simplexml_load_file($xml);
        } else {
            $this->xml = simplexml_load_string($xml);
        }
    }

    public function getErrorMessage() {
        $in_arr = false;
        $el = $this->xml->xpath("//@errors");        
        $returned_errors = count($el);

        if($returned_errors > 0) {
            foreach($el as $element) {
                if(is_object($element) || is_array($element)) {
                    foreach($element as $item) {
                        $in_arr[] = $item;
                    }
                }
            }
        } else {
            return $returned_errors;
        }            
        return $in_arr;
    }
}

// Calling function

// $errorMessage is holding the XML value in an array index
// something like: $arr[3] = $xml;
$errMsg = new parseXML($arr[3]); 
$errMsgArr = $errMsg->getErrorMessage();

What I would like is all the error code and description attribute values

EDIT:

OK this is print_r($this->xml,true);

SimpleXMLElement Object
(
    [error] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [code] => 30
                            [description] => [] is not a valid email address.
                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [code] => 12
                            [description] => Id[12345] does not exist.
                        )

                )

            [2] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [code] => 3
                            [description] => account[] does not exist.
                        )

                )

            [3] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [code] => 400
                            [description] => phone[] does not exist.
                        )

                )

        )

)

for the life of me I can't figure out why I can get the code and description, any thoughts?

EDIT #2 Okay so I guess I will break it down.

I'm using cURL to POST a request to one of our servers, I parse out the HTTP response headers and xml (if xml is returned). each line in the header/xml I explode into an array. so if there is an error I see an extra index to the array. I then do something like this.

$if_err_from_header = $http_return_response[10]; 
// I know that index 10 is where if any the error message in xml is (the one posted above).

after that I do this:

$errMsg = new parseXML($if_err_from_header); 
$errMsgArr = $errMsg->getErrorMessage();

still I can not get the code and description from the attributes in error, what am I missing?

EDIT #3 Okay why does this work?

$in_arr = false;
// This returns all the code attributes
$el = $this->xml->xpath("//@code");

# if $el is false, nothing returned from xpath(), set to an empty array
$el = $el == false ? array() : $el;

foreach($el as $element) {
    $in_arr[] = array("code" => $element["code"], "description" => $element["description"]);
}
return $in_arr;

EDIT #4:

Okay this gets that values I want but it's kinda a hack, would like to select specific elements but...

$el = $this->xml->xpath("//*");

2 Answers 2

2

Make sure you take the namespace into account:

$this->xml->registerXPathNamespace('n', 'http://host/project');
$el = $this->xml->xpath("/n:errors/n:error");
$returned_errors = count($el);

And example of accessing values for lower down..

foreach($el as $element) {
   print "code: " . $element["code"] . "\n";
}
Sign up to request clarification or add additional context in comments.

6 Comments

so just to clarify n is the variable used for the namespace or is the name of the namespace? so I have xmlns, would I use that or n?
@Phil, you've defined "host/project" as the default namespace, and we're choosing to associate the prefix "n" with it. Without specifying this namespace, PHP attempts to use the null namespace and therefore the XPath expression will return an empty set. As an experiment, create a new error node with the xmlns attribute set to "example". You'll see that it is not returned in the output with the others.
added how the SimpleXMLElement Object is coming through, any thoughts?
I'd guess because each of those elements ($element in your example) is an object, not an array. Did you try the second part of my example with the foreach()? You should be able to use $element["code"] and $element["description"] rather than creating another loop.
I've tried you're very nice code but still nothing but an empty array s returned. I have several other functions that I use xpath on and all work without a hitch. but for the life of me I can't figure out why this object doesn't. please see edit #2
|
1

@ in XPath is the attribute selector. You're trying to select the root element so it should be:

  $el = $this->xml->xpath("/errors");

If you want to select all error elements, use

  $el = $this->xml->xpath("/errors/error");

or

  $el = $this->xml->xpath("//error");

3 Comments

hmm still not working, but thanks for pointing out I was using the attribute selector
if I just pass the array index I get an error, this is due to the index not being a string. if I cast the index into a string I get 0 as xpath finds nothing. any thoughts as to why?
added how the SimpleXMLElement Object is coming through, any thoughts?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.