php simplexml adding children-nodes in a loop - php

I'm having a trouble with SimpleXML and addChild().
I am trying to generate an order-file in XML from data in a mysql database.
I want the file to be formed like so:
<Ordreimport>
<Kunde>
<..>
<Orderline>
<data>
</orderline>
<orderline>
<data>
</orderline>
</kunde>
</ordreimport>
The problem is that the following code
$OrderXML = new SimpleXMLElement('<?xml version="1.0" encoding="ISO-8859-1"?><OrdreImport></OrdreImport>');
While ($kunderad = mysql_fetch_array($HentKunde)) {
$OrderXML->addChild('Kunde');
$KundeInfo = $OrderXML->Kunde->addChild('KundeID',''); //BD60 - Kundekort - Kundenr
$OrdreHode = $OrderXML->Kunde->addChild('OrdreHode'); //OF14 - Ordrehode
$OrdreHode= $OrderXML->Kunde->OrdreHode->addChild('OrdreLinje');
while ($olrader = mysql_fetch_array($HentOrdrelinje)) {
$OrdreLinje = $OrderXML->Kunde->OrdreHode->OrdreLinje->addChild('StatusHB'); //se over.
}
Header('Content-type: text/xml');
echo $OrderXML->asXML();
Gives the following result:
<Ordreimport>
<Kunde>
<..>
<Orderline>
<data>
<data>
</orderline>
</kunde>
</ordreimport>
Also having $OrdreHode= $OrderXML->Kunde->OrdreHode->addChild('OrdreLinje'); inside the loop, like I initually though, gives the same result, except that it also creates an empty <orderline> tag for each additional orderline in the database. Which is ALMOST correct, except all the data ends up in the first <orderline> tag.

You are using the entire XML tree for adding nodes. So the first one will be selected. Use the current generated node instead.
Further more write headers and the XML outside the loop.
while ($kunderad = mysql_fetch_array($HentKunde))
{
$Kunde = $OrderXML->addChild('Kunde');
$KundeInfo = $Kunde->addChild('KundeID', ''); //BD60 - Kundekort - Kundenr
$OrdreHode = $Kunde->addChild('OrdreHode'); //OF14 - Ordrehode
$OrdreLinje = $OrdreHode->addChild('OrdreLinje');
// execute statement to query related data rows here
while ($olrader = mysql_fetch_array($HentOrdrelinje))
{
$OrdreLinje = $OrdreLinje->addChild('StatusHB'); //se over.
}
}
Header('Content-type: text/xml');
echo $OrderXML->asXML();
Note that mysql_ functions are unsafe and obsolete in newer PHP versions. Use mysqli_ or PDO instead.
You do not show how you query the results of the line:
while ($olrader = mysql_fetch_array($HentOrdrelinje))
Without executing the statement related to the current $kunderad within each iteration of the outer loop the inner loop won't query any new datasets. I assume you actually did and cutted this out from the minimal example.

Related

Query XML File using PHP for Values

I am currently working on a project that requires me to query an XML file like php to return a value that matches the request. Take a look at the XML:
<ENVELOPE>
<MASTER>
<STKDETNAME>004-011</STKDETNAME>
<STKPNO>PTN771</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>500</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-012</STKDETNAME>
<STKPNO>PTN772</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>500</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-013</STKDETNAME>
<STKPNO>PTN773</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>1000</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-014</STKDETNAME>
<STKPNO>PTN774</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>1000</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-015</STKDETNAME>
<STKPNO>PTN775</STKPNO>
<STKPRICE>400</STKPRICE>
<STKOPBAL>1000</STKOPBAL>
</MASTER>
</ENVELOPE>
Now, I want to get the STKPRICE AND STKOPBAL for a SKTPNO= PTN773. This is what i have seen so far, but i don't know how to get the two values. I am new to XML.
$file = 'stocksum.xml';//same file as above
$xmlfile = simplexml_load_file($file);
$partno = PTN775;
$fnd = $xmlfile->xpath('/ENVELOPE/MASTER/STKPNO[.="$partno"]');
There are a couple of issues with the code which are just syntax problems, these are the partno needing quotes and when building the XPath expression, you use single quotes so it doesn't insert the actual part number.
BUT to get to your actual problem, if you change your XPath to the one used here, this will find the <MASTER> element whose <STKPNO> is the one your after. So then you can refer to the elements withing the <MASTER> element using standard SimpleXML object notation...
$partno = 'PTN775';
$fnd = $xmlfile->xpath('/ENVELOPE/MASTER[STKPNO="'.$partno.'"]');
echo $fnd[0]->STKPRICE.PHP_EOL;
Note that as xpath() returns a list of matches, I use $fnd[0] to get the first one.
Code which also has a check to see if the part actually exists...
$xmlfile = simplexml_load_file($file);
$partno = 'PTN7751';
$fnd = $xmlfile->xpath('/ENVELOPE/MASTER[STKPNO="'.$partno.'"]');
if ( count($fnd) == 0 ) {
echo "Not found";
}
else {
echo $fnd[0]->STKPRICE.PHP_EOL;
}

how to insert data inside tag XML

I want to create dynamic tags in XML using PHP
like this : <wsse:Username>fqsuser01</wsse:Username>
the main thing is that I want the tags will change the value inside ---> "wsse"
(like this value)
what I need to do? to create this XML file wite PHP?
Thanks,
For this purpose you can use XMLWriter for example (another option is SimpleXML). Both option are in PHP core so any third party libraries aren't needed. wsse is a namespace - more about them you can read here
I also share with you some example code:
<?php
//create a new xmlwriter object
$xml = new XMLWriter();
//using memory for string output
$xml->openMemory();
//set the indentation to true (if false all the xml will be written on one line)
$xml->setIndent(true);
//create the document tag, you can specify the version and encoding here
$xml->startDocument();
//Create an element
$xml->startElement("root");
//Write to the element
$xml->writeElement("r1:id", "1");
$xml->writeElement("r2:id", "2");
$xml->writeElement("r3:id", "3");
$xml->endElement(); //End the element
//output the xml
echo $xml->outputMemory();
?>
Result:
<?xml version="1.0"?>
<root>
<r1:id>1</r1:id>
<r2:id>2</r2:id>
<r3:id>3</r3:id>
</root>
You could use a string and convert it to XML using simplexml_load_string(). The string must be well formed.
<?php
$usernames= array(
'username01',
'username02',
'username03'
);
$xml_string = '<wsse:Usernames>';
foreach($usernames as $username ){
$xml_string .= "<wsse:Username>$username</wsse:Username>";
}
$xml_string .= '</wsse:Usernames>';
$note=
<<<XML
$xml_string
XML; //backspace this line all the way to the left
$xml=simplexml_load_string($note);
?>
If you wanted to be able to change the namespaces on each XML element you would do something very similar to what is shown above. (Form a string with dynamic namespaces)
The XML portion that I instructed you to backspace all of the way has weird behavior. See https://www.w3schools.com/php/func_simplexml_load_string.asp for an example that you can copy & paste.

How do I print out an XML response from an XML database result array in PHP?

I have a query that returns my rows as already made XML. If it matters, it is Oracle. When I run my query natively, XMLELEMENT function.
For example, from the Oracle documentation:
SELECT XMLELEMENT("Emp",
XMLATTRIBUTES(e.employee_id AS "ID", e.last_name),
XMLELEMENT("Dept", e.department_id),
XMLELEMENT("Salary", e.salary)) AS "Emp Element"
FROM employees e
WHERE e.employee_id = 206;
Emp Element
---------------------------------------------------------------
<Emp ID="206" LAST_NAME="Gietz">
<Dept>110</Dept>
<Salary>8300</Salary>
</Emp>
How can I make PHP return an XML file, so I don't have to do any '<' . $row['lastname'] . '>';` type statements. I don't need anything like that because it is all handled in my query.
Whenever I use print_r() it strips all my nodes and only gives me the value in the nodes. Same with key, value in a foreach.
<Emp ID="206" LAST_NAME="Gietz">
<Dept>110</Dept>
<Salary>8300</Salary>
</Emp>
ends up with all the xml tags stripped,
110
8300
My code is:
$dbh = new PDO('oci:dbname=tnsname,'username','password');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $dbh->prepare($sql);
$stmt->execute();
$result = $stmt->fetch();
array_shift($result);
//Create a new DOM document and load XML into its internal XML tree
$xml = new SimpleXMLElement($result[0]);
echo $xml->asXML();
print_r($result);
EDIT: Ended up with this, thanks for ThW.
header('Content-Type: application/xml; charset=utf-8');
echo '<employee>';
foreach ($result as $key=>$value)
{
echo $result->$key;
}
echo '</employee>';
Do not output a simple string with print_r(), use echo or print().
The browser does not strip your nodes, it just renders it as HTML. It ignores unknown elements and outputs the text nodes. Check the source view in the browser.
To make the browser recognize the XML, send the content type.
header('Content-Type: application/xml; charset=utf-8');
echo $result[0];

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.

Modify xml nodes using DOM or SIMPLE XML?

I have source XML here: http://www.grilykrby.cz/rss/pf-heureka.xml. I want to use this xml feed and create another modified on my own server. I would like to change every node CATEGORYTEXT which contains word Prislusenstvi. I just tried something but I got only the listing of all categories without changing XML :-(
Here is the example of my code. The row $kategorie="nejaka kategorie"; doesn't work.
<?php
$file = "http://www.grilykrby.cz/rss/pf-heureka.xml";
$xml=simplexml_load_file($file);
foreach ($xml->xpath('//SHOPITEM/CATEGORYTEXT') as $kategorie) {
echo $kategorie."<br />";
$kategorie="nejaka kategorie";
}
file_put_contents('test.xml', $xml->asXML());
?>
$kategorie is just a temp variable used in the loop which contains a copy of the data returned by xpath query. You would need to actually set the value directly in the $xml object.
I would personally also consider doing a str_replace or preg_replace within the XML content itself before parsing it into a simpleXML object.
Final Accepted Answer
<?php
$xml = simplexml_load_file('http://www.grilykrby.cz/rss/pf-heureka.xml');
$i=0;
foreach($xml -> SHOPITEM as $polozka) {
if ($polozka -> CATEGORYTEXT == "Příslušenství") $xml -> SHOPITEM[$i] -> CATEGORYTEXT = "Some other text";
$i++;
}
?>

Categories