append XML literal to DOMDocument in php without escaping - php

I have a string that represents nodes I'd like to append to a DOMDocument in PHP, but when I add it as a value to an element, it gets escaped. Is there a way to append a chunk of XML to a DOMDocument without it getting escaped - and with the one string addition, several nodes getting added?
Here's an example of what I'm trying to do:
$string = <<<XML
<myNode>
<OtherNode>value</OtherNode>
</myNode>
XML;
$domDoc = new DOMDocument();
$xml_id = $domDoc->createElement('mydata');
$value = $domDoc->createTextNode($string);
$xml_id->appendChild($value);
$subNode = $domDoc->appendChild($xml_id);
echo $domDoc->saveXML();
Currently, however the output looks like this:
<?xml version="1.0"?>
<mydata> <myNode>
<OtherNode>value</OtherNode>
</myNode></mydata>
Is there a way to make it look like this?
<?xml version="1.0"?>
<mydata>
<myNode>
<OtherNode>value</OtherNode>
</myNode>
</mydata>

if I'm not incorrect, you actually should create a documentFragment and append the XML literal to that. Then you should append the documentFragment to the $xml_id and then you should append $xml_id to the $domDoc
$domDoc = new DOMDocument();
$xml_id = $domDoc->createElement('mydata');
$frag = $domDoc->createDocumentFragment();
$frag->appendXML($string);
$xml_id->appendChild($frag);
$domDoc->appendChild($xml_id);

Related

PHP DOMDocument not being able to create <image></image>-tag

I'm trying to use DOMDocument in PHP to create an XML-document containing an element formated like this:
<image>
<url>
http://webpage.com/images/img.jpg
</url>
</image>
The problem is that it gets converted to this:
<img>
<url><img></url>
Does it have something to do with the image tag name being reserved, since it defaults to a normal HTML tag.
My current code snippet for this:
$frag = $domtree->createDocumentFragment();
$frag->appendXML('<image>\n<url></url></image>');
$listing->appendChild($frag);
You're source is incomplete. The creation of the document object and the $listing node is missing and here is no output. Fixing that it works fine:
$document = new DOMDocument();
$fragment = $document->createDocumentFragment();
$fragment->appendXML('<image>\n<url>http://webpage.com/images/img.jpg</url></image>');
$document->appendChild($fragment);
echo $document->saveXML();
Output:
<?xml version="1.0"?>
<image>\n<url>http://webpage.com/images/img.jpg</url></image>
PHP will not recognize \n as a linefeed inside a single quoted string. It only supports that in double quoted strings.
Creating XML from fragments is fine, but most of the time you might want to create the
nodes directly:
$document = new DOMDocument();
$document->appendChild($image = $document->createElement('image'));
$image->appendChild($url = $document->createElement('url'));
$url->appendChild($document->createTextNode('http://webpage.com/images/img.jpg'));
echo $document->saveXML();
Output:
<?xml version="1.0"?>
<image><url>http://webpage.com/images/img.jpg</url></image>

How to append XML data without overwriting?

I'm in the process of writing an XML file:
<?php
$xml2 = "currenttest";
$xml = new DOMDocument("1.0");
$root = $xml->createElement ('tv');
$xml->appendChild($root);
$root->appendChild($xml->createTextNode("\n"));
$root->appendChild($xml->createTextNode($xml2));
$root->appendChild($xml->createTextNode("\n"));
$xml->save('epg.xml');
XML:
<?xml version="1.0"?>
<tv>
test
</tv>
If i change the text and again runs the code, the old content is deleted.
And I want the old text to stay.
Let's say this:
<?xml version="1.0"?>
<tv>
currenttest...
newtest...
</tv>
My previous way was to write the XML with:
file_put_contents($file, $xml2, FILE_APPEND | LOCK_EX);
FILE_APPEND | LOCK_EX, its helped me that the previous text would not be erased
I found a solution in another post:
$doc->loadXML(file_get_contents('epg.xml'));
foreach($doc->getElementsByTagName('***') as $node)
{
}
But how can it fit into my code?
You have nothing particular to do, just to reload your xml string and to append a new text node to your root element:
// your previous code (I only changed the variable names and added a default encoding)
$text = "currenttest";
$dom = new DOMDocument("1.0", "UTF-8");
$root = $dom->createElement('tv');
$dom->appendChild($root);
$root->appendChild($dom->createTextNode("\n"));
$root->appendChild($dom->createTextNode($text));
$root->appendChild($dom->createTextNode("\n"));
$xml = $dom->saveXML();
// let's add a new element
$newtext = 'newtext';
$dom = new DOMDocument;
$dom->loadXML($xml);
$root = $dom->documentElement; // conveniant way to target the root element
// but you can also write:
//$root = $dom->getElementsByTagName('tv')->item(0);
$root->appendChild($dom->createTextNode($newtext));
$newxml = $dom->saveXML();
echo $newxml;
demo
About $doc->loadXML(file_get_contents('epg.xml'));, note that you don't need to use file_get_contents since DOMDocument has already two methods:
DOMDocument::loadXML that loads the xml content from a string.
DOMDocument::load that loads the xml content directly from a file.
In addition to DOMNode::appendChild that adds a node to an element after all the children nodes of this element, you have also DOMNode::insertBefore to add a node to an element before the child node of your choice.
I tryed the code on top, 'cause i was overwriting my data, but when I coded in my application, it didn't worked cause I was trying to add the new node data in the loaded xml, you have to create a root to add data inside.
$xml = new DOMDocument("1.0", "UTF-8");
//an tag root must be first thing to add
$root = $xml->createElement('root');
$xml->appendChild($root);
Then, just add the data when you need
$xml = new DOMDocument("1.0", "UTF-8");
$xml->load($sFilepath);
$root = $xml->getElementsByTagName('root')->item(0);
your structure must looks like this:
<xml version="1.0" encoding="UTF-8">
<root>
</root>
The answer on top is totally correct. This answer is only to help if somebody is having trouble to understand.

createCDATASection is undefined when generating XML

I'm trying to generate an xml file using PHP, with the the description element being placed on a CDATA.
<?php
$title = "Volvo";
$description = "this is a test description";
$xml = new SimpleXMLElement('<xml/>');
$track = $xml->addChild('blog');
$post = $track->addChild('post');
$post->addChild('title',$title);
$cdata = createDATASection($description);
$post->addChild('description',$cdata);
$xml->asXml();
?>
Am I using createDATASection correctly? I have also tried other ways but I am still not getting it.
createCDATASection() is a method of the DOMDocument. SimpleXML itself is limited. If you need that much control (like creating specific node types) you will have to use DOM. SimpleXML treats the XML as a tree of just elements. In DOM everything is a node, elements, texts, attributes, comments, ...
In DOM the create and the append are separate. You create an new node (of any type) with the corresponding method of DOMDocument then you append it using the method of the parent node. The append methods will return the node, so you can nest calls.
Here is your example source converted to DOM API calls:
$title = "Volvo";
$description = "this is a test description";
$document = new DOMDocument();
$xml = $document
->appendChild($document->createElement('xml'));
$blog = $xml
->appendChild($document->createElement('blog'));
$track = $blog
->appendChild($document->createElement('track'));
$post = $track
->appendChild($document->createElement('post'));
$post
->appendChild($document->createElement('title'))
->appendChild($document->createTextNode($title));
$post
->appendChild($document->createElement('description'))
->appendChild($document->createCDATASection($description));
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<xml>
<blog>
<track>
<post>
<title>Volvo</title>
<description><![CDATA[this is a test description]]></description>
</post>
</track>
</blog>
</xml>

php parsing xml formatted data

I'm trying to parse an xml data that I'm getting via an api call. I can use file_get_contents to read into a string but simpleXML_load_string seems to fail to read it. I can save it to a file and then simpleXML_load_file works. But I would rather not write the contents to a file. I can't seem to understand how to use DOM or XMLParse with this either. I'm new to PHP and parsing XML. The output data from the api call is below.
<Search>
<DS_Rating>DS3</DS_Rating>
<Overall>17.5</Overall>
<LargestGiftLow>0</LargestGiftLow>
<LargestGiftHigh>0</LargestGiftHigh>
<EstimatedCapacityRange>I - $15,000 - $24,999</EstimatedCapacityRange>
<EstimatedCapacity>20452</EstimatedCapacity>
<RealEstateEst>270073</RealEstateEst>
<RealEstateCount>1</RealEstateCount>
<LikelyMatchesCount>0</LikelyMatchesCount>
<LikelyMatchesTotal>0</LikelyMatchesTotal>
<FndBoard></FndBoard>
<GSBoard></GSBoard>
<PoliticalLikelyCount>0</PoliticalLikelyCount>
<PoliticalLikelyTotal>0</PoliticalLikelyTotal>
<BusinessRevenues>0</BusinessRevenues>
<SECStockValue>0</SECStockValue>
<SECInsider></SECInsider>
<MarketGuide></MarketGuide>
<IRS990PF></IRS990PF>
<RealEstateTrust></RealEstateTrust>
<MarketGuideComp>0</MarketGuideComp>
<MarketGuideOptions>0</MarketGuideOptions>
<BusinessAffiliation></BusinessAffiliation>
<Pension></Pension>
<PensionAssets>0</PensionAssets>
<CorpTech></CorpTech>
<Pilot></Pilot>
<AirplaneOwner></AirplaneOwner>
<Boat></Boat>
<submit_time>2014-03-11 15:48:45</submit_time>
</Search>
Figured out that the issue was that what I was seeing in the browser was actually a php output with html_entiity encoded. I was able to process it with the code below which let me load it with simplexml.
$rawxml = html_entity_decode($rawxml);
$rawxml = str_replace(array(' ', "<pre>"), '', $rawxml);
$rawxml = utf8_encode($rawxml);
$xml = simplexml_load_string($rawxml);
If you XML is in a file use
simplexml_load_file
if you have it in a string use
simplexml_load_string
Then you can use the following code to access it.
<?php
$yourxml = simplexml_load_file('your.xml');
echo $yourxml->search[0]->DS_Rating;
?>
This would then output
DS3
to the browser via the 'echo' in your code. I hope this points you in the correct direction.
Try to use this:
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?>'.$yourXMLString);
In DOM you load the XML into a DOMDocument and create a DOMXpath instance for it.
$dom = new DOMDocument();
$dom->loadXml($xmlString);
//$dom->load($xmlFile);
$xpath = new DOMXpath($dom);
DOMXpath::evaluate() is used to fetch data from the DOM.
$rating = $dom->evaluate('string(/Search/DS_Rating)');
An Xpath expression like /Search/DS_rating always returns a node list. You can use foreach() to iterate it. The string() function in Xpath takes the first node from the list and casts it into a string. If here is not node in the list the result is an empty string.
$xmlString = <<<'XML'
<Search>
<DS_Rating>DS3</DS_Rating>
<Overall>17.5</Overall>
</Search>
XML;
$dom = new DOMDocument();
$dom->loadXml($xmlString);
$xpath = new DOMXpath($dom);
var_dump(
$xpath ->evaluate('string(/Search/DS_Rating)')
);
Output: https://eval.in/118921
string(3) "DS3"

easy xpath query but no results

Trying to get all URLs values from xml.
I have hundreds of entry exactly in the form like e.g. this entry 16:
<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entries>
<entry id="16">
<revision number="1" status="accepted" wordclass="v" nounclasses="" unverified="false"></revision>
<media type="audio" url="http://website.com/file/65.mp3" />
</entry>
<entry id="17">
....
</entry>
</entries>
</root>
I am using this code but cannot get it to work. Why?
$doc = new DOMDocument;
$doc->Load('data.xml');
$xpath = new DOMXPath($doc);
$query = '//root/entries/entry/media';
$entries = $xpath->query($query);
What is the correc query for that? Best would be to only get the url value.
Your query probably returns the proper elements, but by default gives you the content of the media tag ( which in your case are empty, since the tag is self-closing ).
To get the url attribute of the tag you should use getAttribute(), example :
$entries = $xpath->query('//root/entries/entry/media');
foreach($entries as $entry) {
print $entry->getAttribute("url")."<br/>";
}
Or you should just xpath-query the attribute instead and read out it's value:
$urlAttributes = $xpath->query('//root/entries/entry/media/#url');
#####
foreach ($urlAttributes as $urlAttribute)
{
echo $urlAttribute->value, "<br/>\n";
#####
}
See DOMAttr::$valueDocs:
value
The value of the attribute
I would do that with SimpleXML actually:
$file = 'data.xml';
$xpath = '//root/entries/entry/media/#url';
$xml = simplexml_load_file($file);
$urls = array();
if ($xml) {
$urls = array_map('strval', $xml->xpath($xpath));
}
Which will give you all URLs as strings inside the $urls array. If there was an error loading the XML file, the array is empty.

Categories