SimpleXmlElement count - php

I'm trying to count the amount of children in a SimpleXmlElement. I've searched on StackOverflow but I can't seem to find anything;
$xml = simplexml_load_string($xml);
foreach($xml as $key => $field) {
if (count($field) == 0){
$field[0][0] = 'test';
}
}
Some of my XmlElement are empty. Yet count gives 0 on all the elements. The only way I've found to do what I want is this:
if ($field[0][0] == '')
I've tried using $field->count() as specified on http://php.net/manual/en/simplexmlelement.count.php, but no matter what is in $field, it always returns 0.
Isn't there a better way to do this?
Here is the format of the xml through print_r:
SimpleXMLElement Object
(
[firstName] => Test
[lastName] => Test2
[middleName] => SimpleXMLElement Object
(
)
)

You can use the count() function like this:
$elem = new SimpleXMLElement($xml);
$elem->count();
http://php.net/manual/en/simplexmlelement.count.php for reference.

Related

Extracting data from xpath reference of SimpleXMLElement Object

I'm trying to read an XML file into an array and I'm having a little bit of trouble. Here is what my code looks like so far:
$inst = new SimpleXMLElement($xml);
foreach( $inst->xpath("record[#id='" . $range . "']") as $u ) {
foreach($fields as $field) {
$results[$field] = $u->$field;
}
}
But when I do print_r($results), this is what's outputted:
Array
(
[field1] => SimpleXMLElement Object
(
[0] => field1Data
)
[field2] => SimpleXMLElement Object
(
[0] => field2Data
)
[field3] => SimpleXMLElement Object
(
[0] => field3Data
)
)
How can I get the data straight from the SimpleXMLElement Object and store it in the array rather than having it do this? I tried accessing it as an array like $u->$field[0] but that didn't work either.
Casting a SimpleXMLElement to string is the general solution(see "Forcing a SimpleXML Object to a string, regardless of context" for the canonical question), for a complete array containing all SimpleXMLElements like returned by xpath() or like you create it your own, a common way is to map the array onto trim:
$results = array_map('trim', $results);
or strval:
$results = array_map('strval', $results);
For example:
$inst = new SimpleXMLElement($xml);
list($u) = $inst->xpath("record[#id='" . $range . "']")
foreach ($fields as $field) {
$results[$field] = $u->$field;
}
$results = array_map('strval', $results);

query xpath with php

I wrote following php code to extract nodes information from this xml:
<sioctBoardPost rdfabout="http//boards.ie/vbulletin/showpost.php?p=67075">
<rdftype rdfresource="http//rdfs.org/sioc/ns#Post" />
<dctitle>hib team</dctitle>
<siochas_creator>
<siocUser rdfabout="http//boards.ie/vbulletin/member.php?u=497#user">
<rdfsseeAlso rdfresource="http//boards.ie/vbulletin/sioc.php?sioc_type=user&sioc_id=497" />
</siocUser>
</siochas_creator>
<dctermscreated>1998-04-25T213200Z</dctermscreated>
<sioccontent>zero, those players that are trialing 300 -400 pingers? umm..mager lagg and even worse/</sioccontent>
</sioctBoardPost>
<?php
$xml = simplexml_load_file("boards.xml");
$products[0] = $xml->xpath("/sioctBoardPost/sioccontent");
$products[1] = $xml->xpath("/sioctBoardPost/dctermscreated");
$products[2] = $xml->xpath("/sioctBoardPost/#rdfabout");
print_r($products);
?>
This gives following output:
Array (
[0] => Array ( [0] => SimpleXMLElement Object ( [0] => zero, those players that are trialing for hib team, (hpb's) most of them are like 300 -400 pingers? umm..mager lagg and even worse when they play on uk server's i bet/ ) ) [1] => Array ( [0] => SimpleXMLElement Object ( [0] => 1998-04-25T213200Z ) ) [2] => Array ( [0] => SimpleXMLElement Object ( [#attributes] => Array ( [rdfabout] => http//boards.ie/vbulletin/showpost.php?p=67075 ) ) )
)
But I need only nodes content as an output i.e without Array([0] => Array etc.
Output should be like this:
zero, those players that are trialing for hib team, (hpb's) most of them are like 300 -400 pingers? umm..mager lagg and even worse when they play on uk server's i bet
1998-04-25T213200Z
http//boards.ie/vbulletin/showpost.php?p=67075
Thanks in advance
You can use current() to only get the first element of each XPath result (which is an array) and then use a (string) cast to get the node contents:
$products[0] = (string)current($xml->xpath("/sioctBoardPost/sioccontent"));
$products[1] = (string)current($xml->xpath("/sioctBoardPost/dctermscreated"));
$products[2] = (string)current($xml->xpath("/sioctBoardPost/#rdfabout"));
print_r($products);
As you have observed, the xpath() method returns an array of matched nodes, so you need to deal with the elements of the returned arrays. I believe this should work in this case:
$xml = simplexml_load_file("boards.xml");
$products[0] = $xml->xpath("/sioctBoardPost/sioccontent")[0];
$products[1] = $xml->xpath("/sioctBoardPost/dctermscreated")[0];
$products[2] = $xml->xpath("/sioctBoardPost/#rdfabout")[0];
print_r($products);
This should get you what you need...
foreach ($products as $product) { // iterate through the $products array
print $product[0]->nodeValue // output the node value of the SimpleXMLElement Object
}

capture the value of an element in array returned by simpleXML in PHP?

Any idea how can i get a single value from an element in array returned by an XML which looks like this?
SimpleXMLElement Object
(
[status] => SimpleXMLElement Object
(
[id] => 0
[description] => Success
)
......
I want to capture the [id] and return that value to run tests against it.
the above was captured using the following
$xml = simplexml_load_string($result);
Thanks
Try this $id = $xml->status->id;
Are you looking for something like:
$sxml = new SimpleXMLElement("<statuses><status><id>0</id><description>success</description></status></statuses>");
var_dump((string) $sxml->status[0]->id);

SimpleXML and XML collections - how to get the attribute value as an array key?

I'm just trying to figure out how to cleanly and nicely transform a XML collection into an appropriate object. See, I've got this very simple XML string :
$x = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<apiKeys>
<apiKey application="app1">HfxaoMBJJ9pLe</apiKey>
<apiKey application="app2">HfxaoMBJJ9pLeClsSHsh</apiKey>
<apiKey application="app3">HfxaoMBJJ9pLeClsSHshTI9qX</apiKey>
</apiKeys>';
Which I transform using :
$O_xmlElement = simplexml_load_string ($x);
This is what I get :
SimpleXMLElement Object
(
[apiKey] => Array
(
[0] => HfxaoMBJJ9pLe
[1] => HfxaoMBJJ9pLeClsSHsh
[2] => HfxaoMBJJ9pLeClsSHshTI9qX
)
)
And I'd rather have (I expected !) something like :
SimpleXMLElement Object
(
[apiKey] => Array
(
['app1'] => HfxaoMBJJ9pLe
['app2'] => HfxaoMBJJ9pLeClsSHsh
['app3'] => HfxaoMBJJ9pLeClsSHshTI9qX
)
)
Thank you very much for your help people
SimpleXML won't do what you want automatically. You'll have to build the object yourself:
$O_xmlElement = simplexml_load_string($x);
$myObject = new stdClass();
foreach ($O_xmlElement->apiKey as $apiKey) {
$key = (string) $apiKey['application'];
$myObject->${key} = (string) $apiKey;
}
Refer to the basic usage example in the PHP manual for good examples of dealing with child elements and attributes.
When getting attributes from a SimpleXMLElement, remember that each attribute will be a SimpleXMLElement and not a string. You'll want to explicitly cast each attribute to string before using it as an array key or object property name.
Not sure you can do it exactly as you want it, but you can check out php.net's docs here:
http://www.php.net/manual/en/simplexmlelement.attributes.php
Basically the attributes can be found inside an object attached to each of the apiKey objects.
You can use the following code:
$xml = simplexml_load_string($x);
$newArray = array();
$count=0;
foreach($xml as $value){
$key= (string)($xml->apiKey[$count++]->attributes()->application);
$newArray[$key] = $value[0];
}
$newArray = array_map("trim", $newArray);
print_r($newArray);
This will generate the following output:
Array
(
[app1] => HfxaoMBJJ9pLe
[app2] => HfxaoMBJJ9pLeClsSHsh
[app3] => HfxaoMBJJ9pLeClsSHshTI9qX
)

php xpath problems

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("//*");
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";
}
# 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");

Categories