I have a Web Service in PHP that reads a XML file of albums, and simply returns it as a string to my ASP.NET web form. Now, the sending and receiving is fine.
The problem is that now I want to parse this data in order to save the new albums and other information (such as Genre, Artist, and Songs) to my database attached to my ASP.NET web site, and it's giving me a headache.
Here's the code of the Web Service client:
protected void btnGetAlbums_Click(object sender, EventArgs e)
{
phpPublisher.albums albums = new albums();
string result = albums.getAlbums();
if (String.IsNullOrEmpty(result))
{
txtResult.Text = "No albums found";
}
else
{
// parse XML
var xml = XElement.Parse(result);
var albumList = xml.Descendants("Albums")
.Elements("Album");
if (albumList.Count() > 0)
{
txtResult.Text = "Has at least 1 album!";
}
}
}
This is just very 'demo'-ish code for now, I haven't even tackled the database inserting and all that because I can't even parse the data.
If I output the xml variable in my txtResult textbox, it shows:
<Albums> <Album> <AlbumTitle>Stripped</AlbumTitle> <AlbumArtist>Christina Aguilera</AlbumArtist> <AlbumGenre>Pop</AlbumGenre> <AlbumSongs> <AlbumSong>Beautiful</AlbumSong> </AlbumSongs> </Album></Albums>
All in one line, which is incredibly frustrating. I don't know if it can even parse the data like this...what I'd like to do in the PHP side is just send a XML data object that ASP.NET could read. Is this possible?
Here's what my PHP web service function looks like (it returns a string).
function getAlbums() {
$dataSource = "albums.xml";
if(file_exists($dataSource)) {
$xml = simplexml_load_file($dataSource);
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
return $dom->saveXML();
} else {
return null;
}
}
Any help is appreciated. Thank you.
P.S. When I execute albumList.Count(), it returns 0, which means the list contains no elements, so there's a parsing error somewhere.
try
var albumList = xml.Elements("Album");
Related
I have a flash application that posts xml to a php page which validates it against an xsd schema. I'm trying to do the same thing but from an html page. I'm using XMLHttpRequest or with jquery's ajax call but I keep running around the same issues. "document has no document" or the "access-control-allow-origin' header issue. I can fix one but not the other.
My PHP page looks like this:
function libxml_append_errors() {
global $returnXML, $errors;
$e = libxml_get_errors();
foreach ($e as $error) {
$en = $returnXML->createElement("error", trim($error->message));
$en->setAttribute('line',$error->line);
$errors->appendChild($en);
}
libxml_clear_errors();
}
libxml_use_internal_errors(true);
$xml = new DOMDocument();
$contents = $HTTP_RAW_POST_DATA;
$xml->loadXML($contents);
$returnXML = new DOMDocument("1.0", "utf-8");
$rootNode = $returnXML->createElement("result");
$returnXML->appendChild($rootNode);
$errors = $returnXML->createElement("errors");
if (!$xml->schemaValidate('muffin_dumplings.xsd'))
{
libxml_append_errors();
}
$rootNode->appendChild($errors);
echo $returnXML->saveXML();
Either way I'm looking to get xml back with any validation errors or a simple empty error xml node same as I do with flash.
If anyone cares, here is the answer. When you post to PHP, have the right headers, and are using ajax you need to pass a content type. Then it works.
I am writing some code for an IRC bot written in php and running on the linux cli. I'm having a little trouble with my code to retrieve a websites title tag and display it using DOMDocument NodeList. Basically, on websites with two or more tags (and you would be surprised how many there actually are...) I want to process for only the first title tag. As you can see from the code below (which is working fine for processing one, or more tags) there is a foreach block where it iterates through each title tag.
public function onReceivedData($data) {
// loop through each message token
foreach ($data["message"] as $token) {
// if the token starts with www, add http file handle
if (strcmp(substr($token, 0, 4), "www.") == 0) {
$token = "http://" . $token;
}
// validate token as a URL
if (filter_var($token, FILTER_VALIDATE_URL)) {
// create timeout stream context
$theContext['http']['timeout'] = 3;
$context = stream_context_create($theContext);
// get contents of url
if ($file = file_get_contents($token, false, $context)) {
// instantiate a new DOMDocument object
$dom = new DOMDocument;
// load the html into the DOMDocument obj
#$dom->loadHTML($file);
// retrieve the title from the DOM node
// if assignment is valid then...
if ($title = $dom->getElementsByTagName("title")) {
// send a message to the channel
foreach ($title as $theTitle) {
$this->privmsg($data["target"], $theTitle->nodeValue);
}
}
} else {
// notify of failure
$this->privmsg($data["target"], "Site could not be reached");
}
}
}
}
What I'd prefer, is to somehow limit it to only processing the first title tag. I'm aware that I can just wrap an if statement around it with a variable so it only echos one time, but I'm more looking at using a "for" statement to process a single iteration. However, when I do this, I can't access the title attribute with $title->nodeValue; it says it's undefined, and only when i use the foreach $title as $theTitle can I access the values. I've tried $title[0]->nodeValue and $title->nodeValue(0) to retrieve the first title from the list, but unfortunately to no avail. A bit stumped and a quick google didn't turn up a lot.
Any help would be greatly appreciated! Cheers, and I'll keep looking too.
You can solve this with XPath:
$dom = new DOMDocument();
#$dom->loadHTML($file);
$xpath = new DOMXPath($dom);
$title = $xpath->query('//title')->item(0)->nodeValue;
Try something like this:
$title->item(0)->nodeValue;
http://www.php.net/manual/en/class.domnodelist.php
I want to scrape the contents of a page, well really just a single div from that page, and display it to the user inside of a small div on a webpage. I just need a piece of info from a carfax page that needs user credentials so I can't post the exact code but I tried using google.com and have the same problem so the solution should cross over.
Right now I've tried this:
$webPage = file_get_contents('http://www.google.com');
$doc = new DOMDocument();
$doc->loadHTML($webPage);
$div = $doc->getElementById('lga');//this is the id to the div holding the image above the textbox
//echo $webPage;//this displays www.google.com minus the image. I imagine because of the file path
//var_dump($div);//this display "object(DOMElement)#2 (0) { }" and I'm not sure what that means
//echo $div;//this has a server error
I'm also looking at simple_html_dom.php trying to figure that out.
You can use this:
/**
* Downloads a web page from $url, selects the the element by $id
* and returns it's xml string representation.
*/
function getElementByIdAsString($url, $id, $pretty = true) {
$doc = new DOMDocument();
#$doc->loadHTMLFile($url);
if(!$doc) {
throw new Exception("Failed to load $url");
}
// Obtain the element
$element = $doc->getElementById($id);
if(!$element) {
throw new Exception("An element with id $id was not found");
}
if($pretty) {
$doc->formatOutput = true;
}
// Return the string representation of the element
return $doc->saveXML($element);
}
// call it:
echo getElementByIdAsString('http://www.google.com', 'lga');
I am creating a metasearch engine using Yandex API. Yandex gives result in XML format. So we need to traverse the XML response inorder to get the different fields like URL,title ,description etc.
The XML response by Yandex is as follows:
http://pastebin.com/kAVAVri9
This is how i have implemented: paste
$dom5 = new DOMDocument();
if ($dom5->loadXML($site_results)) {
$results = $dom5->getElementsByTagName("response");
$results1 = $results->getElementsByTagName("results");
$results2 = $results1->getElementsByTagName("group");
$totals["yandex"] = 1000;
foreach ($results1 as $link) {
$url = $link->getElementsByTagName("doc")->item(2)->nodeValue;
;
$url = str_replace('http://', '', $url);
if (substr($url, -1, 1) == '/') {
$url = substr($url, 0, strlen($url) - 1);
}
$search_results[$i]["url"] = $url;
$title = $link->getElementsByTagName("doc")->item(4)->nodeValue;
$search_results[$i]["title"] = $title;
$test = $link->getElementsByTagName("doc");
$test1 = $test->getElementsByTagName("title");
$desc = $test1->getElementsByTagName("headline")->item(0)->nodeValue;
$search_results[$i]["desc"] = $desc;
$search_results[$i]["engine"] = 'yandex';
$search_results[$i]["position"] = $i + 1;
$i++;
}
}
I am new to php. Please forgive me if i have done some stupid mistake. I am unable to retrive the results through my implementation. Please help me find the mistake and get the necessary fields from xml response.
Thank you!
The method getElementsByTagName() returns a DOMNodeList:
$results = $dom5->getElementsByTagName("response");
The DOMNodeList does not have a method called getElementsByTagName(), but you call it:
$results1 = $results->getElementsByTagName("results");
Therefore the fatal error is triggered: Whenever in PHP you execute a method on an object that does not exist, you will get a fatal error and your script stops working.
Do not call undefined object methods and you should be fine.
Apart from these basics, for parsing such XML documents I normally suggest SimpleXML, however this XML file is a little specific therfore I suggest to extend from SimpleXML and add the features you likely need to use, in part from regular expressions as well as from DOMDocument.
One concept you should know about when parsing these XML files is Xpath. For example to access the elements you had that many problems with above, you can write the path literally:
/*/response/results/grouping/group
In PHP with SimpleXML this looks like:
$url = 'http://pastebin.com/raw.php?i=kAVAVri9';
$xml = simplexml_load_file($url, 'MySimpleXML');
foreach ($xml->xpath('/*/response/results/grouping/group') as $link) {
# ... operate on $link
}
A larger example:
$url = 'http://pastebin.com/raw.php?i=kAVAVri9';
$url = '../data/yandex.xml';
$xml = simplexml_load_file($url, 'MySimpleXML');
foreach ($xml->xpath('/*/response/results/grouping/group') as $link) {
$url = $link->doc->url->str()->preg('~^https?://(.*?)/*$~u', '$1');
$title = $link->doc->title->text();
$headline = $link->doc->headline->text();
printf("<%s> %s\n%s\n\n", $url, $title, wordwrap($headline));
}
And it's exemplary output:
<www.facebook.com> " Facebook" - a social networking service
Allows users to find and communicate with friends, classmates and
colleagues, share thoughts, photos and videos, and join various groups.
<en.wikipedia.org/wiki/Facebook> Facebook - Wikipedia, the free encyclopedia
Facebook is a social networking service launched in February 2004, owned
and operated by Facebook, Inc. As of September 2012, Facebook has over one
billion active users, more than half of them using Facebook on a mobile
device.
<mashable.com/category/facebook> Facebook
...
The PHP code example above needs some more code to work because it extends from SimpleXML for the ease of use. This is done with the following code:
class MySimpleXML extends SimpleXMLElement
{
public function text()
{
$string = null === $this[0] ? ''
: (dom_import_simplexml($this)->textContent);
return $this->str($string)->normlaizeWS();
}
public function str($string = null)
{
return new MyString($string ?: $this);
}
}
class MyString
{
private $string;
public function __construct($string)
{
$this->string = $string;
}
public function preg($pattern, $replacement)
{
return new self(preg_replace($pattern, $replacement, $this));
}
public function normlaizeWS()
{
return $this->preg('~\s+~', ' ');
}
public function __toString()
{
return (string) $this->string;
}
}
This might be all a little bit much for the beginning, checkout the PHP manual for SimpleXML and the other functions used in the code-example.
I have values inside an XMLList in Actionscript. Need to send these values to the DB and update it.
My actionscript code is as follows:
public static function saveUserPermList():void {
var ht:HTTPService = new HTTPService();
ht.url = Config.getServerURL();
ht.method = URLRequestMethod.POST;
//ht.resultFormat = "e4x";
ht.contentType = "text/xml";
ht.request["action"] = "saveUserPermListXML";
ht.request["pdata"] = Application.application.userPermListModel.toString();
ht.addEventListener(ResultEvent.RESULT,AdminUserList.saveUserPermListResult);
ht.send();
}
public static function saveUserPermListResult(e:ResultEvent):void {
trace(e);
}
How can I send the XMLList data to PHP? Should I add a toString() to it?
Also what should be the contentType in Flex.
How can I catch this inside PHP, pl let me know, trying to use, this way,
if($user -> isAllowedAccess()) {
header("Content-type:text/xml");
$postedData = $_POST["pdata"];
// $xmldoc = simplexml_load_string($POST['pdata']);
// echo($xmldoc);
}
No luck. Pl let me know.
The method property of HTTPService should probably be "POST", and the contentType for the request itself should probably be "application/x-www-form-urlencoded".
On the PHP side, $_POST["pdata"] would then be a string containing XML markup. You could either save that in a database directly, or first parse it into XML (via SimpleXML or DOMDocument) and do something with the contained data.
PS: I've just found this answer that seems to shed some light on the internal behavior of the HTTPService class.