I have an xml document that contains spaces and equal signs in the node names. I'm trying to use SimpleXML to extract the data from those nodes but it returns blank no matter what I try.
A sample of the xml document
<code><away>
<radio>url.here</radio>
<live bitrate="1">url.here</live>
<live bitrate="0">url.here</live>
</away></code>
I have tried using bothecho "<td>".$node->away->{'live bitrate="1"'}."</td>";
echo "<td>".$node->away->{'live'}->{'bitrate="1"'}."</td>";
Here is a function I use to convert the SimpleXML object to an array:
public function simpleXMLToArray($xml,
$flattenValues=true,
$flattenAttributes = true,
$flattenChildren=true,
$valueKey='#value',
$attributesKey='#attributes',
$childrenKey='#children'){
$return = array();
if(!($xml instanceof SimpleXMLElement)){return $return;}
$name = $xml->getName();
$_value = trim((string)$xml);
if(strlen($_value)==0){$_value = null;};
if($_value!==null){
if(!$flattenValues){$return[$valueKey] = $_value;}
else{$return = $_value;}
}
$children = array();
$first = true;
foreach($xml->children() as $elementName => $child){
$value = $this->simpleXMLToArray($child, $flattenValues, $flattenAttributes, $flattenChildren, $valueKey, $attributesKey, $childrenKey);
if(isset($children[$elementName])){
if($first){
$temp = $children[$elementName];
unset($children[$elementName]);
$children[$elementName][] = $temp;
$first=false;
}
$children[$elementName][] = $value;
}
else{
$children[$elementName] = $value;
}
}
if(count($children)>0){
if(!$flattenChildren){$return[$childrenKey] = $children;}
else{$return = array_merge($return,$children);}
}
$attributes = array();
foreach($xml->attributes() as $name=>$value){
$attributes[$name] = trim($value);
}
if(count($attributes)>0){
if(!$flattenAttributes){$return[$attributesKey] = $attributes;}
else{$return = array_merge($return, $attributes);}
}
return $return;
}
Related
Excuse my English, please.
I use Rollingcurl to crawl various pages.
Rollingcurl: https://github.com/LionsAd/rolling-curl
My class:
<?php
class Imdb
{
private $release;
public function __construct()
{
$this->release = "";
}
// SEARCH
public static function most_popular($response, $info)
{
$doc = new DOMDocument();
libxml_use_internal_errors(true); //disable libxml errors
if (!empty($response)) {
//if any html is actually returned
$doc->loadHTML($response);
libxml_clear_errors(); //remove errors for yucky html
$xpath = new DOMXPath($doc);
//get all the h2's with an id
$row = $xpath->query("//div[contains(#class, 'lister-item-image') and contains(#class, 'float-left')]/a/#href");
$nexts = $xpath->query("//a[contains(#class, 'lister-page-next') and contains(#class, 'next-page')]");
$names = $xpath->query('//img[#class="loadlate"]');
// NEXT URL - ONE TIME
$Count = 0;
$next_url = "";
foreach ($nexts as $next) {
$Count++;
if ($Count == 1) {
/*echo "Next URL: " . $next->getAttribute('href') . "<br/>";*/
$next_link = $next->getAttribute('href');
}
}
// RELEASE NAME
$rls_name = "";
foreach ($names as $name) {
$rls_name .= $name->getAttribute('alt');
}
// IMDB TT0000000 RLEASE
if ($row->length > 0) {
$link = "";
foreach ($row as $row) {
$tt_info .= #get_match('/tt\\d{7}/is', $doc->saveHtml($row), 0);
}
}
}
$array = array(
$next_link,
$rls_name,
$tt_info,
);
return ($array);
}
}
Output/Return:
$array = array(
$next_link,
$rls_name,
$tt_info,
);
return ($array);
Call:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
function get_match($regex, $content, $pos = 1)
{
/* do your job */
preg_match($regex, $content, $matches);
/* return our result */
return $matches[intval($pos)];
}
require "RollingCurl.php";
require "imdb_class.php";
$imdb = new Imdb;
if (isset($_GET['action']) || isset($_POST['action'])) {
$action = (isset($_GET['action'])) ? $_GET['action'] : $_POST['action'];
} else {
$action = "";
}
echo " 2222<br /><br />";
if ($action == "most_popular") {
$popular = '&num_votes=1000,&production_status=released&groups=top_1000&sort=moviemeter,asc&count=40&start=1';
if (isset($_GET['date'])) {
$link = "https://www.imdb.com/search/title?title_type=feature,tv_movie&release_date=,".$_GET['date'].$popular;
} else {
$link = "https://www.imdb.com/search/title?title_type=feature,tv_movie&release_date=,2018".$popular;
}
$urls = array($link);
$rc = new RollingCurl([$imdb, 'most_popular']); //[$imdb, 'most_popular']
$rc->window_size = 20;
foreach ($urls as $url) {
$request = new RollingCurlRequest($url);
$rc->add($request);
}
$stream = $rc->execute();
}
If I output everything as "echo" in the class, everything is also displayed. However, I want to call everything individually.
If I now try to output it like this, it doesn't work.
$stream[0]
$stream[1]
$stream[3]
Does anyone have any idea how this might work?
Thank you very much in advance.
RollingCurl doesn't do anything with the return value of the callback, and doesn't return it to the caller. $rc->execute() just returns true when there's a callback function. If you want to save anything, you need to do it in the callback function itself.
You should make most_popular a non-static function, and give it a property $results that you initialize to [] in the constructor.. Then it can do:
$this->results[] = $array;
After you do
$rc->execute();
you can do:
foreach ($imdb->results as $result) {
echo "Release name: $result[1]<br>TT Info: $result[2]<br>";
}
It would be better if you put the data you extracted from the document in arrays rather than concatenated strings, e.g.
$this->$rls_names = [];
foreach ($names as $name) {
$this->$rls_names[] = $name->getAttribute('alt');
}
$this->$tt_infos = [];
foreach ($rows as $row) {
$this->$tt_infos[] = #get_match('/tt\\d{7}/is', $doc->saveHtml($row), 0);
}
$this->next_link = $next[0]->getAttribute('href'); // no need for a loop to get the first element of an array
I am trying to create constructor which creates an multidimensional array. My result should be like this:-
Checkout my array $result_array
For now I have error: Illegal offset type. Note that I have als use __toString() becose I work on xml data.
class Property {
public $xmlClass;
public $elemClass = '';
public $first_array = array();
public $result_array = array();
public $data = '';
public $data2 = '';
public function __construct($xml, $elem) {
$this->xmlClass = $xml;
$this->elemClass = $elem;
foreach ($xml->xpath('//*[#baza]') as $val) {
$this->first_array[] = $val;
foreach ($val->ksiazka as $value) {
$data = $value->$elem->__toString();
$this->result_array[$this->first_array][] = $data;
}
}
}
public function getResult() {
return $this->result_array;
}
}
$result_autor = new Property($xml, 'autor');
$autor = $result_autor->getResult();
You need to change your two foreach() like below:-
foreach($xml->xpath('//*[#baza]') as $val) {
//$this->first_array[] = $val; not needed
foreach($val->ksiazka as $key=> $value){ //check $key here
$data = $value->$elem->__toString();
$this->result_array[$key][] = $data; // add $key hear
}
}
If the above not worked then check this too:-
foreach($xml->xpath('//*[#baza]') as $key=> $val) { //check $key here
//$this->first_array[] = $val; not needed
foreach($val->ksiazka as $value){
$data = $value->$elem->__toString();
$this->result_array[$key][] = $data; // add $key hear
}
}
What I need is,
but what i got is,
How can I remove "#attributes" from the result.
The below code works for me:
// Cleans up ugly JSON data by removing #attributes tag
function cleanup_json ($ugly_json) {
if (is_object($ugly_json)) {
$nice_json = new stdClass();
foreach ($ugly_json as $attr => $value) {
if ($attr == '#attributes') {
foreach ($value as $xattr => $xvalue) {
$nice_json->$xattr = $xvalue;
}
} else {
$nice_json->$attr = cleanup_json($value);
}
}
return $nice_json;
} else if (is_array($ugly_json)) {
$nice_json = array();
foreach ($ugly_json as $n => $e) {
$nice_json[$n] = cleanup_json($e);
}
return $nice_json;
} else {
return $ugly_json;
}
}
// Convert XML to JSON
function convert_to_json ($xml_string) {
$xml = simplexml_load_string($xml_string);
$ugly_json = json_decode(json_encode($xml));
$nice_json = cleanup_json($ugly_json);
return json_encode($nice_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
Try this. It may work for you.
$xml = simplexml_load_string($string);
$json = json_encode($xml, true);
I am trying to decode a collection of json files to a mysql database and return the decoded values to a datatable for presentation. I have one table called ec2_instances, and want to send to that table an array of values which are located at cfi configuration which works fine. but have now added a new column called aws account id which is on object rather than an array I have updated the model to include the new column but I am struggling
<?php
function from_camel_case($input)
{
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
$ret = $matches[0];
foreach ($ret as &$match)
{
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
}
return implode('_', $ret);
}
$resource_types = array();
$resource_types['AWS::EC2::Instance'] = 'EC2Instance';
$resource_types['AWS::EC2::NetworkInterface'] = 'EC2NetworkInterface';
$resource_types['AWS::EC2::VPC'] = 'VPC';
$resource_types['AWS::EC2::Volume'] = 'Volume';
$resource_types['AWS::EC2::SecurityGroup'] = 'EC2SecurityGroup';
$resource_types['AWS::EC2::Subnet'] = 'Subnet';
$resource_types['AWS::EC2::RouteTable'] = 'RouteTable';
$resource_types['AWS::EC2::EIP'] = 'EIP';
$resource_types['AWS::EC2::NetworkAcl'] = 'NetworkAcl';
$resource_types['AWS::EC2::InternetGateway'] = 'InternetGateway';
$accounts = DB::table('aws_account')->get();
$account_id = array($accounts);
$account_id_exists = array_add($account_id, 'key', 'value');
foreach(glob('../app/views/*.json') as $filename)
{
//echo $filename;
$data = file_get_contents($filename);
if($data!=null)
{
$decoded=json_decode($data,true);
if(isset($decoded["Message"]))
{
//echo "found message<br>";
$message= json_decode($decoded["Message"]);
if(isset($message->configurationItem))
{
// echo"found cfi<br>";
$insert_array = array();
$cfi = $message->configurationItem;
switch ($cfi->configurationItemStatus)
{
case "ResourceDiscovered":
//echo"found Resource Discovered<br>";
if (array_key_exists($cfi->resourceType,$resource_types))
{
//var_dump($cfi->resourceType);
$resource = new $resource_types[$cfi->resourceType];
foreach ($cfi->configuration as $key => $value)
{
if (in_array($key,$resource->fields))
{
$insert_array[from_camel_case($key)] = $value;
}
}
if (array_key_exists($cfi->awsAccountId,$resource_types))
{
$resource = new $resource_types[$cfi->awsAccountId];
foreach ($cfi->awsAccountId as $key => $value)
{
if (in_array($key,$resource->fields))
{
$insert_array[from_camel_case($key)] = $value;
}
}
$resource->populate($insert_array);
if (!$resource->checkExists())
{
$resource->save();
I'm using drupal's NAT module and need to get the nid from the term id.
Here's what I tried:
foreach ( (array)nat_get_nids($termid) as $natid ) {
$NatName = $natid->name;
}
print $natid;
This does not work.
Node auto term's get nid function is like this:
function nat_get_nids($tids, $get_nodes = FALSE) {
static $nid_cache = NULL;
static $node_cache = NULL;
$return = array();
// Keep processing to a minimum for empty tid arrays.
if (!empty($tids)) {
// Sort tid array to ensure that the cache_string never suffers from order
// issues.
sort($tids);
$cache_string = implode('+', $tids);
if ($get_nodes) {
if (isset($node_cache[$cache_string])) {
return $node_cache[$cache_string];
}
elseif (isset($nid_cache[$cache_string])) {
// If the nid cache stores the same string, node_load() each nid and
// return them.
$return = array();
foreach (array_keys($nid_cache[$cache_string]) as $nid) {
$return[$nid] = node_load($nid);
}
$node_cache[$cache_string] = $return;
return $return;
}
}
else {
if (isset($nid_cache[$cache_string])) {
return $nid_cache[$cache_string];
}
elseif (isset($node_cache[$cache_string])) {
// If the node cache stores the same string, retrieve only the nids and
// return them.
foreach ($node_cache[$cache_string] as $nid => $node) {
$return[$nid] = $node->name;
}
// Cache extracted results.
$nid_cache[$cache_string] = $return;
return $return;
}
}
// Results have not been cached.
$tids = implode(', ', $tids);
$result = db_query("SELECT n.nid, t.name FROM {nat} n INNER JOIN {term_data} t USING (tid) WHERE n.tid IN (". db_placeholders($tids) .")", $tids);
while ($node = db_fetch_object($result)) {
if ($get_nodes) {
$return[$node->nid] = node_load($node->nid);
}
else {
$return[$node->nid] = $node->name;
}
}
if ($get_nodes) {
$node_cache[$cache_string] = $return;
}
else {
$nid_cache[$cache_string] = $return;
}
}
return $return;
}
Thanks in advance!
Edit: Try based on the first answer:
foreach (nat_get_nids($termid) as $nid => $node_name) {
}
print $node_name;
It looks like nat_get_nids is returning an associative array, so your for loop should look like
foreach (nat_get_nids($termid) as $nid => $node_name) {
...
}
$nids = nat_get_nids(array($termid));