Empty xml object when using SimpleXML - Node no longer exists - php

The xml is as follows:
<root>
<organizations>
<organization>
<info>
<orgID>1234</orgID>
<orgName>XYZ Company</orgName>
<address>
<address1>1 Main Street</address1>
<city>Somewhere</city>
<state>MI</state>
<zip>12334</zip>
</address>
</info>
</organization>
</organizations>
</root>
The code is as follows:
$ind = strpos($xmlResponse, "<");
$xml = simplexml_load_string(substr($xmlResponse, $ind));
//echo $xml;
$orgList = $xml->organizations->children();
foreach($orgList as $orgList)
{
echo $orgList->orgName;
}
And I get the following error:
Warning: main() [function.main]: Node no longer exists in...
The offending line is
foreach($orgList as $orgList)
Can anyone tell me what I'm doing wrong? I've tried accessing the xml through 50 different ways and either get that error or an empty xml object.
Thanks in advance!

It looks like you're overwriting the xml object when you loop with $orgList as $orgList. Try this instead:
foreach($orgList as $org)
echo $org->orgName;

Try the following:
$xml = simplexml_load_string($xml);
$org = $xml->organizations->children();
foreach($org as $k => $v)
{
echo $v->info->orgName;
}

Try using xpath
Put the XML in x.xml file
then create php file:
<?php
$xml = simplexml_load_file('x.xml');
$orgList = $xml->xpath("/root/organizations/organization/info");
print $orgList[0]->orgName;
?>

Related

PHP Search between two points

I'm trying to deal with some XML in PHP.
I have code, such as this:
<?php
$stream = fopen("xml","r");
?>
Where "xml" contains something such as this:
<name>name1</name>
<key>key1</key>
<name>name2</name>
<key>key2</key>
etc.
I'd like to create an array out of the contents of the <key> tags, something like where
keys[0] = "key1"
and
keys[1] = "key2"
Any help is appreciated, thank you very much :)
Solution:
$xmlstr = fread($stream,filesize("xml-file"));
$sxe = new SimpleXMLElement($xmlstr);
echo $sxe->getName() . "\n";
foreach ($sxe->children() as $child) {
echo $child->children();
}
You should use DOM functions for this case. Let's suppose a well-formed XML document (xmltest.xml):
<?xml version="1.0" encoding="utf-8"?>
<root>
<name>name1</name>
<key>key1</key>
<name>name2</name>
<key>key2</key>
</root>
This code loads the xml file into DOM document and gets all nodes with tag key;
<?php
$dom = new DOMDocument('1.0','utf-8');
$dom->load('xmltest.xml');
$keys = $dom->getElementsByTagName('key');
for ($i = 0; $i < $keys->length; $i++) {
echo $keys->item($i)->nodeValue . "</br>";
}
?>

How to load string back xml with simpleXML in PHP?

Would anyone know how i can "explode" a string back into "normal" xml format?
I found this script (ref:gooseflight,2010) that looks like it can do the job but the output comes out stuck together.
Here's the code:
enter code herefunction combineXML($file)
{
global $xmlstr;
$xml = simplexml_load_file($file);
foreach($xml as $element)
$xmlstr .= $element->asXML();
}
$files[] = "tmp.xml";
$files[] = "traduction.xml";
$xmlstr = '<CAB>';
foreach ($files as $file)
combineXML($file);
$xmlstr .= '</CAB>';
// Convert string to XML for further processing
$xml = simplexml_load_string($xmlstr);
$bytes = file_put_contents("combined.xml", $xml->asXML())
Here is the output:
<?xml version="1.0" encoding="UTF-8"?>
<CAB>
<CABO>XXXXXXXXXX0987650003</CABO><ACTIVITY>NONE</ACTIVITY><BEORI>blablaE</BEORI>BEDEST>blabla</BEDEST><NATRELA>more blabla</NATRELA><ANE>2014</ANE><NODEP>1111</NODEP>
</CAB>
So how could i seperate the nodes to look like this?:
<?xml version="1.0" encoding="UTF-8"?>
<CAB>
<CABO>XXXXXXXXXX0987650003</CABO>
<ACTIVITY>NONE</ACTIVITY>
<BEORI>blablaE</BEORI>
<BEDEST>blabla</BEDEST>
<NATRELA>more blabla</NATRELA>
<ANE>2014</ANE>
<NODEP>1111</NODEP>
.....
</CAB>
Would anyone know how to fix it?
I would suggest to use DomDocument class to save the XML; check this:
$dom_obj = new DOMDocument();
$dom_obj->loadXML($file);
// Do all your changes to the file by using DomDocument command (e.g. CreateElement, CreateAttribute, etc)
$dom_obj->formatOutput = true;
$dom_obj->save($file);

Pull XML nodeValue into php Variable

I am trying to assign the <all> / <avg> value in this XML code to a variable, so that I can use it for calculations. But when I do this, and try to print the value, I get a blank screen. Can someone please help?
<stats>
<type id="a">
<buy>
<volume>698299009</volume>
<avg>17.94</avg>
<max>18.45</max>
<min>1.00</min>
</buy>
<sell>
<volume>16375234</volume>
<avg>21.03</avg>
<max>24.99</max>
<min>20.78</min>
</sell>
<all>
<volume>714674243</volume>
<avg>18.01</avg>
<max>24.99</max>
<min>1.00</min>
</all>
</type>
</stats>
The php code I am using is as follows:
$xml = simplexml_load_file("values.xml");
$unit_value = $xml->xpath("/stats/type[#id='a']/buy/avg/")->nodeValue;
echo $unit_value;
Please refer documentation here, $xml->xpath should return you the array. The docs also shows an example of how to access text nodes. Below is an excerpt from the docs
<?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";
}
?>
which produces output as
/a/b/c: text
/a/b/c: stuff
b/c: text
b/c: stuff
which is I suppose exactly what you need.
xpath returns an array of SimpleXMLElement objects .. so you can do this :
$unit_value = $xml->xpath("//stats//type[#id='a']//buy//avg");
echo (string)$unit_value[0]; // cast to string not required
Working example here
or if you are using PHP => 5.4 you can do this :
$unit_value = $xml->xpath("//stats//type[#id='a']//buy//avg")[0];
echo $unit_value;
Working example here

PHP XML Output Concatenation

I am using XPath to query an xml document and then copy found nodes to a separate results xml file, however the problem I am having is that the XML declaration at the top gets added each time a new node is added to the results file.
Here is my php code:
$allEventsForVenue = $xPath->query(
"/Ticket/EventsPoints/Event[contains(PerformanceName,'$searchParam')]"
);
foreach ($allEventsForVenue as $event) {
$dstDom = new DOMDocument('1.0', 'utf-8');
$dstDom->appendChild($dstDom->createElement('EventsPoints'));
$dstDom->documentElement->appendChild($dstDom->importNode($event, true));
//echo $dstDom->saveXml();
$dstDom->formatOutput = true;
$strxml .= $dstDom->saveXML();
$handle = fopen("/var/www/html/xml/searchresults$searchID.xml", "w");
fwrite($handle, $strxml);
fclose($handle);
}
Invalid XML File (two xml declarations in the one file):
->> <?xml version="1.0" encoding="utf-8"?>
<EventsPoints>
<Event ID="17">
<PerformanceName>Bressie</PerformanceName>
<PresaleTime/>
<PriceRange>17 - 17</PriceRange>
<VenueID ID="19"/>
</Event>
</EventsPoints>
->> <?xml version="1.0" encoding="utf-8"?>
<EventsPoints>
<Event ID="180">
<PerformanceName>U2</PerformanceName>
<PriceRange>20 - 20</PriceRange>
<VenueID ID="198"/>
</Event>
</EventsPoints>
You are creating new DOMDocument instance in loop. Also you are writing in each iteration. This is making new XML document on each iteration and its get appended in your xml file. What you need to do is, loop the XML generation part. Not the whole thing.
If you loop only the appendChild parts, your problem will be solved.
$dstDom = new DOMDocument('1.0', 'utf-8');
$dstDom->formatOutput = true;
foreach ($allEventsForVenue as $event) {
$dstDom->appendChild($dstDom->createElement('EventsPoints'));
$dstDom->documentElement->appendChild($dstDom->importNode($event, true));
}
file_put_contents("/var/www/html/xml/searchresults$searchID.xml", $dstDom->saveXML());
DomDocument lets you output a specific node without the xml declaration.
Just include a node in saveXML, like saveXML($node), with node being an XMLNode type object.
With this method I think you can bypass the whole "create sub-xmldocument/import node" thing, by outputting directly the desired node in a string.
use something like this
enter <?php
// Continued from example XML above.
/* Search for <a><b><c> */
$result = $xml->xpath('/a/b/c');
while(list( , $node) = each($result)) {
echo $node->asXML();
}
?>

xml parsing with php

I would like to create a new simplified xml based on an existing one:
(using "simpleXml")
<?xml version="1.0" encoding="UTF-8"?>
<xls:XLS>
<xls:RouteInstructionsList>
<xls:RouteInstruction>
<xls:Instruction>Start</xls:Instruction>
</xls:RouteInstruction>
</xls:RouteInstructionsList>
<xls:RouteInstructionsList>
<xls:RouteInstruction>
<xls:Instruction>End</xls:Instruction>
</xls:RouteInstruction>
</xls:RouteInstructionsList>
</xls:XLS>
Because there are always colons in the element-tags, it will mess with "simpleXml", I tried to use the following solution->link.
How can I create a new xml with this structure:
<main>
<instruction>Start</instruction>
<instruction>End</instruction>
</main>
the "instruction-element" gets its content from the former "xls:Instruction-element".
Here is the updated code:
But unfortunately it never loops through:
$source = "route.xml";
$xmlstr = file_get_contents($source);
$xml = #simplexml_load_string($xmlstr);
$new_xml = simplexml_load_string('<main/>');
foreach($xml->children() as $child){
print_r("xml_has_childs");
$new_xml->addChild('instruction', $child->RouteInstruction->Instruction);
}
echo $new_xml->asXML();
there is no error-message, if I leave the "#"…
/* the use of # is to suppress warning */
$xml = #simplexml_load_string($YOUR_RSS_XML);
$new_xml = simplexml_load_string('<main/>');
foreach ($xml->children() as $child)
{
$new_xml->addChild('instruction', $child->RouteInstruction->Instruction);
}
/* to print */
echo $new_xml->asXML();
You could use xpath to simplify things. Without knowing the full details, I don't know if it will work in all cases:
$source = "route.xml";
$xmlstr = file_get_contents($source);
$xml = #simplexml_load_string($xmlstr);
$new_xml = simplexml_load_string('<main/>');
foreach ($xml->xpath('//Instruction') as $instr) {
$new_xml->addChild('instruction', (string) $instr);
}
echo $new_xml->asXML();
Output:
<?xml version="1.0"?>
<main><instruction>Start</instruction><instruction>End</instruction></main>
Edit: The file at http://www.gps.alaingroeneweg.com/route.xml is not the same as the XML you have in your question. You need to use a namespace like:
$xml = #simplexml_load_string(file_get_contents('http://www.gps.alaingroeneweg.com/route.xml'));
$xml->registerXPathNamespace('xls', 'http://www.opengis.net/xls'); // probably not needed
$new_xml = simplexml_load_string('<main/>');
foreach ($xml->xpath('//xls:Instruction') as $instr) {
$new_xml->addChild('instruction', (string) $instr);
}
echo $new_xml->asXML();
Output:
<?xml version="1.0"?>
<main><instruction>Start (Southeast) auf Sihlquai</instruction><instruction>Fahre rechts</instruction><instruction>Fahre halb links - Ziel erreicht!</instruction></main>

Categories