SimpleXML IF condition - php

I have an XML document that will either return a URL or an error code. If it returns an error code I'd like to redirect the page to an error image. I can get SimpleXML to return the URL, but I am not sure how to write a condition if the error returns. If anyone has any suggestions, that'd be great! This is what I have right now:
<?php
error_reporting(0);
$url = 'http://radiocast.co/art/api1/key=KeyHere&album=' . htmlspecialchars($_GET["album"]) . '&artist=' . htmlspecialchars($_GET["artist"]) . '';
$xml = simplexml_load_file($url);
$img = $xml->xpath('//image[#size="large"]');
$large = (string)$img[0];
header("Location:".urldecode($large));
?>
This is what the XML document returns if it cannot be found:
<?xml version="1.0" encoding="utf-8"?>
<lookup status="failed">
<error code="3">Art not found</error></lookup>

How about checking for the error node in your XML, and if you find it then handling the various errors? If you don't find it you can continue with your normal logic.
if (isset($xml->error)) {
switch ($xml->error['code']) {
case '3':
// not found stuff here
break;
// other error codes here
}
} else {
// success logic here
$img = $xml->xpath('//image[#size="large"]');
$large = (string) $img[0];
header("Location: " . urldecode($large));
}

Related

PHP XMLReader 400 Bad Request

I'm trying to get started using XMLReader to process large XML files, but I am getting a strange HTTP 400 Bad Request when I try to run the following code:
<?php
$reader = new XMLReader ();
$reader->open ( "testfile.xml" );
while ( $reader->read () ) {
switch ($reader->nodeType) {
case (XMLREADER::ELEMENT) :
echo "<" . $reader->name . "> <br>";
break;
case (XMLREADER::TEXT) :
if ($reader->hasValue) {
echo $reader->value . "<br>";
}
break;
}
}
$reader->close();
?>
I have also tried it this way and get the same 400 Bad Request error:
<?php
$reader = new XMLReader ();
$reader->open ( "testfile.xml" );
while ( $reader->read() ) {
switch ($reader->nodeType) {
case (XMLREADER::ELEMENT) :
echo "<" . $reader->name . "> <br>";
$reader->read();
if (($reader->nodeType == XMLREADER::TEXT) && $reader->hasValue) {
echo $reader->value . "<br>";
}
break;
}
}
$reader->close();
?>
In both cases, the error goes away when I comment out echo reader->value ."<br>";. Apache error logs aren't showing anything. Also, in spite of the 400 error, the page is created and rendered as expected with the elements and text values (i.e., the code appears to work, it just gives an HTTP error as well).
It is also worth noting that it seems to work without error on a small, simple test XML file with only one root and one child element with text. It's only on the larger more complicated XML file that I'm actually intending to process that I'm getting the error.
Thanks in advance for any help!
FYI in case anyone else runs into this, I found out I needed to use htmlspecialchars() to escape the value. I changed:
echo $reader->value . "<br>";
to
echo htmlspecialchars($reader->value, ENT_XML1, 'UTF-8') . "<br>";
Guess there must be some html in the XML that the browser was trying to interpret causing the 400 error.

How do I process XML string in order using PHP

I have an XML file which contains text with some very simple layout constructs:
<?xml version='1.0'?>
<page>
<section>
<header>Header</header>
<par>Some paragraph</par>
<par>Another paragraph with <emph>formatting</emph></par>
</section>
</page>
In PHP then I read this file using SimpleXML (Note that I intentionally strip other tags!):
$page = file_get_contents("page.xml");
if ($page) {
$stripped = strip_tags($page, "<?xml><page><section><header><par><emph>");
$xml = new SimpleXMLElement($stripped);
}
Now I would like to iterate over the XML elements and print them in order as HTML for my website. The final result should be the following snippet:
<h1>Header</h1>
<p>Some paragraph
<p>Another paragraph with <i>formatting</i>
I've noodled through SimpleXML and XPath and tried to figure out how I can iterate over the XML tree in order so that I can digest the original XML file into HTML output. I can produce a somewhat desired result but the <emph></emph> is just gone; how do I descent further into the tree? My code so far:
foreach ($xml->section as $s) {
echo "<h1>" . $s->header . "</h1>";
foreach ($s->par as $p) {
echo "<p>" . $p;
// Do some magic here to ensure <emph> tags are recognized and responded to properly.
}
}
Any hints and pointers are appreciated! Thanks :-)
Well, without an answer I just had to noodle myself :-) So here is what I did and it worked out just fine.
Turned out that the SimpleXML thing didn't cut it, so I used the XMLReader:
$xml = new XMLReader();
Then I manually parsed the XML string, jumped from element to element and acted upon each of them:
if ($xml->xml($stripped)) { // $stripped here is a string that's been validated (see below).
while (false !== $xml->read()) {
$t = $xml->nodeType;
if ($t === XMLReader::ELEMENT) {
$n = $xml->name;
switch ($n) {
case "page":
case "section":
// Nothing to echo here.
break;
case "header":
// Handle attributes here
echo "<h1>";
break;
case "par":
echo "<p> ";
break;
case "emph";
echo "<i>"; // This can also open a <span> for more flexibility later.
break;
default:
// Nothing should arrive here.
echo "Gah!"
}
}
else if ($t === XMLReader::END_ELEMENT) {
... // Close the opened tags here.
}
else if ($t === XMLReader::TEXT) {
$s = $xml->readString();
echo $s;
}
else {
// Everything else are comments or white spaces.
}
}
}
You get the drift. I basically had to bounce through the XML structure myself and, dependent on the element type, handle attributes and nodes of elements manually.
In fact, this is a two-step process. What you see here assumes a valid XML document. I also have a validator that runs before the above code, and which makes sure that the correct elements are nested properly and that the given XML is "well formed" as per my own definitions of nesting, attributes, whatnot. The validator operates after the exact same principle.
Hope this helps.

If 1st XML is empty then load a different one

Im getting the contents of an xml feed and printing the titles on my web page with php:
$url = 'http://site.com/feed';
$xml = simplexml_load_file($url);
foreach($xml->ART as $ART) {
echo $ART->TITLE;
}
I want to be able to set a backup, so if the first xml isn't found a different one is loaded instead.
I tried the following code but it doesn't work. If the feed isnt found the page shows 'XML Parsing Error:' which i guess isnt the same as nothing.
if ($url != '') {
$xml = simplexml_load_file($url);
} else {
//Here I would load a different xml file.
}
What should I do? Should I write conditional php to check if the first url contains a TITLE, and if not load the 2nd url?
Thanks
UPDATE
This messed up my whole page:
$first_url = 'http://site.com/feed1';
$second_url = 'http://site.com/feed2';
// if URL wrappers is enabled
if (is_url($first_url))
{
// parse first url
$xml = simplexml_load_file($first_url);
}
else
{
// parse second url
$xml = simplexml_load_file($second_url);
}
foreach($xml->ART as $ART) {
echo $ART->TITLE;
}
See simplexml_load_file
Returns an object of class SimpleXMLElement with properties containing the data held within the XML document. On errors, it will return FALSE.
Example from php.net
<?php
// The file test.xml contains an XML document with a root element
// and at least an element /[root]/title.
if (file_exists('test.xml')) {
$xml = simplexml_load_file('test.xml');
print_r($xml);
} else {
exit('Failed to open test.xml.');
}
?>
EDIT: you can do
$url = 'http://site.com/feed';
if( $xml = simplexml_load_file($url) ) {
foreach($xml->ART as $ART) {
echo $ART->TITLE;
}
} else {
//parsing new url
}
function parse_xml($url)
{
// your code
}
try
{
parse_xml($first_url);
}
catch (Exception $e)
{
parse_xml($second_url);
}
Alternatively, you can do a check if the URL return XML before proceed to parsing :-
// if URL wrappers is enabled
if (is_url($first_url))
{
// parse first url
$xml = simplexml_load_file($first_url);
}
else
{
// parse second url
$xml = simplexml_load_file($second_url);
}
Think ive got it working with:
$url = 'site.com/feed1';
$xml = simplexml_load_file($url);
if ($xml == null) {
$url = 'site.com/feed2';
$xml = simplexml_load_file($url);
}
foreach($xml->ART as $ART) {
echo $ART->TITLE;
}

simplexml load on google weather api prooblem

Hi I have been having problems with the google weather api having errors Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 2: parser error ....
I tried to use the script of the main author(thinking it was my edited script) but still I am having this errors I tried 2
//komunitasweb.com/2009/09/showing-the-weather-with-php-and-google-weather-api/
and
//tips4php.net/2010/07/local-weather-with-php-and-google-weather/
The weird part is sometimes it fixes itself then goes back again to the error I have been using it for months now without any problem, this just happened yesterday. Also the demo page of the authors are working but I have the same exact code any help please.
this is my site http://j2sdesign.com/weather/widgetlive1.php
#Mike I added your code
<?
$xml = file_get_contents('http://www.google.com/ig/api?weather=jakarta'); if (! simplexml_load_string($xml)) { file_put_contents('malformed.xml', $xml); }
$xml = simplexml_load_file('http://www.google.com/ig/api?weather=jakarta');
$information = $xml->xpath("/xml_api_reply/weather/forecast_information");
$current = $xml->xpath("/xml_api_reply/weather/current_conditions");
$forecast_list = $xml->xpath("/xml_api_reply/weather/forecast_conditions");
?>
and made a list of the error but I can't seem to see the error cause it's been fixing itself then after sometime goes back again to the error
here is the content of the file
<?php include_once('simple_html_dom.php'); // create doctype $dom = new DOMDocument("1.0");
// display document in browser as plain text
// for readability purposes //header("Content-Type: text/plain");
// create root element
$xmlProducts = $dom->createElement("products");
$dom->appendChild($xmlProducts);
$pages = array( 'http://myshop.com/small_houses.html', 'http://myshop.com/medium_houses.html', 'http://myshop.com/large_houses.html' ) foreach($pages as $page) { $product = array(); $source = file_get_html($page); foreach($source->find('img') as $src) { if (strpos($src->src,"http://myshop.com") === false) { $product['image'] = "http://myshop.com/$src->src"; } } foreach($source->find('p[class*=imAlign_left]') as $description) { $product['description'] = $description->innertext; } foreach($source->find('span[class*=fc3]') as $title) { $product['title'] = $title->innertext; } //debug perposes! echo "Current Page: " . $page . "\n"; print_r($product); echo "\n\n\n"; //Clear seperator } ?>
When simplexml_load_string() fails you need to store the data you're trying to load somewhere for review. Examining the data is the first step to diagnose what it causing the error.
$xml = file_get_contents('http://example.com/file.xml');
if (!simplexml_load_string($xml)) {
file_put_contents('malformed.xml', $xml);
}

PHP returning page error on simplexml print_r

The problem is only happening with one file when I try to do a DocumentDOM/SimpleXML method, so it seems like the issue is with that file. No clue what it could be.
If I do the following:
$file = "test1.html";
$dom = DOMDocument::loadHTMLFile($file);
$xml = simplexml_import_dom($dom);
print_r($xml);
in Chrome, I get a "Page Unavailable" error. In Firefox, I get nothing.
If I do the same thing but to a "test2.html", I get a print out as expected.
If I try the same thing but doing it this way:
$file = "test1.html";
$data = file_get_contents($file)
$dom = DOMDocument::loadHTML($data);
$xml = simplexml_import_dom($dom);
print_r($xml);
I get the same issue.
If I comment out the print_r line, Chrome goes from the "Page Unavailable" to blank.
I changed the permissions to 777, in case that was an issue, no fix.
I tried simply echoing out the contents of the html, no problem at all.
Any clues as to why a) Chrome would do that, and b) why I'm not getting any usable results?
Update:
If I put in:
$file = "test1.html";
$dom = DOMDocument::loadHTMLFile($file);
if(!$dom) {
echo "No Load!";
}
else {
$xml = simplexml_import_dom($dom);
print_r($xml);
}
I get the same issue. If I put in:
$file = "test1.html";
$dom = DOMDocument::loadHTMLFile($file);
if(!$dom) {
echo "No Load!";
}
else {
echo "Load!";
}
I get the "Load!" output, meaning that the dom method shouldn't be the problem (?)
I'll try the same exact test with the simplexml.
Update2:
If I do this:
I get the same issue. If I put in:
$file = "test1.html";
$dom = DOMDocument::loadHTMLFile($file);
$xml = simplexml_import_dom($dom);
if(!$xml) {
echo "No Load!";
}
else {
echo "Load!";
}
I get "Load!" but if I do:
$file = "test1.html";
$dom = DOMDocument::loadHTMLFile($file);
$xml = simplexml_import_dom($dom);
if(!$xml) {
echo "No Load!";
}
else {
echo "Load!";
print_r($xml);
}
I get the error. I did finally notice that I had an option to view the error in Chrome:
Error 324 (net::ERR_EMPTY_RESPONSE): Unknown error.
The troublesome html file is 288Kb. Could that be the issue? If so, how would I adjust for that?
Last Update:
Very Odd. I can use methods and functions on the object (as simplexml or domdocument), so I can do things like xpath to delete or parse the html, etc. In some cases (small results) it can echo out results, but for big stuff (show all spans), it fails in the same way.
So, since the end result, I think will fit in these parameters, I SHOULD be okay (I guess).
But any real solution is very welcome.
Turn on error reporting: error_reporting(E_ALL); in the first line of your PHP code.
Check the memory limit of your PHP configuration: memory_limit in the respective php.ini
What's the difference between test1.html and test2.html? Perhaps test1.html is not well-formed.
DocumentDOM and/or SimpleXML may bail out if the document is malformed. Try something like:
$dom = DOMDocument::loadHTMLFile($file);
if (!$dom) {
echo 'Loading file failed';
exit;
}
$xml = simplexml_import_dom($dom);
if (!$xml) {
...
}
If creating the $dom worked, conversion to $xml should work as well, but make sure anyway.
Edit: As Gehrig said, make sure error reporting is on, that should make it obvious where the process fails.

Categories