Exception xml+php - php

well guys this code trow this exception and I dont know why...
exception: Fatal error: Uncaught exception 'DOMException' with message
'Not Found Error' in
C:\AppServ\www\CpVela\publicidades\delete_pub.php:14 Stack trace: #0
C:\AppServ\www\CpVela\publicidades\delete_pub.php(14):
DOMNode->removeChild(Object(DOMElement)) #1 {main} thrown in
C:\AppServ\www\CpVela\publicidades\delete_pub.php on line 14
<?php
include "../src/defines.php";
if(!empty($_GET['CDG'])){
$doc = new DOMDocument;
$doc->load(DIR_PUBLICIDADES);
$thedocument = $doc->documentElement;
$list = $thedocument->getElementsByTagName('item');
echo $list->length;
$nodeToRemove = NULL;
foreach ($list as $domElement){
$attrValue = $domElement->getAttribute('numero');
if ($attrValue == $_GET['CDG']) {
$nodeToRemove = $domElement;
$thedocument->removeChild($nodeToRemove); // <<< line 14
$f = fopen(DIR_PUBLICIDADES,'w+');
fwrite($f,$doc->saveXML());
fclose($f);
}
}
if ($nodeToRemove != null){
$thedocument->removeChild($nodeToRemove);
$f = fopen(DIR_PUBLICIDADES,'w+');
fwrite($f,$doc->saveXML());
fclose($f);
}
}
header("location:publicidades.php");
?>
my code XML is
<?xml version="1.0" encoding="utf-8"?>
<publicidades>
<internas>
<item nombre="Tony Roma's" numero="SOL_17" posX="266" posY="229" telefono="" web="" correo="" encargado="" descripcion="" promocion="" ></item>
</internas>
<externas>
</externas>
</publicidades>

The problem is with your removeChild method.
This error is a result of:
Raised if oldnode is not a child of this node.
$nodeToRemove reffers to <item,
while $thedocument reffers to the root element node which is <publicidades>.
<item> is a child of <internas> not of <public...>.
EDIT:
Try adding:
$internas = $doc->documentElement->getElementsByTagName('internas');
right after:
$thedocument = $doc->documentElement;
and then:(EDIT2)
foreach ($internas as $node) {
$node->parentNode->removeChild($node);
}

Related

Cannot parse XML using simplexml_load_string

I have tried various methods as seen in here
and in here and many more.
I even tried the function in here.
The XML looks something like this:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://tempuri.org/IFooEntryOperation/SaveFooStatusResponse</a:Action></s:Header><s:Body><SaveFooStatusResponse xmlns="http://htempuri.org/"><SaveFooStatusResult xmlns:b="http://schemas.datacontract.org/2004/07/FooAPI.Entities.Foo" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><b:AWBNumber>999999999</b:AWBNumber><b:IsError>true</b:IsError><b:Status><b:FooEntryStatus><b:StatusCode>Foo_ENTRY_FAILURE</b:StatusCode><b:StatusInformation>InvalidEmployeeCode</b:StatusInformation></b:FooEntryStatus></b:Status></SaveFooStatusResult></SaveFooStatusResponse></s:Body></s:Envelope>
And here's one example of my code (I have a dozen variations):
$ReturnData = $row["ReturnData"]; // string frm a database
if (strpos($ReturnData, "s:Envelope") !== false){
$ReturnXML = new SimpleXMLElement($ReturnData);
$xml = simplexml_load_string($ReturnXML);
$StatusCode = $xml["b:StatusCode"];
echo "<br>StatusCode: " . $StatusCode;
$IsError = $xml["b:IsError"];
echo "<br>IsError: " . $IsError;
}
Another option I tried:
$test = json_decode(json_encode($xml, 1); //this didn't work either
I either get an empty array or I get errors like:
"Fatal error: Uncaught exception 'Exception' with message 'String
could not be parsed as XML"
I have tried so many things, I may lost track of where my code is right now. Please help - I am really stuck...
I also tried:
$ReturnXML = new SimpleXMLElement($ReturnData);
foreach( $ReturnXML->children('b', true)->entry as $entries ) {
echo (string) 'Summary: ' . simplexml_load_string($entries->StatusCode->children()->asXML(), null, LIBXML_NOCDATA) . "<br />\n";
}
Method 1.
You can try the below code snippet to parse it an array
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $values, $indexes);// $xml containing the XML
xml_parser_free($p);
echo "Index array\n";
print_r($indexes);
echo "\nVals array\n";
print_r($values);
Method 2.
function XMLtoArray($xml) {
$previous_value = libxml_use_internal_errors(true);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->loadXml($xml);
libxml_use_internal_errors($previous_value);
if (libxml_get_errors()) {
return [];
}
return DOMtoArray($dom);
}
function DOMtoArray($root) {
$result = array();
if ($root->hasAttributes()) {
$attrs = $root->attributes;
foreach ($attrs as $attr) {
$result['#attributes'][$attr->name] = $attr->value;
}
}
if ($root->hasChildNodes()) {
$children = $root->childNodes;
if ($children->length == 1) {
$child = $children->item(0);
if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE]))
{
$result['_value'] = $child->nodeValue;
return count($result) == 1
? $result['_value']
: $result;
}
}
$groups = array();
foreach ($children as $child) {
if (!isset($result[$child->nodeName])) {
$result[$child->nodeName] = DOMtoArray($child);
} else {
if (!isset($groups[$child->nodeName])) {
$result[$child->nodeName] = array($result[$child->nodeName]);
$groups[$child->nodeName] = 1;
}
$result[$child->nodeName][] = DOMtoArray($child);
}
}
}
return $result;
}
You can get an array using print_r(XMLtoArray($xml));
I don't know how you would do this using SimpleXMLElement but judging by the fact you have tried so many things I trust that the actual method employed is not important so you should therefore find the following, which uses DOMDocument and DOMXPath, of interest.
/* The SOAP response */
$strxml='<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IFooEntryOperation/SaveFooStatusResponse</a:Action>
</s:Header>
<s:Body>
<SaveFooStatusResponse xmlns="http://htempuri.org/">
<SaveFooStatusResult xmlns:b="http://schemas.datacontract.org/2004/07/FooAPI.Entities.Foo" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<b:AWBNumber>999999999</b:AWBNumber>
<b:IsError>true</b:IsError>
<b:Status>
<b:FooEntryStatus>
<b:StatusCode>Foo_ENTRY_FAILURE</b:StatusCode>
<b:StatusInformation>InvalidEmployeeCode</b:StatusInformation>
</b:FooEntryStatus>
</b:Status>
</SaveFooStatusResult>
</SaveFooStatusResponse>
</s:Body>
</s:Envelope>';
/* create the DOMDocument and manually control errors */
libxml_use_internal_errors( true );
$dom=new DOMDocument;
$dom->validateOnParse=true;
$dom->recover=true;
$dom->strictErrorChecking=true;
$dom->loadXML( $strxml );
libxml_clear_errors();
/* Create the XPath object */
$xp=new DOMXPath( $dom );
/* Register the various namespaces found in the XML response */
$xp->registerNamespace('b','http://schemas.datacontract.org/2004/07/FooAPI.Entities.Foo');
$xp->registerNamespace('i','http://www.w3.org/2001/XMLSchema-instance');
$xp->registerNamespace('s','http://www.w3.org/2003/05/soap-envelope');
$xp->registerNamespace('a','http://www.w3.org/2005/08/addressing');
/* make XPath queries for whatever pieces of information you need */
$Action=$xp->query( '//a:Action' )->item(0)->nodeValue;
$StatusCode=$xp->query( '//b:StatusCode' )->item(0)->nodeValue;
$StatusInformation=$xp->query( '//b:StatusInformation' )->item(0)->nodeValue;
printf(
"<pre>
%s
%s
%s
</pre>",
$Action,
$StatusCode,
$StatusInformation
);
The output from the above:
http://tempuri.org/IFooEntryOperation/SaveFooStatusResponse
Foo_ENTRY_FAILURE
InvalidEmployeeCode

Generate XML out of Textfile using json_decode

I have this Textfile (namelist.txt):
{"0":"Mr Tony Test","1":"Ms Tina Testy"}
And I try to convert it into XML:
<?php
$xml = new DOMDocument();
$names = json_decode(file_get_contents('namelist.txt'));
foreach ($names as $name)
{
$xml_name = $xml->createElement($name);
}
$xml->save("rss.xml");
?>
I get the following Error:
Fatal error: Uncaught exception 'DOMException' with message 'Invalid
Character Error' in C:\xampp\htdocs\xibo\rss.php:6 Stack trace: #0
C:\xampp\htdocs\xibo\rss.php(6): DOMDocument->createElement('Mr Tony
Te...') #1 {main} thrown in C:\xampp\htdocs\xibo\rss.php on line 6
Is is even possible like this?
Edit 1:
Tried a solution by #spiky but I get a blank page as result:
<?php
$obj=('namelist.txt');
function json_to_xml($obj){
$str = "";
if(is_null($obj))
return "<null/>";
elseif(is_array($obj)) {
//a list is a hash with 'simple' incremental keys
$is_list = array_keys($obj) == array_keys(array_values($obj));
if(!$is_list) {
$str.= "<hash>";
foreach($obj as $k=>$v)
$str.="<item key=\"$k\">".json_to_xml($v)."</item>".CRLF;
$str .= "</hash>";
} else {
$str.= "<list>";
foreach($obj as $v)
$str.="<item>".json_to_xml($v)."</item>".CRLF;
$str .= "</list>";
}
return $str;
} elseif(is_string($obj)) {
return htmlspecialchars($obj) != $obj ? "<![CDATA[$obj]]>" : $obj;
} elseif(is_scalar($obj))
return $obj;
else
throw new Exception("Unsupported type $obj");
}
?>
If you decode the JSON is an object with two properties (0 and 1).
var_dump(json_decode('{"0":"Mr Tony Test","1":"Ms Tina Testy"}'));
Output:
object(stdClass)#1 (2) {
["0"]=>
string(12) "Mr Tony Test"
["1"]=>
string(13) "Ms Tina Testy"
}
You iterate the properties and use the values as element names. But they aren't valid names. Here is a static example producing the error:
$document = new DOMDocument();
$document->createElement('name with spaces');
Output:
Fatal error: Uncaught exception 'DOMException' with message
'Invalid Character Error' in /tmp/...
So you to make sure that you generate a valid XML. Likes this:
$json = json_decode('{"0":"Mr Tony Test","1":"Ms Tina Testy"}');
$document = new DOMDocument();
$names = $document->appendChild(
$document->createElement('names')
);
foreach ($json as $value) {
$names
->appendChild($document->createElement('name'))
->appendChild($document->createTextNode($value));
}
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<names>
<name>Mr Tony Test</name>
<name>Ms Tina Testy</name>
</names>
It is a better idea to use a definable node structure for the XML, not one that is defined by the data.
You named the result xml file 'rss.xml'. RSS is a defined format. So if you like to generate RSS you have to generate specific nodes.
$json = json_decode('{"0":"Mr Tony Test","1":"Ms Tina Testy"}');
$document = new DOMDocument();
$rss = $document->appendChild($document->createElement('rss'));
$rss->setAttribute('version', '2.0');
$channel = $rss->appendChild($document->createElement('channel'));
foreach ($json as $value) {
$item = $channel->appendChild($document->createElement('item'));
$item
->appendChild($document->createElement('title'))
->appendChild($document->createTextNode($value));
}
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<item>
<title>Mr Tony Test</title>
</item>
<item>
<title>Ms Tina Testy</title>
</item>
</channel>
</rss>

PHP DOM append child after getting Element from Tag

Currently my XML looks like
<?xml version="1.0" ?>
<hero-attributes>
<hero-weaknesses>
<hero>
IO
</hero>
</hero-weaknesses>
</hero-attributes>
I am trying to add
<hero>Wisp</hero>
after
<hero>IO</hero>
I currently have
<?php
$dir = opendir("../../heroes/");
while ($listing = readdir($dir))
{
if (substr($listing, 0, 1) == ".")
continue;
$dom = new DOMDocument();
$url = '../../heroes/' . $listing;
#$dom->load($url);
$element = $dom->getElementsByTagName('hero-weaknesses')->item(0);
if(is_null($element))
die('No element found');
$hero = $dom->createElement('hero', "IO");
$hero = $element->appendChild($hero);
$heroName = $dom->createTextNode('Wisp');
$heroName = $hero->appendChild($heroName);
}
?>
the error I am getting (When i remove the null check)
Fatal error: Call to a member function appendChild() on a non-object in C:\GitHub\--\public_html\Scripts\GetHeros.php on line 15
I have no idea why $element is NULL and what the problem is

Getting nodes by attribute value in DomXML and PHP

I am trying to select a specific node to edit its content and attributes later on, but I am not able to select a notice node (see the PHP code below).
XML document
<?xml version="1.0" encoding="UTF-8"?>
<notices lastID="0001">
<!--
<notice id="0000" endDate="31-12-2025">
Content of the notice.
</notice>
-->
<notice id="0001" endDate="13-01-2013" active="1">
One amazing notice.
</notice>
</notices>
The $id value is "0001" (string).
PHP
$document = new DOMDocument;
$document = dom_import_simplexml($this->xml);
$notices= $document->getElementsByTagName('notice');
#var_dump($notices);
foreach($notices as $element)
{
if($element->getAttribute('id') == $id)
{
$notice = $element;
var_dump($notice); //Returns absolutely nothing (I guess the if returns false).
}
}
$notice->removeAttribute("endDate");
$notice->setAttribute("endDate",$endDate);
Everytime I fall into the if statement, my $notice returns no value.
I tried with xpath query ( //notice[#id="{$id}"]) without any success.
To clarify, my problem would be $element->getAttribute('id') does not seem to work.
I also tried with SimpleXML:
PHP
$document = new DOMDocument;
$document = simplexml_import_dom($this->xml);
$notice = "";
foreach($document->notices->children() as $element)
{
$attributes = $element->attributes();
if($attributes['id'] == $id)
{
$notice= $element;
var_dump($notice);
}
}
$avis->removeAttribute("endDate");
$avis->setAttribute("endDate",$endDate);
SimpleXML gives me the following message: Node no longer exists on the following line:
foreach($document->notices->children() as $element)
I finally got it.
PHP
$document = simplexml_import_dom($this->xml);
$notice = "";
$xpathResults = $document->xpath('//notice');
foreach($xpathResults as $element)
{
$elementID = $element->id[0];
$domXML = dom_import_simplexml($element);
if((string) $noticeID == $id)
{
$notice = $domXML;
}
}

Wrap an element for each set of elements with SimpleXML/DOMDocument

I have the code below to create a XML file
<?php
try
{
$dom = new domDocument;
$dom->formatOutput = true;
$root = $dom->appendChild($dom->createElement( "items" ));
$sxe = simplexml_import_dom( $dom );
$sxe->addChild("model", "HTC Desire");
$sxe->addChild("model", "Motorola Atrix");
echo $sxe->asXML();
}
catch( Exception $e )
{
echo $e->getMessage();
}
?>
While execute this code, it will generate the content likes:
<?xml version="1.0"?>
<items>
<model>HTC Desire</model>
<model>Motorola Atrix</model>
</items>
But, I would like to wrap an element called item for each model, the result should be:
<?xml version="1.0"?>
<items>
<item><model>HTC Desire</model></item>
<item><model>Motorola Atrix</model></item>
</items>
Anyone could suggest how to do this?
The addChild method returns a SimpleXMLElement object representing the child added to the XML node. This allows for method chaining like so:
try
{
$dom = new domDocument;
$dom->formatOutput = true;
$root = $dom->appendChild($dom->createElement( "items" ));
$sxe = simplexml_import_dom($dom);
$sxe->addChild("item")->addChild("model", "HTC Desire");
$sxe->addChild("item")->addChild("model", "Motorola Atrix");
echo $sxe->asXML();
}
catch( Exception $e )
{
echo $e->getMessage();
}

Categories