xml problem with php - 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

Related

Getting XML feed and outputting

Hello I would like to get the XML feed for my site:
http://buildworx-mc.com/forum/syndication.php?fid=4&limit=5
And display them in this format:
<ul>
<li> Topic 1 </li>
<li> Topic 2 </li>
<li> Topic 3 </li>
</ul>
I guess the best/easiest method to do this is using PHP, so how can I get the XML and display them in list items? It'll be displayed on http://example.com while the feed is http://example.com/forum
I tried the other answers from other questions asked, but nothing seems to work for me.
You may need to use the command "file_get_contents" to get a copy of the remote file in order to parse it using PHP. I'm surprised this step is necessary since you say you want to display items from your forum on your site so you might be able to set the 'feed' variable to the direct link, assuming everything is under the same domain. If not, this ought to work.
$feed = file_get_contents('http://buildworx-mc.com/forum/syndication.php?fid=4&limit=5');
$xml = simplexml_load_string($feed);
$items = $xml->channel->item;
foreach($items as $item) {
$title = $item->title;
$link = $item->link;
$pubDate = $item->pubDate;
$description = $item->description;
echo $title . "<br>";
// continue to format as an unordered list
}
You may try SimpleXML once you are using PHP:
http://php.net/manual/en/book.simplexml.php
Just load that URL, so that it will convert the XML file into an object:
http://www.php.net/manual/en/function.simplexml-load-file.php
Then you may iterate the objects with a simple "foreach", to generate that HTML list you want.
For testing purposes, and to understand how the object is created, you may use "print_r()".

PHP: Parse XML with SimpleXML

I'm having issues attempting to parse an XML file I'm pulling in from another site with SimpleXML. I need to display the rent for certain properties. However, I only want to display the rent for certain properties. I've never seen an XML file structured in this manner: http://dl.dropbox.com/u/1925679/example.xml
First, how would I parse through this file based on
Property->PropertyID->MITS:Identification->MITS:PrimaryID
Then, echo out the Property->Floorplan->MarketRent(Min and Max) based on an ID?
TIA!!!!
// get all properties
$properties = $xml->xpath('//Property');
// get document namesapces in prefix => uri format
$namespaces = $xml->getNamespaces(true);
foreach($properies as $property)
{
// get namespaced nodes
$identification = $property->PropertyID->children($namespaces['MITS']);
$id = $identification->children($namespaces['MITS'])->PrimaryID;
// do your check id is an expected value or whatever and if so then...
foreach($property->Floorplan as $floorplan){
{
echo $floorplan->MarketRent['min'];
echo $floorplan->MarketRent['max'];
}
}
You could probably com up with an xpath query to ONLY select properties with a given id or set of ids straight away so then you would only have to loop over them and invoke the floorplan loop but ill leave that to your investigation :-) I will say though if you go that route, you will need to register the namespaces with xpath i think. Pretty sure thats not automatic.

How do you rename a tag in SimpleXML through a DOM object?

The problem seems straightforward, but I'm having trouble getting access to the tag name of a SimpleXMLElement.
Let's say I have the follow XML structure:
<xml>
<oldName>Stuff</oldName>
</xml>
And I want it to look like this:
<xml>
<newName>Stuff</newName>
</xml>
Is this possible to do without doing a copy of the entire object?
I've started to realize the errors of the ways I am approaching this problem. It seems that I need to convert my SimpleXMLElement into a DOM object. Upon doing so I find it very hard to manipulate the object in the way I want (apparently renaming tags in a DOM isn't easy to do for a reason).
So... I am able to import my SimpleXMLElement into a DOM object with the import, but I am finding it difficult to do the clone.
Is the following the right thinking behind cloning a DOM object or am I still way off:
$old = $dom->getElementsByTagName('old')->item(0); // The tag is unique in my case
$new = $dom->createElement('new');
/* ... some recursive logic to copy attributes and children of the $old node ... */
$old->ownerDocument->appendChild($new);
$new->ownerDocument->removeChild($old);
Here's what's probably the simplest way to copy a node's children and attributes without using XSLT:
function clonishNode(DOMNode $oldNode, $newName, $newNS = null)
{
if (isset($newNS))
{
$newNode = $oldNode->ownerDocument->createElementNS($newNS, $newName);
}
else
{
$newNode = $oldNode->ownerDocument->createElement($newName);
}
foreach ($oldNode->attributes as $attr)
{
$newNode->appendChild($attr->cloneNode());
}
foreach ($oldNode->childNodes as $child)
{
$newNode->appendChild($child->cloneNode(true));
}
$oldNode->parentNode->replaceChild($newNode, $oldNode);
}
Which you can use this way:
$dom = new DOMDocument;
$dom->loadXML('<foo><bar x="1" y="2">x<baz/>y<quux/>z</bar></foo>');
$oldNode = $dom->getElementsByTagName('bar')->item(0);
clonishNode($oldNode, 'BXR');
// Same but with a new namespace
//clonishNode($oldNode, 'newns:BXR', 'http://newns');
die($dom->saveXML());
It will replace the old node with a clone with a new name.
Attention though, this is a copy of the original node's content. If you had any variable pointing to the old nodes, they are now invalid.
Maybe easier way would be to replace the tags using preg functions for the XML source string?
Cleaner way
Create XSLT XML transformation file and use xsl PHP extension to translate it.
For this see this answer – Rename nodes with XSLT.
PHP code part could be found in PHP documentation.
Is this possible to do without doing a copy of the entire object?
Nope, it's not.
You could do it in XSLT via an "identity transform". If you search around for "rename tag" and "identity transform" you should find a few examples, assuming XSLT is an option.
Rather late but I came up with the fallowing solution by replacing the hell out of the xml. I thought this might help some people as I couldnt find any good solution on the web without copying all children.
function RenameNode(SimpleXMLElement $Entire_XML, SimpleXMLElement $Node, $New_Title)
{
$Full_XML = $Entire_XML->asXML();
$Old_Title = $Node->getName();
$XML_String = $Node->asXML();
$Replaced = preg_replace("/$Old_Title/", $New_Title, $XML_String, 1);
if (count($Node->children())>0)
{
$Replaced = strrev(
preg_replace(
strrev("/$Old_Title/"),
strrev($New_Title),
strrev($Replaced),
1
)
);
}
$Full_XML = str_replace($XML_String, $Replaced, $Full_XML);
return simplexml_load_string($Full_XML);
}
Sidenote: This function can be simplified but I quickly rewrote this function in order to post this here. The original function I use looks a little bit different

nested xml document in Simplexml document

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>";
}

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