php - Adding new node to an xml string - php

$result = "<QRYRESULT>
<ISSUCCESS>Y</ISSUCCESS>
<TRN_REF>2498297295729857927</TRN_REF>
<WARNING>IF ANY WARNING</WARNING>
</QRYRESULT>";
this is an XML string I am using. now I have to add a new node to this string (not a file). That is after adding the new node the XML string will look like the following. I am getting this XML string from another system in a variable so modifying the string manually is not an option.
$result = "<QRYRESULT>
<ISSUCCESS>Y</ISSUCCESS>
<TOKEN>some token</TOKEN>
<TRN_REF>2498297295729857927</TRN_REF>
<WARNING>IF ANY WARNING</WARNING>
</QRYRESULT>";
how can I do that ??

Use eg. simplexml
$xml = new SimpleXMLElement($yourstring);
$xml->addChild('node_name', 'node_value');
echo $xml->asXML();

A variant without using XML and consistency check:
$result=str_replace("</ISSUCCESS>","</ISSUCCESS><TOKEN>some token</TOKEN>",$result);

Related

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.

PHP: Keeping HTML inside XML node without CDATA

I've got an xml like this:
<father>
<son>Text with <b>HTML</b>.</son>
</father>
I'm using simplexml_load_string to parse it into SimpleXmlElement. Then I get my node like this
$xml->father->son->__toString(); //output: "Text with .", but expected "Text with <b>HTML</b>."
I need to handle simple HTML such as:
<b>text</b> or <br/> inside the xml which is sent by many users.
Me problem is that I can't just ask them to use CDATA because they won't be able to handle it properly, and they are already use to do without.
Also, if it's possible I don't want the file to be edited because the information need to be the one sent by the user.
The function simplexml_load_string simply erase anything inside HTML node and the HTML node itself.
How can I keep the information ?
SOLUTION
To handle the problem I used the asXml as explained by #ThW:
$tmp = $xml->father->son->asXml(); //<son>Text with <b>HTML</b>.</son>
I just added a preg_match to erase the node.
A CDATA section is a character node, just like a text node. But it does less encoding/decoding. This is mostly a downside, actually. On the upside something in a CDATA section might be more readable for a human and it allows for some BC in special cases. (Think HTML script tags.)
For an XML API they are nearly the same. Here is a small DOM example (SimpleXML abstracts to much).
$document = new DOMDocument();
$father = $document->appendChild(
$document->createElement('father')
);
$son = $father->appendChild(
$document->createElement('son')
);
$son->appendChild(
$document->createTextNode('With <b>HTML</b><br>It\'s so nice.')
);
$son = $father->appendChild(
$document->createElement('son')
);
$son->appendChild(
$document->createCDataSection('With <b>HTML</b><br>It\'s so nice.')
);
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<father>
<son>With <b>HTML</b><br>It's so nice.</son>
<son><![CDATA[With <b>HTML</b><br>It's so nice.]]></son>
</father>
As you can see they are serialized very differently - but from the API view they are basically exchangeable. If you're using an XML parser the value you get back should be the same in both cases.
So the first possibility is just letting the HTML fragment be stored in a character node. It is just a string value for the outer XML document itself.
The other way would be using XHTML. XHTML is XML compatible HTML. You can mix an match different XML formats, so you could add the XHTML fragment as part of the outer XML.
That seems to be what you're receiving. But SimpleXML has some problems with mixed nodes. So here is an example how you can read it in DOM.
$xml = <<<'XML'
<father>
<son>With <b>HTML</b><br/>It's so nice.</son>
</father>
XML;
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$result = '';
foreach ($xpath->evaluate('/father/son[1]/node()') as $child) {
$result .= $document->saveXml($child);
}
echo $result;
Output:
With <b>HTML</b><br/>It's so nice.
Basically you need to save each child of the son element as XML.
SimpleXML is based on the same DOM library internally. That allows you to convert a SimpleXMLElement into a DOM node. From there you can again save each child as XML.
$father = new SimpleXMLElement($xml);
$sonNode = dom_import_simplexml($father->son);
$document = $sonNode->ownerDocument;
$result = '';
foreach ($sonNode->childNodes as $child) {
$result .= $document->saveXml($child);
}
echo $result;

SaveXml in php returning empty string

I have the following xml :
<assumption_list>
<assumption name="test" id="23" description="test1" is_shared="no">
<watchlists>
<watchlist globalissuer="koolwater" prepayrate="5" prepaytype="CPR" defaultrate="5" defaulttype="CDR" lossrate="7" lagmonths="2"/>
</watchlists>
</assumption>
</assumption_list>
I load the following received from a jsp call in php as DOMDocument
I am trying the get the <watchlists> node as a string by using the following code :
$result = $xmlDoc->getElementsByTagName('watchlists');
$strxml='';
foreach($result as $element)
{
print_r(simplexml_import_dom($element));
$strxml = $xmlDoc->saveXML($element);
var_dump($strxml);
}
I do see my print_r(simplexml_import_dom($element)); this getting populated but for some reasons i see the empty string after the saveXml operation. Is there something wrong with the current implementation.
I am trying to get the xml string representation so that i can pass the xml string to c# dll used by php application
If you want to output the xml string representation, you can use a simple htmlentities() on this one. Consider this example: Sample Output
$xmlDoc = '<assumption_list> <assumption name="test" id="23" description="test1" is_shared="no"> <watchlists> <watchlist globalissuer="koolwater" prepayrate="5" prepaytype="CPR" defaultrate="5" defaulttype="CDR" lossrate="7" lagmonths="2"/> </watchlists> </assumption></assumption_list>';
$xmlDoc = simplexml_load_string($xmlDoc);
$result = $xmlDoc->assumption->watchlists->watchlist;
// echo $result->asXML(); // output as xml
echo htmlentities($result->asXML()); // output as xml string

PHP and XMLWriter

I was successfully using the following code to merge multiple large XML files into a new (larger) XML file. Found at least part of this on StackOverflow
$docList = new DOMDocument();
$root = $docList->createElement('documents');
$docList->appendChild($root);
$doc = new DOMDocument();
foreach(xmlFilenames as $xmlfilename) {
$doc->load($xmlfilename);
$xmlString = $doc->saveXML($doc->documentElement);
$xpath = new DOMXPath($doc);
$query = self::getQuery(); // this is the name of the ROOT element
$nodelist = $xpath->evaluate($query, $doc->documentElement);
if( $nodelist->length > 0 ) {
$node = $docList->importNode($nodelist->item(0), true);
$xmldownload = $docList->createElement('document');
if (self::getShowFileName())
$xmldownload->setAttribute("filename", $filename);
$xmldownload->appendChild($node);
$root->appendChild($xmldownload);
}
}
$newXMLFile = self::getNewXMLFile();
$docList->save($newXMLFile);
I started running into OUT OF MEMORY issues when the number of files grew as did the size of them.
I found an article here which explained the issue and recommended using XMLWriter
So, now trying to use PHP XMLWriter to merge multiple large XML files together into a new (larger) XML file. Later, I will execute xpath against the new file.
Code:
$xmlWriter = new XMLWriter();
$xmlWriter->openMemory();
$xmlWriter->openUri('mynewFile.xml');
$xmlWriter->setIndent(true);
$xmlWriter->startDocument('1.0', 'UTF-8');
$xmlWriter->startElement('documents');
$doc = new DOMDocument();
foreach($xmlfilenames as $xmlfilename)
{
$fileContents = file_get_contents($xmlfilename);
$xmlWriter->writeElement('document',$fileContents);
}
$xmlWriter->endElement();
$xmlWriter->endDocument();
$xmlWriter->flush();
Well, the resultant (new) xml file is no longer correct since elements are escaped - i.e.
<?xml version="1.0" encoding="UTF-8"?>
<CONFIRMOWNX>
<Confirm>
<LglVeh id="GLE">
<AddrLine1>GLEACHER &amp; COMPANY</AddrLine1>
<AddrLine2>DESCAP DIVISION</AddrLine2>
Can anyone explain how to take the content from the XML file and write them properly to new file?
I'm burnt on this and I KNOW it'll be something simple I'm missing.
Thanks.
Robert
See, the problem is that XMLWriter::writeElement is intended to, well, write a complete XML element. That's why it automatically sanitize (replace & with &, for example) the contents of what's been passed to it as the second param.
One possible solution is to use XMLWriter::writeRaw method instead, as it writes the contents as is - without any sanitizing. Obviously it doesn't validate its inputs, but in your case it does not seem to be a problem (as you're working with already checked source).
Hmm, Not sure why it's converting it to HTML Characters, but you can decode it like so
htmlspecialchars_decode($data);
It converts special HTML entities back to characters.

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