How to convert XML into array of objects in PHP? - php

I am trying to build a simple web app since I want to learn PHP.
I have this code:
// create objects
$object = new Post();
$object->name = 'Post no. 1';
$object->content = "My glorious content\nwritten in two lines!";
$object->fixed = 'True';
$object->picture = 'pathtoimg1.png';
$posts[] = $object;
$object = new Post();
$object->name = 'Post no. 2';
$object->content = 'Content.';
$object->fixed = 'False';
$object->picture = 'pathtoimg2.bmp';
$posts[] = $object;
// set xml
$postsXml = new SimpleXMLElement('<arrayOfPost></arrayOfPost>');
foreach($posts as $post){
$element = $postsXml->addChild('post');
$element->addChild('name', $post->name);
$element->addChild('content', $post->content);
$element->addChild('fixed', $post->fixed);
$element->addChild('picture', $post->picture);
}
echo $postsXml->asXML();
It creates this XML:
$xmlString = '<?xml version="1.0"?>
<arrayOfPost><post><name>Post no. 1</name><content>My content
written in two lines!</content><fixed>True</fixed><picture>pathtoimg1.png</picture></post><post><name>Post no. 2</name><content>Content.</content><fixed>False</fixed><picture>pathtoimg2.bmp</picture></post></arrayOfPost>';
And that is the class I am using:
class Post {
// Properties
public $name;
public $content;
public $fixed;
public $picture;
}
How can I parse the XML string to be an array of object "Post" again?

You can use SimpleXMLElement class simplexml_load_string method to parse the XML string into a SimpleXMLElement object, and then iterate over the post elements to recreate the Post objects:
$xml = simplexml_load_string($xmlString);
$posts = array();
foreach ($xml->post as $postXml) {
$post = new Post();
$post->name = (string) $postXml->name;
$post->content = (string) $postXml->content;
$post->fixed = (string) $postXml->fixed;
$post->picture = (string) $postXml-> picture;
$posts[] = $post;
}

Related

I am trying to scrap website but get only one array detail in xml file

I am trying to scrape this webpage. In this webpage I have to get the job title and its location. Which I am able to get from my code. But the problem is coming that when I am sending it in XML, then only one detail is going from the array list.
I am using goutte CSS selector library and also please tell me how to scrap pagination in goutte CSS selector library.
here is my code:
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://www.simplyhired.com/search?q=pharmacy+technician&l=American+Canyon%2C+CA&job=X5clbvspTaqzIHlgOPNXJARu8o4ejpaOtgTprLm2CpPuoeOFjioGdQ');
$job_posting_location = [];
$response->filter('.LeftPane article .SerpJob-jobCard.card .jobposting-subtitle span.JobPosting-labelWithIcon.jobposting-location span.jobposting-location')
->each(function ($node) use (&$job_posting_location) {
$job_posting_location[] = $node->text() . PHP_EOL;
});
$joblocation = 0;
$response->filter('.LeftPane article .SerpJob-jobCard.card .jobposting-title-container h3 a')
->each( function ($node) use ($job_posting_location, &$joblocation, $httpClient) {
$job_title = $node->text() . PHP_EOL; //job title
$job_posting_location = $job_posting_location[$joblocation]; //job posting location
// display the result
$items = "{$job_title} # {$job_posting_location}\n\n";
global $results;
$result = explode('#', $items);
$results['job_title'] = $result[0];
$results['job_posting_location'] = $result[1];
$joblocation++;
});
function convertToXML($results, &$xml_user_info){
foreach($results as $key => $value){
if(is_array($value)){
$subnode = $xml_user_info->addChild($key);
foreach ($value as $k=>$v) {
$xml_user_info->addChild("$k",htmlspecialchars("$v"));
}
}else{
$xml_user_info->addChild("$key",htmlspecialchars("$value"));
}
}
return $xml_user_info->asXML();
}
$xml_user_info = new SimpleXMLElement('<root/>');
$xml_content = convertToXML($results,$xml_user_info);
$xmlFile = 'details.xml';
$handle = fopen($xmlFile, 'w') or die('Unable to open the file: '.$xmlFile);
if(fwrite($handle, $xml_content)) {
echo 'Successfully written to an XML file.';
}
else{
echo 'Error in file generating';
}
what i got in xml file --
<?xml version="1.0"?>
<root><job_title>Pharmacy Technician
</job_title><job_posting_location> Vallejo, CA
</job_posting_location></root>
what i want in xml file --
<?xml version="1.0"?>
<root>
<job_title>Pharmacy Technician</job_title>
<job_posting_location> Vallejo, CA</job_posting_location>
<job_title>Pharmacy Technician 1</job_title>
<job_posting_location> Vallejo, CA</job_posting_location>
<job_title>Pharmacy Technician New</job_title>
<job_posting_location> Vallejo, CA</job_posting_location>
and so on...
</root>
You overwrite the values in the $results variable. You're would need to do something like this to append:
$results[] = [
'job_title' => $result[0];
'job_posting_location' => $result[1]
];
However here is no need to put the data into an array at all, just create the
XML directly with DOM.
Both your selectors share the same start. Iterate the card and then fetch
related data.
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', $url);
$document = new DOMDocument();
// append document element node
$postings = $document->appendChild($document->createElement('jobs'));
// iterate job posting cards
$response->filter('.LeftPane article .SerpJob-jobCard.card')->each(
function($jobCard) use ($document, $postings) {
// fetch data
$location = $jobCard
->filter(
'.jobposting-subtitle span.JobPosting-labelWithIcon.jobposting-location span.jobposting-location'
)
->text();
$title = $jobCard->filter('.jobposting-title-container h3 a')->text();
// append 'job' node to group data in result
$job = $postings->appendChild($document->createElement('job'));
// append data nodes
$job->appendChild($document->createElement('job_title'))->textContent = $title;
$job->appendChild($document->createElement('job_posting_location'))->textContent = $location;
}
);
echo $document->saveXML();

Send ID with DOMNodeList

I have this splendid code
public static function city($city)
{
$html = file_get_contents("http://www.example.com/?=$city");
libxml_use_internal_errors(true);
$doc = new \DOMDocument();
if($doc->loadHTML($html))
{
$result = new \DOMDocument();
$xpath = new \DOMXPath($doc);
$movies = $xpath->query("/html/body");
$url = $xpath->query("/html/body/a/#");
return $movies;
}
}
This function returns as expected a list om movies, and i fetch them with $movies->nodeValue
But i want to send an ID as well.
So i try to add this snipp (to explode the ID from the URL):
foreach($url as $MovieId){
$data=parse_url($MovieId->nodeValue, PHP_URL_QUERY);
$splittedstring=explode("&",$data);
$id[] = substr(strstr($splittedstring[0], "="),1);
}
And this works perfect when i just echo it like this:
$i=0;
echo '<ul>';
foreach ($movies as $key => $movie) {
echo '<li>'.$movie->nodeValue . '</li>';
$i++;
}
echo '</ul>';
But when trying to send it from the Model, to the view with:
$data = new stdClass;
$data->movie_title = $movies;
$data->movie_id = $id;
return $data;
I get: Notice: Undefined property: DOMNodeList::$nodeValue...
My question: How can i either
convert the $movies to a stdClass
send the id with the object(DOMNodeList) (and retrieve it how?)

DOM document character error

The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol.
dom create error like above,, and page return blank when I create new element in meta and data node like this :
<?php
$this->module->daftarkanJs('underscore-min.js');
$form = CJSON::decode(file_get_contents(Yii::app()->getBaseUrl(true).'/index.php/odk/api/index/id/'.$_GET['id']));
$input = CJSON::decode(file_get_contents(Yii::app()->getBaseUrl(true).'/index.php/odk/api/input/id/'.$_GET['id']));
function haveChild($id, $input_id){
$child = CJSON::decode(file_get_contents(Yii::app()->getBaseUrl(true).'/index.php/odk/api/child/id/'.$id.'/parentId/'.$input_id));
if($child['result']){ // jika child ada
foreach($child['result'] as $data){
// echo '- <b>'.$data['input_id'].'</b><br/>';
haveChild($id, $data['input_id']);
}
return true;
}else{
return false;
}
}
function loop($inputResult, $id){
$dom = new DOMDocument('1.0', 'utf-8');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$html = $dom->createElementNS('http://www.w3.org/2002/xforms', 'h:html');
$html->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:h', 'http://www.w3.org/1999/xhtml');
$html->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:ev', 'http://www.w3.org/2001/xml-events');
$html->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
$html->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:jr', 'http://openrosa.org/javarosa');
$html = $dom->appendChild($html);
$head = $dom->createElement('h:h');
$head = $html->appendChild($head);
$title = $dom->createElement('h:t', 'xxxxxxx');
$title = $head->appendChild($title);
$model = $dom->createElement('m');
$model = $head->appendChild($model);
$instance = $dom->createElement('instance');
$instance = $model->appendChild($instance);
$data = $dom->createElement('data');
$data = $instance->appendChild($data);
$meta = $dom->createElement('meta');
$meta = $data->appendChild($meta);
$instanceID = $dom->createElement('instaceID');
$instanceID = $meta->appendChild($instanceID);
$bind = $dom->createElement('bind');
$bind->setAttribute("nodeset","/data/meta/instanceID");
$bind = $model->appendChild($bind);
foreach($inputResult as $data){
if(!$data['parent_id']){ // ambil yang bukan child
$check = haveChild($id, $data['input_id']);
if(!$check){
$data = $dom->createElement('data');
$data = $instance->appendChild($data);
$meta = $dom->createElement('meta');
$meta = $data->appendChild($meta);
$bind = $dom->createElement('bind');
$bind->setAttribute("nodeset","/data/".str_replace(" ", "_", $data['name']));
$bind = $model->appendChild($bind);
}
}
}
$body = $dom->createElement('h:b');
$body = $html->appendChild($body);
printf ("<pre>%s</pre>", htmlentities ($dom->saveXML()));
}
loop($input['result'], $_GET['id']);
?>
error in this line :
$data = $dom->createElement('data');
$data = $instance->appendChild($data);
$meta = $dom->createElement('meta');
$meta = $data->appendChild($meta);
You don't output the XML, but HTML with escaped XML.
<pre>some escaped xml</pre>
This output matches the error message if it is treated as XML. Here is no XML declaration with an encoding.
Stripped down to the DOM methods, your source outputs an XML document: https://eval.in/private/1507ef8a4065d0.
However, I suggest to use createElementNS() for ALL namespaced nodes. Calls like $dom->createElement('h:h'); are ambiguous.
$xmlns = [ 'h' => 'http://www.w3.org/1999/xhtml' ];
$dom = new DOMDocument();
$html = $dom->appendChild(
$dom->createElementNS($xmlns['h'], 'h:html')
);
$head = $html->appendChild($dom->createElementNS($xmlns['h'], 'h:head'));
echo $dom->saveXml();
Output:
<?xml version="1.0"?>
<h:html xmlns:h="http://www.w3.org/1999/xhtml"><h:head/></h:html>

Convert form request data to xml in cakephp

I'm trying to convert all the form data in a cakephp request object to xml and then convert that to a string so that I can place it in a (blob) column in a mysql table.
I'm trying to do this current using the buildin xml builders in CakePHP 2.x.x as shown below but am getting an error.
if ($this->request->is('post')) {
$this->Survey->create();
$xml = Xml::build($this->request->data);
}
The form is shown below
<?php echo $this->Form->create('Survey'); ?>
<fieldset>
<legend><?php echo __('Add Survey'); ?></legend>
<?php
echo $this->Form->input('Question 1');
echo $this->Form->input('Question 2');
echo $this->Form->input('Question 3');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
The error I'm getting seems to be due to the DOCDocument->createElement(string,string) in the stacktrace. I've also used other methods including building it manually like so:
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$doc->loadHTML($this->request->data);
$data = $this->request->input('Xml::build',
array('return' => 'domdocument'));
while(list($key,$value) = each($this->request->data)){
$data = $data . $key . $value;
}
if(isset($this->request->data)){
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$root = $doc->appendChild($doc->createElement('survey'));
$post = $this->request->data['Survey'];
unset($post['submit']);
foreach($post as $key => $value){
$node = $doc->createElement($key,$value);
$root->appendChild($node);
}
$test1 = $doc->saveXML();
Any help would be appreciated. Thank you.
See the transforming an array into a string of XML section.

Using variable for tag in getElementsByTagName() for PHP and XML?

See my PHP:
file = "routingConfig.xml";
global $doc;
$doc = new DOMDocument();
$doc->load( $file );
function traverseXML($ElTag, $attr = null, $arrayNum = 'all'){
$tag = $doc->getElementsByTagName($ElTag);
$arr = array();
foreach($tag as $el){
$arr[] = $el->getAttribute($attr);
}
if ($arrayNum == 'all'){
return $arr;
}else if(is_int($arrayNum)){
return $arr[$arrayNum];
}else{
return "Invalid $arrayNum value: ". $arrayNum;
};
}
echo traverseXML("Route", "type", 2);
XML is:
<Routes>
<Route type="source"></Route>
<Route></Route>
<Routes>
Error returned is:
Fatal error: Call to a member function getElementsByTagName() on a non-object
I'm not sure how to do this?
EDIT: Here is the actual code being used. I originally stripped it a little bit trying to make it easier to read, but I think my problem is related to using the function.
Your problem is that the global $doc; statement is outside the function, so the variable $doc is not defined inside the function.
This would fix it:
// ...
function traverseXML($ElTag, $attr = null, $arrayNum = 'all') {
global $doc;
// ...
...but
Global variables are bad news. They usually indicate poor design.
Really you should pass $doc in as an argument, like this:
function traverseXML($doc, $ElTag, $attr = null, $arrayNum = 'all'){
$tag = $doc->getElementsByTagName($ElTag);
$arr = array();
foreach($tag as $el){
$arr[] = $el->getAttribute($attr);
}
if ($arrayNum == 'all'){
return $arr;
}else if(is_int($arrayNum)){
return $arr[$arrayNum];
}else{
return "Invalid $arrayNum value: ". $arrayNum;
};
}
$file = "routingConfig.xml";
$doc = new DOMDocument();
$doc->load( $file );
echo traverseXML($doc, "Route", "type", 2);
Although you might consider whether you need the function at all - if you don't use it anywhere else in you application, you might as well just do this:
$file = "routingConfig.xml";
$ElTag = "Route";
$attr = "type";
$arrayNum = 2;
$doc = new DOMDocument();
$doc->load( $file );
$tag = $doc->getElementsByTagName($ElTag);
$arr = array();
foreach($tag as $el){
$arr[] = $el->getAttribute($attr);
}
if ($arrayNum == 'all'){
echo $arr;
}else if(is_int($arrayNum)){
echo $arr[$arrayNum];
}else{
echo "Invalid $arrayNum value: ". $arrayNum;
};
The $doc variable is not defined inside your function. You have two options:
Pass $doc as one of the function arguments, which is preferred.
Write global $doc; at the top of your function ... devs usually try to avoid globals.

Categories