nested xml document in Simplexml document - php

I have a problem when using simplexml to read a xml document that I am getting back from a webservice call.
Reading the data is fine however one node called UserArea contains a nested XMLdocument which contains namespaces.
From this question on SO I've looked at how to deal with child nodes. However when I call the node that has this nested XML in it I get null back.
The data looks like this:
<UserArea>
<rm:EngineVersion>4.2.0.62</rm:EngineVersion>
<rm:DocumentFormat>305</rm:DocumentFormat>
<rm:Industry>AUT</rm:Industry>
<rm:Department>GEN</rm:Department>
<rm:HighestDegree year="2004" major="COMPUTER PROGRAMMING">BACHELORS</rm:HighestDegree>
<rm:ExperienceSummary>
<rm:Experience>
<rm:ExperienceKind>Summary</rm:ExperienceKind>
<rm:Years>11</rm:Years>
<rm:Detail>A total of 11 years of work experience.</rm:Detail>
</rm:Experience>
<rm:Experience>
<rm:ExperienceKind>HighestIndustry</rm:ExperienceKind>
<rm:Years>5</rm:Years>
<rm:Industry>AUT</rm:Industry>
<rm:Detail>Highest industry-related experience is 5 years in automotive </rm:Detail>
</rm:Experience>
</rm:ExperienceSummary>
</UserArea>
I am out of ideas because the code:
foreach($myObject->UserArea->children as $userAreaXML){
foreach($userAreaXML->ExperianceSummary as $summary){
echo $summary->Detail;
}
}
just doesn't work.

You might want to read http://www.sitepoint.com/blogs/2005/10/20/simplexml-and-namespaces/ .. Couldn't be explained much clearer.

This code will print out the details
$experiences = $myObject->ExperienceSummary->Experience;
foreach($experiences as $experience) {
echo $experience->Detail . "<br>";
}

Related

Parsing the Google Reader export

I am attempting to use SimpleXML to parse the xml file that is produced from the Google Reader export.
File example:
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<head>
<title>TheTechBox subscriptions in Google Reader</title>
</head>
<body>
<outline text="Engadget RSS Feed" title="Engadget RSS Feed"
type="rss" xmlUrl="http://www.engadget.com/rss.xml" htmlUrl="http://www.engadget.com"/>
<outline text="xkcd.com" title="xkcd.com" type="rss"
xmlUrl="http://xkcd.com/rss.xml" htmlUrl="http://xkcd.com/"/>
</body>
</opml>
This is what I have tried so far, the user uploads the file to this form and the form needs to loop through and extract the data.
<?php
if ($_FILES["file"]["error"] > 0)
{
echo "Error: " . $_FILES["file"]["error"] . "<br>";
}
else
{
$import = new SimpleXMLElement($_FILES["file"]["name"]);
foreach($import->opml->body->outline[0] as $feed){
echo $feed["title"];
}
}
?>
Right now chrome produces a server error which indicates something is very wrong on the page, the file uploads OK so it appears to be the simpleXML part.
I am planning to do something more complex with the data later, I am currently trying to get it just to echo the data on the page (for demo purposes).
Any feedback would be greatly appreciated.
Here is the working code in the end
$import = simplexml_load_file($_FILES["file"]["tmp_name"]);
foreach($import->body->outline as $feed){
echo $feed["title"];
}
This will need adding to to parse all of the data but this works.
You've fallen into a classic trap when using SimpleXML: the first object you get when parsing a file or string is not an abstract "document" object, but the parent node. In this case, the parent node is <opml> ... </opml>, so $import in your sample code is that <opml> node. In other words, rather than $import->opml->body you just need to say $import->body.
There's another bug in your loop as well, which is that you are asking for the first <outline> element (->outline[0]) when what you want is to be looping over all of the elements (foreach( $whatever->outline as $feed )).

Scraping content from a file

I have a file that contains many of these
<sync start="14400">
<p class="ENCC">
Removed
</p>
</sync>
and I would like to turn them into this format
<p begin="00:00:33.3" end="00:00:35.8">Removed</p>
I would like to get the data inside start="" and the data inside and loop through until I have all of them on the page.
I have been trying to do this for a few hours now but could do with a point in the right direction. Any help or guidance would be greatly appreciated. Thank you
Edit: also please ignore the start/behin formatting I already have the code to do that
If what you're after is a simple way to parse XML, look into phpQuery (very accessible if you're used to jQuery). The code would look something like (untested):
$start_values = array ();
$content_values = array ();
$doc = phpQuery::newDocumentXML ($xml);
foreach (pq ('sync') as $node)
{
$start_values[] = pq ($node)->attr ('start');
$content_values[] = pq ($node)->find ('p')->html ();
}
$start_values would then be an array with the respective values for the start-attribute and $content_values would be an array with the respective content of the actual tag.
UPDATED
I noticed that I didn't take the p-node under sync into consideration earlier. The find ('p') part should take care of that.

check if nodes exist in xml with php

I am reading some xml which has come back from amazon's api. Most times amazon provides a list of similar products in their xml, but not always. If there are similar products I echo our them as a set of links. The problem is that not all products have similar products in the xml. I would like to change this code so that it checks if there are similar products nodes first and then if there are it continues to render them out as links as below but if not it just does nothing. The code below currently gives the following error message if there are no similar products in the xml:
Warning: Invalid argument supplied for foreach() in /public_html/product.php on line 26
if there are no similar product nodes in the xml returned from amazon.
Thanks in advance.
foreach ($result->Items->Item->SimilarProducts->SimilarProduct as $SimilarProduct) {
echo "<li>" . $SimilarProduct->Title . "</li/> \n";
}
You can do this test before the foreach (note the if):
if ($result->Items->Item->SimilarProducts->SimilarProduct !== null)
{
foreach ($result->Items->Item->SimilarProducts->SimilarProduct as $SimilarProduct) {
echo "<li>" . $SimilarProduct->Title . "</li/> \n";
}
}
Anyway this test works if there're no errors or null vars before the 'SimilarProduct' (for example if 'Item' is null the script will fail anyway).
Note: I suggest you to not do this kind of things, I mean this repeated access to vars (that is ->...->...->) because you will have a low control on the situation and on what's happening.

xml problem with php

I'm trying to use an xml file and retrieve all links from it. so far I have:
$xmlHeadline = $xml->channel[0]->item[3]->link;
print($xmlHeadline);
This works ok to print the single headline link for item[3] in the xml. But as you can see it is 2 levels deep. Then next one will be at channel[0]->item[4]->link. There is no channel 1, just channel[0].
All the examples on the internet only deal with 1 level deep. They all used a foreach loop, but I am not sure if that can be used here...
How can I cycle through all item's in the xml and echo all links?
Try
foreach ($xml->channel[0]->item as $item) {
echo $item->link;
}
or
foreach ($xml->xpath('/channel/item/link') as $link) {
echo $link;
}
I think you want a DOM parser, that will allow you to load the xml as a structured hierarchy and then use a function like getElementById http://php.net/manual/en/domdocument.getelementbyid.php to parse the xml and get the specific items you want at any depth.
If you provide the structure of the xml file I may be able to help with the specific use of a DOM function.
$str = '<channels><channel>
<item><link>google.com</link></item>
<item><link>google.com.cn</link></item>
<item><link>google.com.sg</link></item>
<item><link>google.com.my</link></item>
</channel></channels>';
$xml = simplexml_load_string($str);
$objs = $xml->xpath('//channel/item/link');
PS: Please include some example of your xml

Updating the XML file using PHP script

I'm making an interface-website to update a concert-list on a band-website.
The list is stored as an XML file an has this structure :
I already wrote a script that enables me to add a new gig to the list, this was relatively easy...
Now I want to write a script that enables me to edit a certain gig in the list.
Every Gig is Unique because of the first attribute : "id" .
I want to use this reference to edit the other attributes in that Node.
My PHP is very poor, so I hope someone could put me on the good foot here...
My PHP script :
Well i dunno what your XML structure looks like but:
<gig id="someid">
<venue></venue>
<day></day>
<month></month>
<year></year>
</gig>
$xml = new SimpleXmlElement('gig.xml',null, true);
$gig = $xml->xpath('//gig[#id="'.$_POST['id'].'"]');
$gig->venue = $_POST['venue'];
$gig->month = $_POST['month'];
// etc..
$xml->asXml('gig.xml)'; // save back to file
now if instead all these data points are attributes you can use $gig->attributes()->venue to access it.
There is no need for the loop really unless you are doing multiple updates with one post - you can get at any specific record via an XPAth query. SimpleXML is also a lot lighter and a lot easier to use for this type of thing than DOMDOcument - especially as you arent using the feature of DOMDocument.
You'll want to load the xml file in a domdocument with
<?
$xml = new DOMDocument();
$xml->load("xmlfile.xml");
//find the tags that you want to update
$tags = $xml->getElementsByTagName("GIG");
//find the tag with the id you want to update
foreach ($tags as $tag) {
if($tag->getAttribute("id") == $id) { //found the tag, now update the attribute
$tag->setAttribute("[attributeName]", "[attributeValue]");
}
}
//save the xml
$xml->save();
?>
code is untested, but it's a general idea

Categories