Can I find selected options in a form using simplexml? - php

I'm able to find a select's options on a website using the following code:
$dom = new DOMDocument();
$dom->loadHTMLFile('http://webseven.com.au/carl/testpage.htm');
$xml = simplexml_import_dom($dom);
//print_r($xml);
$select = $xml->xpath('//table/tr/td/select');
print_r($select);
I get (as an example)
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => product_OnWeb
[tabindex] => 4
)
[option] => Array
(
[0] => Yes
[1] => No
)
)
But I cannot find a way to find which of those is selected. Can this be done with SimpleXML or is there another method?

You need to loop through all the options (using foreach ( $node->option ... )), and check for the selected attribute (using $node['selected']):
$dom = new DOMDocument();
$dom->loadHTMLFile('http://webseven.com.au/carl/testpage.htm');
$xml = simplexml_import_dom($dom);
$selects = $xml->xpath('//table/tr/td/select');
foreach ( $selects as $select_node )
{
echo $select_node['name'] . ': ';
foreach ( $select_node->option as $option_node )
{
if ( isset($option_node['selected']) )
{
echo $option_node['value'] . ' ';
}
}
echo "\n";
}
As an aside, you are likely to be led astray if you use print_r to debug SimpleXML, as it doesn't show you the true state of the object. I've written a simplexml_dump function which might be more useful.

Related

Storing XML Document with XPath and PHP, tag info isn't storing in array like needed

So, I want to iterate through the XML by the attributes of and then print the tags from within the coordinating tag. This is the structure:
<emp salesid="1">
<report>07-14-2015_DPLOH_SalesID_1.pdf</report>
<report>07-17-2015_DPLOH_SalesID_1.pdf</report>
<report>07-14-2015_DTE_SalesID_1.pdf</report>
<report>07-14-2015_IDT_SalesID_1.pdf</report>
<report>07-14-2015_Kratos_SalesID_1.pdf</report>
<report>07-14-2015_Spark_SalesID_1.pdf</report>
</emp>
Here is the my code:
$xml = new SimpleXMLElement($xmlStr);
foreach($xml->xpath("//emp/report") as $node) {
//For all found nodes retrieve its ID from parent <emp> and store in $arr
$id = $node->xpath("../#salesid");
$id = (int)$id[0];
if(!isset($arr[$id])) {
$arr[$id] = array();
}
//Then we iterate through all nodes and store <report> in $arr
foreach($node as $report) {
$arr[$id][] = (string)$report;
}
}
echo "<pre>";
print_r($arr);
echo "</pre>";
However, this is what I get for output:
Array
(
[1] => Array
(
)
[10] => Array
(
)
... and it continues to iterate through all of the attributes of tags, but never fills the array with any information.
If anyone could help tell me what I'm missing, I would GREATLY appreciate it. I feel like I'm losing my mind over what seems like should be rather simple.
Thanks!
You're very close. The code isn't working because of the second for loop. The outer loop will iterate through all of the report elements. So, node is a report element. When you try to iterate through the children of report, there's nothing there.
Instead of the second (inner) loop, simply do this:
$arr[$id][] = (string)$node;
When I did, I got the following result:
<pre>
Array
(
[1] => Array
(
[0] => 07-14-2015_DPLOH_SalesID_1.pdf
[1] => 07-17-2015_DPLOH_SalesID_1.pdf
[2] => 07-14-2015_DTE_SalesID_1.pdf
[3] => 07-14-2015_IDT_SalesID_1.pdf
[4] => 07-14-2015_Kratos_SalesID_1.pdf
[5] => 07-14-2015_Spark_SalesID_1.pdf
)
)
I updated your script to work slightly differently:
$emp = new SimpleXMLElement($xmlStr);
$id = intval($emp['salesid']);
$arr = array(
$id => array(),
);
$lst = $emp->xpath('/emp/report');
while (list(, $text) = each($lst))
{
$arr[$id][] = (string) $text;
}
echo "<pre>";
print_r($arr);
echo "</pre>";
Cheers

SimpleXmlElement count

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.

How can I extract value from an xml

I'm new to PHP. I'm trying to get the data out of the below XML. Now, in my code $data->Address contains value of the below code i.e:
$data->Address = "<tolist></tolist>
<cclist>
<cc>
<contactpersonname>niraj</contactpersonname>
<name>niraj</name>
<email>stgh#gmail.com</email>
<number>+91.3212365212</number>
<prefix>Ms.</prefix>
<contactpersonprefix>Ms.</contactpersonprefix>
</cc>
<cc>
<contactpersonname>fdg</contactpersonname>
<name>admin</name>
<email>admin12#gmail.com</email>
<number>+91.4554343234</number>
<prefix>Mr.</prefix>
<contactpersonprefix>Mr.</contactpersonprefix>
</cc>
</cclist>";
Now I want to extract the <contactpersonname> tag and print it. How can I do this?
Since your XML is missing a tag that encompasses all others, you need to create on in order to get parsers to work properly:
<?php
$buffer = "<tolist></tolist>
<cclist>
<cc>
<contactpersonname>niraj</contactpersonname>
<name>niraj</name>
<email>stgh#gmail.com</email>
<number>+91.3212365212</number>
<prefix>Ms.</prefix>
<contactpersonprefix>Ms.</contactpersonprefix>
</cc>
<cc>
<contactpersonname>fdg</contactpersonname>
<name>admin</name>
<email>admin12#gmail.com</email>
<number>+91.4554343234</number>
<prefix>Mr.</prefix>
<contactpersonprefix>Mr.</contactpersonprefix>
</cc>
</cclist>";
// ***** wrap the whole thing in a <root> tag...
$xml = simplexml_load_string("<root>".$buffer."</root>");
$array = json_decode(json_encode((array) $xml), 1);
echo "<pre>";
print_r($array);
echo "</pre>";
?>
Result:
Array
(
[tolist] => Array
(
)
[cclist] => Array
(
[cc] => Array
(
[0] => Array
(
[contactpersonname] => niraj
[name] => niraj
[email] => stgh#gmail.com
[number] => +91.3212365212
[prefix] => Ms.
[contactpersonprefix] => Ms.
)
[1] => Array
(
[contactpersonname] => fdg
[name] => admin
[email] => admin12#gmail.com
[number] => +91.4554343234
[prefix] => Mr.
[contactpersonprefix] => Mr.
)
)
)
)
UPDATED
Now you can navigate down to where you want to go with
echo "<pre>";
$ccList = $array['cclist'];
$cc = $ccList['cc'];
$contacts = array();
foreach($cc as $i=>$val) {
$contacts[$i]=$val['contactpersonname'];
}
echo "first contact: " . $contacts[0] . "<br>";
echo "second contact: " . $contacts[1] ."<br>";
Result:
first contact: niraj
second contact: fdg
You can convert the XML to an array with the following code:
$xml = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), 1);
Where $buffer is the xml string.
Then you can obtain the person name as follow:
$data->Address = $array['cclist']['cc']['contactpersonname'];
It's a quick and dirty method to convert the xml to an array, but it works.
Try this..
$xml = new SimpleXMLElement($string);
$results = $xml->xpath('cclist/cc/contactpersonname');
http://php.net/manual/en/simplexmlelement.xpath.php
$xml = simplexml_load_file("note.xml");
echo $xml->contactpersonname;
This requires you to load it form an xml file. If you already have the string in the code I'd recommend a regex. If you know the data won't ever be incorrect written!
$pattern = '#<contactpersonname>(.*?)</contactpersonname>#';
echo preg_match ($pattern, $data->Address);

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);

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