Xml PHP Get attributes and its children value - php

XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<lessons>
<lesson level="1" course="2">
<name type="Dog" category="Animals">Dog name</name>
</lesson>
</lessons>
I want to get the values saved like this:
$type = "Dog";
$category = "Animals";
$name = "dog name";
This is what I've done:
foreach($xml->name as $name){
$type = $name['type'];
$category = $name['category'];
echo "Type: $type Category: $category<br>";
// AND TO get the text, haven't figuered it out yet.. <name ..="" ..="">text</name>
}
But it doesn't work. Don't get any errors neither any output. Any ideas?
EDIT:
OK. I changed foreach($xml->name as $name)
to foreach($xml->lesson->name as $name)
so I get the values of the attribute. But now I don't know how to get the value of the children.
I've tried this: $xml->lesson->children()
It prints children()
SOLVED: $text = $xml->lesson->children();
echo $text;
PROBLEM WAS: I'm using utf-8 in my other code but didn't change it.

Edit : this part related to a question typo. If you copied your xml directly from where you were editting it, then part of the problem might be that it is malformed. You have an opening <lessons> but you appear to wrongly try to close it with </lesson>.
Also, depending on your root node settings, ->name may or may not be a child of the $xml object. Can you post a var_dump() of it and get some clues?

I think, there is some problem in your xml.
-> You have to close lessons tag correctly.Because you have entered </lesson> (see last line) instead of </lessons>. If you start any tag, you should use the same tag name while closing..
you can use this code to extract values from your xml,
<?php
$xmlstring='<lessons>
<lesson level="1" course="2">
<name type="Dog" category="Animals">Dog name</name>
</lesson>
</lessons>';
$xml = simplexml_load_string($xmlstring);
$ATTRIBUTE=array();
$counter = 0;
foreach($xml->children() as $key=>$child)
{
$counter++;
$ATTRIBUTE[$counter]["type"]=$child->name->attributes()->type;
$ATTRIBUTE[$counter]["category"]=$child->name->attributes()->category;
$ATTRIBUTE[$counter]["value"]= $child->name;
}
echo "<pre>";
print_r($ATTRIBUTE);
?>
here you will get everything in array. So you can fetch based on your requirement.

Related

Check if child exists? - SimpleXML (PHP)

I have different XML files where I renamed for each XML file all individual tags, so that every XML file has the same tag name. That was easy because the function was customized for the XML file.
But instand of writing 7 new functions for each XML file now I want to check if a XML file has a specidifed child or not. Because if I want to say:
foreach ($items as $item) {
$node = dom_import_simplexml($item);
$title = $node->getElementsByTagName('title')->item(0)->textContent;
$price = $node->getElementsByTagName('price')->item(0)->textContent;
$url = $node->getElementsByTagName('url')->item(0)->textContent;
$publisher = $node->getElementsByTagName('publisher')->item(0)->textContent;
$category = $node->getElementsByTagName('category')->item(0)->textContent;
$platform = $node->getElementsByTagName('platform')->item(0)->textContent;
}
I get sometimes: PHP Notice: Trying to get property of non-object in ...
For example. Two different XML sheets. One contains publisher, category and platform, the other not:
XML 1:
<products>
<product>
<desc>This is a Test</desc>
<price>11.69</price>
<price_base>12.99</price_base>
<publisher>Stackoverflow</publisher>
<category>PHP</category>
</packshot>
<title>Check if child exists? - SimpleXML (PHP)</title>
<url>http://stackoverflow.com/questions/ask</url>
</product>
</products>
XML 2:
<products>
<product>
<image></image>
<title>Questions</title>
<price>23,90</price>
<url>google.de/url>
<platform>Stackoverflow</platform>
</product>
</products>
You see, sometimes one XML file contains publisher, category and platform but sometimes not. But it could also be that not every node of a XML file contains all attributes like in the first!
So I need to check for every node of a XML file individual if the node is containing publisher, category or/and platform.
How can I do that with SimpleXML?
I thought about switch case but at first I need to check which childs are contained in every node.
EDIT:
Maybe I found a solution. Is that a solution or not?
if($node->getElementsByTagName('platform')->item(0)){
echo $node->getElementsByTagName('platform')->item(0)->textContent . "\n";
}
Greetings and Thank You!
One way to rome... (working example)
$xml = "<products>
<product>
<desc>This is a Test</desc>
<price>11.69</price>
<price_base>12.99</price_base>
<publisher>Stackoverflow</publisher>
<category>PHP</category>
<title>Check if child exists? - SimpleXML (PHP)</title>
<url>http://stackoverflow.com/questions/ask</url>
</product>
</products>";
$xml = simplexml_load_string($xml);
#set fields to look for
foreach(['desc','title','price','publisher','category','platform','image','whatever'] as $path){
#get the first node
$result = $xml->xpath("product/{$path}[1]");
#validate and set
$coll[$path] = $result?(string)$result[0]:null;
#if you need here a local variable do (2 x $)
${$path} = $coll[$path];
}
#here i do array_filter() to remove all NULL entries
print_r(array_filter($coll));
#if local variables needed do
extract($coll);#this creates $desc, $price
Note </packshot> is an invalid node, removed here.
xpath syntax https://www.w3schools.com/xmL/xpath_syntax.asp
Firstly, you're over-complicating your code by switching from SimpleXML to DOM with dom_import_simplexml. The things you're doing with DOM can be done in much shorter code with SimpleXML.
Instead of this:
$node = dom_import_simplexml($item);
$title = $node->getElementsByTagName('title')->item(0)->textContent;
you can just use:
$title = (string)$item->title[0];
or even just:
$title = (string)$item->title;
To understand why this works, take a look at the SimpleXML examples in the manual.
Armed with that knowledge, you'll be amazed at how simple it is to see if a child exists or not:
if ( isset($item->title) ) {
$title = (string)$item->title;
} else {
echo "There is no title!";
}

Adding child to XML file using PHP

While adding child, this error is thrown :
Cannot add child. Parent is not a permanent member of the XML tree.
I cannot resolve this.
This is my code :
if($visited=='FIRST')
{
$xml=new SimpleXMLElement("<xml/>");
$topology=$xml->addChild("Topology_Configuration");
$flavor=$topology->addChild("Flavor");
$networks=$topology->addChild("Networks");
$vms=$topology->addChild("VMs");
$vnfs=$topology->addChild("VNFs");
$xml->asXML('saddening.xml');
}
else
{
$xml= simplexml_load_file('saddening.xml');
$Topology_Configuration = new SimpleXMLElement($xml->asXML());
$vmcount=$_POST['arguments']['vmcount'];
$flavor=$Topology_Configuration->Flavor;
$flavor_name=$flavor->addChild($_POST['arguments']['flavorName']);
$Topology_Configuration->asXML('saddening.xml');
}
When it is executed for the first time, the file is created(in if part). Otherwise else part is executed. It cannot add the child and is throwing the error in line :
$flavor_name=$flavor->addChild($_POST['arguments']['flavorNa‌​me']);. Please help!!
The XML from your first run results in an XML like this:
<?xml version="1.0"?>
<xml>
<Topology_Configuration>
<Flavor/>
<Networks/>
<VMs/><VNFs/>
</Topology_Configuration>
</xml>
So if you strip down the problem you can reproduce it with:
$Topology_Configuration = simplexml_load_file($fileName);
$flavor=$Topology_Configuration->Flavor;
$flavor->addChild('abc');
echo $Topology_Configuration->asXml();
Results in:
Warning: SimpleXMLElement::addChild(): Cannot add child.
Parent is not a permanent member of the XML tree in
The message is a little wrong, you just try to add the element to an element that does not exists. $Topology_Configuration contains the xml element node, not the Topology_Configuration.
Here are two possible solutions:
Change the XML structure
Create the XML with the Topology_Configuration as the root element.
$topology =new SimpleXMLElement("<Topology_Configuration/>");
Change the access to the Flavor
$xml = simplexml_load_file($fileName);
$flavor=$xml->Topology_Configuration->Flavor;
$flavor->addChild('abc');
At the first time, you can use example to add child nodes
$new_xml = new SimpleXMLElement("<root></root>");
$new_xml->addAttribute('newAttr', 'value');
$newsIntro = $new_xml->addChild('content');
$newsIntro->addAttribute('type', 'value');
Header('Content-type: text/xml');
echo $new_xml->asXML();
and result
<?xml version="1.0"?>
<news newAttr="value">
<content type="value"/>
</news

Parse XML to HTML with PHP SimpleXMLElement

I am having some issues with SimpleXMLElement that I was hoping to get some help.
I was reading about SimpleXMLElement and I built a PHP page to parse this XML:
<?xml version='1.0'?>
<AdXML>
<Response>
<Campaign>
<Overview>
<Name>strip</Name>
<Description>category</Description>
<Status>L</Status>
</Overview>
<Pages>
<Url>page01</Url>
<Url>page02</Url>
<Url>page03</Url>
</Pages>
</Campaign>
</Response>
</AdXML>
Tag "Pages" can have any number of tags "Url" other tags might have only one value, like the tag "Name" for example.
Reading about SimpleXMLElement I ended up with the following code:
$xmlparsed = new SimpleXMLElement($xml); //my xml is being sent as variable
To display single values I am using the code below without a problem:
<?php echo $xmlparsed->Response[0]->Campaign[0]->Overview[0]->Name;?>
Everything works fine. But when I try to parse a tag with multiple lines I get only one line, and everytime I refresh the page it gives me a different "url" value. This is the code I am using:
<?php foreach ($xmlparsed->Response->Campaign->Pages as $Pages) {echo $Pages->Url, PHP_EOL;} ?>
According to PHP's site: http://php.net/manual/en/simplexml.examples-basic.php this should work, but it isn't.
Since I am not expert on PHP I am testing code on a trial-and-error basis.
What am I doing wrong here?
thanks in advance for any help.
You only have one Pages so you are only entering that foreach once. Try looping on the urls.
$xml = "<?xml version='1.0'?>
<AdXML>
<Response>
<Campaign>
<Overview>
<Name>strip</Name>
<Description>category</Description>
<Status>L</Status>
</Overview>
<Pages>
<Url>page01</Url>
<Url>page02</Url>
<Url>page03</Url>
</Pages>
</Campaign>
</Response>
</AdXML>";
$xmlparsed = new SimpleXMLElement($xml);
foreach ($xmlparsed->Response->Campaign->Pages->Url as $url) {
echo $url, PHP_EOL;
}
Output:
page01
page02
page03
You can also use XPath.
foreach( $xml->xpath( 'Response/Campaign/Pages/Url' ) as $url ) {
echo $url;
}

Edit XML file (remove node and add new one)

I have problems to deal with XML in PHP. What i want is to remove a not needed element and replace it with a other one.
Let's say the XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<software>
<info>
<version>1.2</version>
<lasterror>1386680712</lasterror>
</info>
<decryption>
<funcgroup siglength="86">
<func>
<name>Mk</name>
<args>$a</args>
<code>XXXX</code>
</func>
<func>
<name>Nk</name>
<args>$a,$b</args>
<code>XXXX</code>
</func>
</funcgroup>
</decryption>
</software>
PHP Code:
$domtree = new DOMDocument('1.0', 'UTF-8');
$domtree->loadXML(file_get_contents('test.xml'));
$thedocument = $domtree->documentElement;
$list = $thedocument->getElementsByTagName('funcgroup');
foreach ($list as $domElement) {
$sig_length = $domElement->getAttribute('siglength');
if($sig_length == $signature_length) {
$domElement->parentNode->removeChild($domElement);
break;
}
}
$some_stuff = $domtree->getElementsByTagName('software');
$some_stuff = $domtree->getElementsByTagName('decryption');
$funcgroup = $domtree->appendChild($domtree->createElement('funcgroup'));
$funcgroup->setAttribute('siglength', $signature_length);
$func = $funcgroup->appendChild($domtree->createElement('func'));
$func->appendChild($domtree->createElement('name', $outer_element[0]));
$func->appendChild($domtree->createElement('args', $outer_element[1]));
$code = $func->appendChild($domtree->createElement('code'));
$code->appendChild($domtree->createTextNode($outer_element[2]));
Note: I removed some stuff otherwise it would get too complicated i guess. The above code shows what i do, but without some other loops and variables which are not needed in that question. Every variable (and array) is defined. So don't worry about that.
What i want is to remove the whole <funcgroup siglength="86"> in order to replace it with a different one.
The script works fine, but there is one problem in the output XML. It looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<software>
<info>
<version>6.3</version>
<lasterror>1386680712</lasterror>
</info>
<decryption/>
</software>
<funcgroup siglength="86">
<func>
<name>Nk</name>
<args>$a</args>
<code>YYYYY</code>
</func>
<func>
<name>Ok</name>
<args>$a,$b</args>
<code>YYYY</code>
</func>
</funcgroup>
As you can see, the closing software and decryption tags are on the wrong place now.
How can i fix that? I spent hours but can't find a working solution.
The problem is caused by the removeChild() since it works fine if i do not remove something.
You are adding your new child node to the document itself (instead of the decryption node), which is not what you want
$domtree->appendChild
Instead you should:
$decryption = $domtree->getElementsByTagName('decryption')->item(0);
$funcgroup = $decryption->appendChild($domtree->createElement('funcgroup'));
Edit:
You can edit the text value of the lasterror node by doin:
$domtree->getElementsByTagName('lasterror')->item(0)->firstChild->nodeValue = "New value";
Consult the documentation of the DOMNodeList and DOMNode class to see what else you can do with it.

xml and php getting tag elements with certain element and outputting

I am have two xml files.. I first get one and loop through it then I need to take an id from the first xml file and find it in the second one and echo out the results associated with that id. If I were to do this with SQL I would simply do this:
$query = (SELECT * FROM HotelSummary WHERE roomTypeCode = '$id') or die();
while($row=mysql_fetch_array($query)){
$name = $row['Name'];
}
echo $name;
How can I do this is in xml and php??
I recommend you to read the DOMDocument documentation.
It's quite heavy but also powerful (not always clear what happens, but the Internet shold always give you a solution)
You can simply walk through your first document, finding your Id and then find your DOMElement via an XPath.
<?php
$dom = new DOMDocument();
$dom->load('1.xml');
foreach ($dom->getElementsByTagName('article') as $node) {
// your conditions to find out the id
$id = $node->getAttribute('id');
}
$dom = new DOMDocument();
$dom->load('2.xml');
$xpath = new DOMXPath($dom);
$element = $xpath->query("//*[#id='".$id."']")->item(0);
// would echo "top_2" based on my example files
echo $element->getAttribute('name');
Based on following test files:
1.xml
<?xml version="1.0" encoding="UTF-8"?>
<articles>
<article id="foo_1">
<title>abc</title>
</article>
<article id="foo_2">
<title>def</title>
</article>
</articles>
2.xml
<?xml version="1.0" encoding="UTF-8"?>
<tests>
<test id="foo_1" name="top_1">
</test>
<test id="foo_2" name="top_2">
</test>
</tests>
Use SimpleXML to create an object representation of the file. You can then loop through the elements of the Simple XML object.
Depending on the format of the XML file:
Assuming it is:
<xml>
<roomTypeCode>
<stuff>stuff</stuff>
<name>Skunkman</name>
</roomTypeCode>
<roomTypeCode>
<stuff>other stuff</stuff>
<name>Someone Else</name>
</roomTypeCode>
</xml>
It would be something like this:
$xml = simplexml_load_file('xmlfile.xml');
for($i = 0; $i < count($xml->roomTypeCode); $i++)
{
if($xml->roomTypeCode[$i]->stuff == "stuff")
{
$name = $xml->roomTypeCode[$i]->name;
}
}
That connects to the XML file, finds how many roomTypeCode entries there are, searches for the value of "stuff" within and when it matches it correctly, you can access anything having to do with that XML entry.

Categories