I'm somewhat new to php and I'm trying to loop through my XML file in order to extract data and display it in HTML. I know how to do the display to HTML part, but I'm a little confused for what to do for the XML part.
Here is a sample file of what I am trying to do (you can picture it as a categorized list of movies where groupType would be genre):
<mainGroup>
<groupHeading type="heading">This is a sample heading</groupHeading>
<group type="groupType1">
<title>Title1</title>
<date when="0001"></date>
</group>
<group type="groupType1">
<title>Title2</title>
<date when="0002"></date>
</group>
<group type="groupType2">
<title>Title3</title>
<date when="0003"></date>
</group>
</mainGroup>
... There are more mainGroups with differet group types etc
Basically, I will have 10+ mainGroups, with many different groups inside of it, so I need a way to loop through these using php. The main problem is the fact that I need someway to "getElementBy Type()", but that does not exist.
If anything is confusing, I can elaborate more, I'm still a novice to php so I hope I can do this.
real simple --> use PHP's simplexml ---> live demo: http://codepad.viper-7.com/i4MRGI
$xmlstr = '<mainGroup>
<groupHeading type="heading">This is a sample heading</groupHeading>
<group type="groupType1">
<title>Title1</title>
<date when="0001"></date>
</group>
<group type="groupType1">
<title>Title2</title>
<date when="0002"></date>
</group>
<group type="groupType2">
<title>Title3</title>
<date when="0003"></date>
</group>
</mainGroup>';
// create simplexml object
$xml=simplexml_load_string($xmlstr);
// loop through all <groupheading>, we use an xpath-query...
foreach ($xml->xpath("//groupHeading") as $gh) {
echo($gh),'<br />';
}
// now the titles under every group with groupType1...
foreach ($xml->xpath("//group[#type='groupType1']/title") as $gt1) {
echo $gt1,'<br />';
}
EDIT: echo title of each groupHeading, then titles of child-nodes if grouptype=1:
---> see new demo: http://codepad.viper-7.com/eMuyr5
foreach ($xml->groupHeading as $gh) {
echo($gh),'<br />';
foreach ($gh->xpath("//group[#type='groupType1']/title") as $gt1) {
echo $gt1,'<br />';
}
}
You could use PHP DOM
If you wanted to search groups for a particular type and then get the results you could do something like this:
EDIT - $string would be your XML. If you needed to load it from a file you can do
$string = file_get_contents('/path/to/your/file');
$dom = new DOMDocument;
$dom->loadXML($string);
$searchtype = "groupType1";
$results = array();
$groups = $dom->getElementsByTagName('group');
foreach( $groups as $g ) {
if( $g->getAttribute('type') == $searchtype ) {
$results[] = array(
'title' =>$g->getElementsByTagName('title')->item(0)->nodeValue,
'date' =>$g->getElementsByTagName('date')->item(0)->getAttribute('when')
);
}
}
print_r($results);
Related
I have an XML structure like this
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
<county>
</location>
</company>
</companies>
I am trying to get specific info from the elements into PHP variables.
To get "vatno" I use:
$vatno = $xmlObject->item($i)->getElementsByTagName('vatno')->item(0)->childNodes->item(0)->nodeValue;
But what if I need the county name for example?
I cannot use getElementsByTagName('text') as it would get the company name also using the element name "text".
You may be better off using SimpleXML, you can then access the various components in a more intuitive way.
The example above would be something like...
$data = <<< XML
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
</county>
</location>
</company>
</companies>
XML;
$xml = simplexml_load_string($data);
foreach ( $xml->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
So each sub element is accessed using ->.
If you wanted to stick with what you already had, you should be able to use...
$countyName = $xmlObject->item($i)->getElementsByTagName('text')->item(1)
->nodeValue;
Using item(1) will fetch the second instance of the <text> elements, so this assumes that the name will have this value as well.
It works with SimpleXML if I use
$xml = simplexml_load_string($data);
foreach ( $xml->companies->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
i know a few about php, so sorry for the question:
i have this file xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<alert>
<status> </status>
<nothing> </nothing>
<info>
<area>
</area>
</info>
<info>
<area>
</area>
</info>
<info>
<area>
</area>
</info>
</alert>
i must do a for loop and inside a "foreach" for each
The problem is that i'm not sure what is a way to know how many times i had to repeat a for loop. Because in this file xml (that is an example) i don't know how many are
Is good if:
$url = "pathfile";
$xml = simplexml_load_file($url);
$numvulcani = count($xml->alert->info); // is good ?
for ($i = 0; $i <= $numvulcani; $i++) {
foreach ($xml->alert->info[$i] as $entry) {
$area = $entry->area;
}
}
is true ?
sorry for bad english
You need to use SimpleXMLElement::count function for this — It counts the children of an element.
<?php
$xml = <<<EOF
<people>
<person name="Person 1">
<child/>
<child/>
<child/>
</person>
<person name="Person 2">
<child/>
<child/>
<child/>
<child/>
<child/>
</person>
</people>
EOF;
$elem = new SimpleXMLElement($xml);
foreach ($elem as $person) {
printf("%s has got %d children.\n", $person['name'], $person->count());
}
?>
The output will be as follows :
Person 1 has got 3 children.
Person 2 has got 5 children.
Also take a look at this link : xml count using php
Try replacing foreach ($xml->alert->info[$i] as $entry) with:
foreach ($xml->alert->info[$i] as $j => $entry)
The current item index will be $j
You're perhaps overcomplicating this a bit as it's new to you.
First of all, you don't need to reference the alert root element like $xml->alert because the SimpleXMLElement named by the variable $xml represents that document element already.
And second, you don't need to count here, you can just foreach directly:
foreach ($xml->info as $info) {
echo ' * ', $info->asXML(), "\n";
}
This iterates over those three info elements that are children of the alert element.
I recommend the Basic SimpleXML usage guide in the PHP manual for a good start with SimpleXML.
This question already has answers here:
SimpleXML: Selecting Elements Which Have A Certain Attribute Value
(2 answers)
Closed 8 years ago.
I have the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<result name="response">
<doc>
<str name="index">2</str>
<str name="summary">A summary</str>
<str name="title">A Title</str>
<arr name="media">
<str>/image/123.jpg</str>
</arr>
</doc>
</result>
I'm grabbing the contents and creating a SimpleXMLElement in PHP. I need to be able to grab the contents of a specific tag based on it's name value. E.g. If I was trying to echo out "A summary" something like this:
echo $xmlObj->doc->str['name']->summary;
I know that doesn't work but what will? I've looked at a lot of similar questions but haven't found one with this specific problem. Cheers.
Use XPath (http://www.w3schools.com/php/func_simplexml_xpath.asp)
<?php
$string = <<<XML
<a>
<b>
<c>text</c>
<c>stuff</c>
</b>
<d>
<c>code</c>
</d>
</a>
XML;
$xml = new SimpleXMLElement($string);
/* Search for <a><b><c> */
$result = $xml->xpath('/a/b/c');
while(list( , $node) = each($result)) {
echo '/a/b/c: ',$node,"\n";
}
/* Relative paths also work... */
$result = $xml->xpath('b/c');
while(list( , $node) = each($result)) {
echo 'b/c: ',$node,"\n";
}
?>
The solution to the problem is as follows:
$summary = $xmlObj->xpath('doc/str[#name="summary"]');
if($summary) {
echo $summary[0];
}
It involves using XPath as a4arpan pointed out.
First of all, thanks for the time reading this :)
I need help reordering an XML feed. I've tried many things and researched, but can't come up with a solution.
<xml>
<group>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
</result>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
</result>
</group>
<group region=top>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
</result>
</group>
<group type=bottom>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
<moreinfo>
<result>
<title>Title</title>
</result>
<result>
<title>Title</title>
</result>
</moreinfo>
</result>
</group>
</xml>
What I am trying to do is re-order the XML feed to display each node inside 'result'. However, I need the feed reordered so the 'result' from 'group region=top' is at the top, then the results from 'group', then results from 'group region=bottom'.
You might notice there is another 'result' tag nested inside of a 'result' tag in 'group region=bottom', which is causing most of the issues. The way I envision a solution to this is with the following pseudo-code:
$books = $doc->getElementsByTagName( "result" );
foreach( $books as $book )
{
if (parent_attribute = top){
$toptitle = $book->getElementsByTagName( "title" );
$toptitle = $toptitle->item(0)->nodeValue;
$topnew[] =array("title"=>$toptitle);
}
if (parent_attribute = null){
$middletitle = $book->getElementsByTagName( "title" );
$middletitle = $middletitle->item(0)->nodeValue;
$middlenew[] =array("title"=>$middletitle);
}
if (parent_attribute = bottom){
$bottomtitle = $book->getElementsByTagName( "title" );
$bottomtitle = $bottomtitle->item(0)->nodeValue;
if (parent_element = moreinfo){
$moretitle = $book->getElementsByTagName( "title" );
$moretitle = $moretitle->item(0)->nodeValue;
}
$bottomnew[] =array("title"=>$bottomtitle, "more"=>$moretitle);
}
}
The XML you posted is invalid and not consistent, as attribute values have to be enclosed in "", for consistency see my comment above.
Here's how I do it using simplexml and xpath, it can be easily adapted to DOM as well.
$xml = simplexml_load_string($x); // assuming XML in $x
$regions['top'] = $xml->xpath("group[#region='top']/result");
$regions['middle'] = $xml->xpath("group[not(#*)]/result"); // <group> with no attribute
$regions['bottom'] = $xml->xpath("group[#region='bottom']/result");
// output:
foreach ($regions as $region => $results) {
echo "$region:<br />";
foreach ($results as $result) {
echo $result->title . "<br />";
if (count($result->moreinfo) > 0)
foreach ($result->moreinfo->result as $subresult)
echo "____$subresult->title<br />";
} // foreach $results
} // foreach $regions
see it working: http://codepad.viper-7.com/5adWxC
I have this XML code :
<?xml version="1.0"?>
<Days>
<day value="1">
<Imsaak>04:59</Imsaak>
<Fajr>05:09</Fajr>
<Sunrise>06:23</Sunrise>
<Dhuhr>12:39</Dhuhr>
<Asr>16:12</Asr>
<Sunset>18:55</Sunset>
<Maghrib>19:10</Maghrib>
<Isha>20:04</Isha>
</day>
<day value="2">
<Imsaak>04:58</Imsaak>
<Fajr>05:08</Fajr>
<Sunrise>06:22</Sunrise>
<Dhuhr>12:39</Dhuhr>
<Asr>16:12</Asr>
<Sunset>18:56</Sunset>
<Maghrib>19:11</Maghrib>
<Isha>20:05</Isha>
</day>
</Days>
and I want to select <day> node depending on the attribute value
I am using SimpleXMLElement class but I don't how to select with arrtibute value.
how I can do that??
EDIT: my code :
include 'days.xml';
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml->day as $day) {
// process data
}
from php manual SimpleXMLElement::attributes (little bit edited)
Considering this data:
<?xml version="1.0" encoding="utf-8"?>
<data>
<item ID="30001">
<Company>Navarro Corp.</Company>
</item>
<item ID="30002">
<Company>Performant Systems</Company>
</item>
<item ID="30003">
<Company>Digital Showcase</Company>
</item>
</data>
Example of listing both the ID Attribute and Company Element values:
<?php
$xmlObject = new SimpleXMLElement($xmlstring);
foreach ($xmlObject->children() as $node) {
$arr = $node->attributes(); // returns an array
if(in_array("30002", $arr)){ // search the value of an attribute
print ("Company=".$node->Company);
}
//depending of your needs, you could use a switch / case instead of use an if
}
?>
$xml = new SimpleXMLElement($xmlStr)
$xml->day[0]->attribute()->value;//will echo out 1
of course you can loop through all of the day like this:
foreach($sml->day as $day){
$day->attribute()->value; //will trace out 1 and then 2
}