PHP array_push() 2-dimensional array - php

array_push($typedict[$current], "value");
Does not seem to do anything here, i output the associative array of arrays($typedict) but all of them are empty(array()). I print the current associative index out with echo to confirm that it is the correct one(it always is).
Since the print chelc at the end states "[name] => Array()" i have no clue what could be the problem as this indicates that they are indeed arrays and therefore could have stuff pushed in. Also the var $current as stated always have the correct content. at:
echo "current: ". $current;
full code:
<?php
$typedict = array();
$xsdstring = file_get_contents("infile.xsd");
$xsdstring = str_replace("xs:choice", "xs:sequence", $xsdstring);
$doc = new DOMDocument();
$doc->loadXML(mb_convert_encoding($xsdstring, 'utf-8', mb_detect_encoding($xsdstring)));
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
$xpath->registerNamespace('vc', 'http://www.w3.org/2007/XMLSchema-versioning');
function outputFormat($indent, $elementDef)
{
echo "<div>" . $indent . $elementDef->getAttribute('name')
. " type:" . $elementDef->getAttribute('type')
. " min:" . $elementDef->getAttribute('minOccurs')
. " max:" . $elementDef->getAttribute('maxOccurs')
. "</div>\n";
}
function echoElements($indent = "", $elementDef, $evaluate, &$typedict)
{
global $doc, $xpath, $current;
if($indent == "")
{
$attribute_name = $elementDef->getAttribute('name');
$typedict[$attribute_name] = array();
$current = $attribute_name;
}else{
echo "current: ". $current;
$type = $elementDef->getAttribute('name');
array_push($typedict[$current], "value");
#$typedict[$current][0] = "value";
print_r($typedict[$current]);
}
outputFormat($indent, $elementDef);
$elementDefs = $xpath->evaluate($evaluate, $elementDef);
foreach($elementDefs as $elementDef)
{
echoElements($indent . " ", $elementDef, $evaluate);
}
}
$elementDefs = $xpath->evaluate("/xs:schema/xs:element");
foreach($elementDefs as $elementDef)
{
echoElements("", $elementDef, "xs:complexType/xs:sequence/xs:element", $typedict);
}
$elementDefs = $xpath->evaluate("/xs:schema/xs:complexType");
foreach($elementDefs as $elementDef)
{
echoElements("", $elementDef, "xs:sequence/xs:element", $typedict);
}
print_r($typedict);
?>

$current does contain the correct value. As seen in the code i check it pretty much everytime it gets set. So im pretty confident about that part.
I do not want to change whatever is in $current as it behaves excactly as i want.
My goal is an array inside each entry of the associative array $typedict.
Example:
$typedict["whatever"][0] = "value";
$typedict["whatever"][1] = "value";
...
$current is the index of $typedict not any of it's contents. So in this case $current contains the string "whatever" and not "value". And this is how it should be.
Edit:
I think i figured out the problem. But i have no clue how this could happen and therefore can't fix it:
$typedict["whatever"] seems to be only visible inside the IF block since the last value is okay if chekcked inside the block.
I somehow need to declare the whole structure of $typedict as global. Not just the base array(the associative one) but alos all the arrays inside it. But i only get to know the keys later.
Edit2:
Definetly a visibilty problem:
changing:
global $doc, $xpath, $current;
to:
global $doc, $xpath, $current, $typedict;
solved it

Related

Getting a random object from an array in PHP

First and foremost, forgive me if my language is off - I'm still learning how to both speak and write in programming languages. How I can retrieve an entire object from an array in PHP when that array has several key, value pairs?
<?php
$quotes = array();
$quotes[0] = array(
"quote" => "This is a great quote",
"attribution" => "Benjamin Franklin"
);
$quotes[1] = array(
"quote" => "This here is a really good quote",
"attribution" => "Theodore Roosevelt"
);
function get_random_quote($quote_id, $quote) {
$output = "";
$output = '<h1>' . $quote["quote"] . '.</h1>';
$output .= '<p>' . $quote["attribution"] . '</p>';
return $output;
} ?>
<?php
foreach($quotes as $quote_id => $quote) {
echo get_random_quote($quote_id, $quote);
} ?>
Using array_rand and var_dump I'm able to view the item in the browser in raw form, but I'm unable to actually figure out how to get each element to display in HTML.
$quote = $quotes;
$random_quote = array_rand($quote);
var_dump($quote[$random_quote]);
Thanks in advance for any help!
No need for that hefty function
$random=$quotes[array_rand($quotes)];
echo $random["quote"];
echo $random["attribution"];
Also, this is useless
<?php
foreach($quotes as $quote_id => $quote) {
echo get_random_quote($quote_id, $quote);
} ?>
If you have to run a loop over all the elements then why randomize hem in the first place? This is circular. You should just run the loop as many number of times as the quotes you need in output. If you however just need all the quotes but in a random order then that can simply be done in one line.
shuffle($quotes); // this will randomize your quotes order for loop
foreach($quotes as $qoute)
{
echo $quote["quote"];
echo $quote["attribution"];
}
This will also make sure that your quotes are not repeated, whereas your own solution and the other suggestions will still repeat your quotes randomly for any reasonably sized array of quotes.
A simpler version of your function would be
function get_random_quote(&$quotes)
{
$quote=$quotes[array_rand($quotes)];
return <<<HTML
<h1>{$quote["quote"]}</h1>
<p>{$quote["attribution"]}</p>
HTML;
}
function should be like this
function get_random_quote($quote_id, $quote) {
$m = 0;
$n = sizeof($quote)-1;
$i= rand($m, $n);
$output = "";
$output = '<h1>' . $quote[$i]["quote"] . '.</h1>';
$output .= '<p>' . $quote[$i]["attribution"] . '</p>';
return $output;
}
However you are not using your first parameter-$quote_id in the function. you can remove it. and call function with single parameter that is array $quote
Why don't you try this:
$quote = $quotes;
$random_quote = array_rand($quote);
$random = $quote[$random_quote];
echo '<h1>' . $random["quote"] . '.</h1><br>';
echo '<p>' . $random["attribution"] . '</p>';
Want to create a function:
echo get_random_quote($quotes);
function get_random_quote($quotes) {
$quote = $quotes;
$random_quote = array_rand($quote);
$random = $quote[$random_quote];
return '<h1>' . $random["quote"] . '.</h1><br>'.'<p>' . $random["attribution"] . '</p>';
}
First, you dont need the $quote_id in get_random_quote(), should be like this:
function get_random_quote($quote) {
$output = "";
$output = '<h1>' . $quote["quote"] . '.</h1>';
$output .= '<p>' . $quote["attribution"] . '</p>';
return $output;
}
And I cant see anything random that the function is doing. You are just iterating through the array:
foreach($quotes as $quote_id => $quote) {
echo get_random_quote( $quote);
}
According to http://php.net/manual/en/function.array-rand.php:
array_rand() Picks one or more random entries out of an array, and
returns the key (or keys) of the random entries.
So I guess $quote[$random_quote] should return your element, you can use it like:
$random_quote = array_rand($quotes);
echo get_random_quote($quote[$random_quote]);

PHP Unset acting like a Reference

I am having trouble understanding why PHP is unsetting my children property for both objects even when I create a copy.
When I assign $singleNode = $node it shouldn't remove the singleNode child because I'm not passing a reference, but it's behaving that way.
Can anyone clear this up for me?
You can run this in PHP CLI to see what I mean
<?php
$node = new stdClass();
$node->title = 'Test';
$node->children = [1,2,3,4,5];
// Does the node have children?
if (property_exists($node, 'children')) {
echo '$node has children' . PHP_EOL;
} else {
echo '$node NOT has children' . PHP_EOL;
}
// Assign node to a new variable, and remove children
$singleNode = $node;
if (property_exists($singleNode, 'children')) {
echo '$singleNode removed children' . PHP_EOL;
unset($singleNode->children);
}
// Does the node have children?
if (property_exists($node, 'children')) {
echo '$node has children' . PHP_EOL;
} else {
echo '$node NOT has children' . PHP_EOL;
}
I found I can do this:
$singleNode = clone $node
Is that the right way to do this? Why does this happen? No matter what I assign the variable to, the variable is referencing the same item in memory?
You are having just one object. To get a second object you would have to create a clone. Technically $singleNode = $node is copying the oject handle which still refers to the same object.
See
http://php.net/manual/en/language.oop5.cloning.php and http://php.net/manual/en/language.oop5.references.php

How to introduce white space in following?

The following snippet of PHP code creates $desc alright, but I like it to introduce two (2) blank spaces between every dpItemFeatureList found as it goes through its iteration.
I can't seem to garner exactly what or where to add a snippet to do this?
function get_description($asin){
$url = 'http://www.amazon.com/gp/aw/d/' . $asin . '?d=f&pd=1';
$data = request_data($url);
$desc = '';
if ($data) {
$dom = new DOMDocument();
#$dom->loadHTML($data);
$xpath = new DOMXPath($dom);
if (preg_match('#dpItemFeaturesList#',$data)){
$k = $xpath->query('//ul[#class="dpItemFeaturesList"]');
foreach ($k as $c => $tot) {
$desc .= $tot->nodeValue;
}
}
}
return $desc;
Looking at the code you have shared here and consequently having a look at the data that you are processing (a sample of which I have pasted here) you actually want to collect the text within the <li> child elements of the <ul class="dpItemFeaturesList"> node.
In your original code snippet your XPath is as follows:
'//ul[#class="dpItemFeaturesList"]'
This will only select the <ul> element and not the child elements. Consequently when you try to do a $tot->nodeValue it will concatenate all the text within all it's child nodes without spaces (ah ha, the real reason why you want spaces in the first place).
To fix this we should do two things:
Select the <li> nodes within the appropriate node. Change the XPath to //ul[#class="dpItemFeaturesList"]/li.
In the foreach loop concatenate 2 non-breakable spaces (because this is HTML) to the $desc variable.
Here $c is the array index.
function get_description($asin){
$url = 'http://www.amazon.com/gp/aw/d/' . $asin . '?d=f&pd=1';
$data = request_data($url);
$desc = '';
if ($data) {
$dom = new DOMDocument();
#$dom->loadHTML($data);
$xpath = new DOMXPath($dom);
if (preg_match('#dpItemFeaturesList#',$data)){
$k = $xpath->query('//ul[#class="dpItemFeaturesList"]/li');
foreach ($k as $c => $tot) {
if ($c > 0) {
$desc .= " ";
}
$desc .= $tot->nodeValue;
}
}
}
return $desc;
}
We check for $c > 0 so that you will not get extra spaces after the last node in the loop.
P.S.: Unrelated to your original question. The code for which you shared a link has an undefined variable $timestamp in $date = date("format", $timestamp); on line 116.
Since you're appending everything to desc, try something like
$desc .= $tot->nodeValue;
$desc .= "<br />"
try that:
$desc .= $tot->nodeValue.' ';
and trim($desc) after the loop to avoid two spaces at the end.
or, alternatively create an array:
$desc = array();
//....
$desc[] = $tot->nodeValue;
and return implode(' ', $desc)
If you need that between each one, you need to add in front on each iteration but the first:
$k = $xpath->query('//ul[#class="dpItemFeaturesList"]');
foreach ($k as $c => $tot) {
$c && $desc .= ' '; # all but first
$desc .= $tot->nodeValue;
}
This is an expression which saves you an if but it works similar. Maybe a bit of taste so sure, an if can do it as well:
$k = $xpath->query('//ul[#class="dpItemFeaturesList"]');
foreach ($k as $c => $tot) {
if($c) $desc .= ' '; # all but first
$desc .= $tot->nodeValue;
}
This works because every integer number but zero is true in PHP.
See the demo.

Checking if an index in a multidimensional array is an array

The code:
$row['text'] = 'http://t.co/iBSiZZD4 and http://t.co/1rG3oNmc and http://t.co/HGFjwqHI and http://t.co/8UldEAVt';
if(preg_match_all('|http:\/\/t.co\/.{1,8}|i',$row['text'],$matches)){
foreach($matches[0] as $value){
$headers = get_headers($value,1);
if(is_array($headers['Location'])){
$headers['Location'] = $headers['Location'][0];
}
$row['text'] = preg_replace('|http:\/\/t.co\/.{1,8}|i', '' . $headers['Location'] . '',$row['text']);
}
}
This is related to get_headers(). Sometimes get_headers($url,1) returns an array with a location index key like so: [Location]=>Array([0]=>url1 [1]=>url2). I basically want to make [Location] equal to [Location][0] if [Location][0] exists. However, the above code doesn't seem to accomplish that task. I've also tried array_key_exists() and isset() but neither solved the problem. Thoughts?
Don't try to replace on the fly. First get all the values, and then do the replace in one batch (using two arrays as the $search and $replace parameters).
<?php
$replace = array();
$row = array('text' => 'http://t.co/iBSiZZD4 and http://t.co/1rG3oNmc and http://t.co/HGFjwqHI and http://t.co/8UldEAVt');
if (preg_match_all('|http:\/\/t.co\/.{1,8}|i', $row['text'], $search)) {
foreach ($search[0] as $value) {
$headers = get_headers($value, 1);
if (is_array($headers['Location'])) {
$headers['Location'] = $headers['Location'][0];
}
$replace[] = "<a href='{$headers["Location"]}'>{$headers["Location"]}</a>";
}
$row['text'] = str_replace($search[0], $replace, $row['text']);
echo $row["text"];
}
P.S. - Next time, please tell us the context of your problem, tell us you "are making a service that resolves shortened URLs", don't let me figure that out from your code alone.

Need some help with XML parsing

The XML feed is located at: http://xml.betclick.com/odds_fr.xml
I need a php loop to echo the name of the match, the hour, and the bets options and the odds links.
The function will select and display ONLY the matchs of the day with streaming="1" and the bets type "Ftb_Mr3".
I'm new to xpath and simplexml.
Thanks in advance.
So far I have:
<?php
$xml_str = file_get_contents("http://xml.betclick.com/odds_fr.xml");
$xml = simplexml_load_string($xml_str);
// need xpath magic
$xml->xpath();
// display
?>
Xpath is pretty simple once you get the hang of it
you basically want to get every match tag with a certain attribute
//match[#streaming=1]
will work pefectly, it gets every match tag from underneath the parent tag with the attribute streaming equal to 1
And i just realised you also want matches with a bets type of "Ftb_Mr3"
//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]
This will return the bet node though, we want the match, which we know is the grandparent
//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..
the two dots work like they do in file paths, and gets the match.
now to work this into your sample just change the final bit to
// need xpath magic
$nodes = $xml->xpath('//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..');
foreach($nodes as $node) {
echo $node['name'].'<br/>';
}
to print all the match names.
I don't know how to work xpath really, but if you want to 'loop it', this should get you started:
<?php
$xml = simplexml_load_file("odds_fr.xml");
foreach ($xml->children() as $child)
{
foreach ($child->children() as $child2)
{
foreach ($child2->children() as $child3)
{
foreach($child3->attributes() as $a => $b)
{
echo $a,'="',$b,"\"</br>";
}
}
}
}
?>
That gets you to the 'match' tag which has the 'streaming' attribute. I don't really know what 'matches of the day' are, either, but...
It's basically right out of the w3c reference:
http://www.w3schools.com/PHP/php_ref_simplexml.asp
I am using this on a project. Scraping Beclic odds with:
<?php
$match_csv = fopen('matches.csv', 'w');
$bet_csv = fopen('bets.csv', 'w');
$xml = simplexml_load_file('http://xml.cdn.betclic.com/odds_en.xml');
$bookmaker = 'Betclick';
foreach ($xml as $sport) {
$sport_name = $sport->attributes()->name;
foreach ($sport as $event) {
$event_name = $event->attributes()->name;
foreach ($event as $match) {
$match_name = $match->attributes()->name;
$match_id = $match->attributes()->id;
$match_start_date_str = str_replace('T', ' ', $match->attributes()->start_date);
$match_start_date = strtotime($match_start_date_str);
if (!empty($match->attributes()->live_id)) {
$match_is_live = 1;
} else {
$match_is_live = 0;
}
if ($match->attributes()->streaming == 1) {
$match_is_running = 1;
} else {
$match_is_running = 0;
}
$match_row = $match_id . ',' . $bookmaker . ',' . $sport_name . ',' . $event_name . ',' . $match_name . ',' . $match_start_date . ',' . $match_is_live . ',' . $match_is_running;
fputcsv($match_csv, explode(',', $match_row));
foreach ($match as $bets) {
foreach ($bets as $bet) {
$bet_name = $bet->attributes()->name;
foreach ($bet as $choice) {
// team numbers are surrounded by %, we strip them
$choice_name = str_replace('%', '', $choice->attributes()->name);
// get the float value of odss
$odd = (float)$choice->attributes()->odd;
// concat the row to be put to csv file
$bet_row = $match_id . ',' . $bet_name . ',' . $choice_name . ',' . $odd;
fputcsv($bet_csv, explode(',', $bet_row));
}
}
}
}
}
}
fclose($match_csv);
fclose($bet_csv);
?>
Then loading the csv files into mysql. Running it once a minute, works great so far.

Categories