Xml Append/Add new node php - php

I'm trying to update and add node to a xml file. Currently I can create and overwrite the file with my new node, however what I need to do is do to is add the new node to the existing file (.xml) and I am exhausted. I am new to php (I've tried all every code on this site and this is my current code can't be added here ... please Help
$doc = new DOMDocument;
// Load the XML
///$doc->loadXML("<root/>");
//---- ///$xml = new Document;
///$xml ->loadXML($xml);
//$xml = simplexml_load_file("pole.xml");
$title = $_POST["title"];
$xml = <<<XML <item> <title>$title</title> </item> XML;
$xml = new Document;
$xml ->loadXML($xml);
$xml ->appendXML($xml);
$xml = new SimpleXMLElement($xml);
echo $xml->saveXML('pole.xml');

I can offer no advice for using SimpleXML but as the above does attempt at using DOMDocument perhaps the following simple example will be of use.
$filename='pole.xml';
# Stage 1
# -------
// Create an instance of DOMDocument and then
// generate whatever XML you need using DOMDocument
// and save.
libxml_use_internal_errors( true );
$dom=new DOMDocument('1.0','utf-8');
$dom->formatOutput=true;
$dom->preserveWhiteSpace=true;
$root=$dom->createElement('Root');
$dom->appendChild( $root );
$item=$dom->createElement('Item');
$title=$dom->createElement('title','Hello World');
$item->appendChild( $title );
$root->appendChild( $item );
$dom->save( $filename );
$dom=null;
This yields the following XML:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Item>
<title>Hello World</title>
</Item>
</Root>
To then modify the XML file you have created or downloaded etc:
# Stage 2
# -------
// A new instance of DOMDocument is NOT strictly necessary here
// if you are continuing to work with the generated XML but for the purposes
// of this example assume stage 1 and stage 2 are done in isolation.
// Find the ROOT node of the document and then add some more data...
// This simply adds two new simple nodes that have various attributes
// but could be considerably more complex in structure.
$dom=new DOMDocument;
$dom->formatOutput=true;
$dom->preserveWhiteSpace=false;
$dom->load( $filename );
# Find the Root node... !!important!!
$root=$dom->getElementsByTagName('Root')->item(0);
# add a new node
$item=$dom->createElement('Banana','Adored by monkeys');
$attributes=array(
'Origin' => 'Central America',
'Type' => 'Berry',
'Genus' => 'Musa'
);
foreach( $attributes as $attr => $value ){
$attr=$dom->createAttribute( $attr );
$attr->value=$value;
$item->appendChild( $attr );
}
#ensure that you add the new node to the dom
$root->appendChild( $item );
#new node
$item=$dom->createElement('Monkey','Enemies of Bananas');
$attributes=array(
'Phylum' => 'Chordata',
'Class' => 'Mammalia',
'Order' => 'Primates'
);
foreach( $attributes as $attr => $value ){
$attr=$dom->createAttribute( $attr );
$attr->value=$value;
$item->appendChild( $attr );
}
$root->appendChild( $item );
$dom->save( $filename );
$dom=null;
This modifies the XML file and yields the following:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Item>
<title>Hello World</title>
</Item>
<Banana Origin="Central America" Type="Berry" Genus="Musa">Adored by monkeys</Banana>
<Monkey Phylum="Chordata" Class="Mammalia" Order="Primates">Enemies of Bananas</Monkey>
</Root>

Related

How to add content to xml with PHP?

I want to copy the content from the PHP file into XML:
$channel = "15";
$start = "20180124021100 +0200";
$stop = "20180124031500 +0200";
$title = "news";
$desc = "show number 50";
I need to do later loop and add more channels, so I do not want only to edit the XML,
I want to open the XML file and add the PHP content to the page in a specific location:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<channel id="1">
<display-name lang="he">1</display-name>
</channel>
// I want the content to stick to the end
<programme start="$start" stop="$stop" channel="$number">
<title lang="he">$title</title>
<desc lang="he">$desc</desc>
</programme>
// And that the next loop will be the same, will paste the content to the end as well:
<programme start="$start" stop="$stop" channel="$number">
<title lang="he">$title</title>
<desc lang="he">$desc</desc>
</programme>
Rather than using strings to build the XML you ought to look at one of the existing classes to do all the heavy lifting - they are after all designed for this purpose. Looking at the xml in the question it does not appear valid XML as there is no root node for the content. The following ought to help get started.
<?php
$channel = "15";
$start = "20180124021100 +0200";
$stop = "20180124031500 +0200";
$title = "news";
$desc = "show number 50";
/* file path to saved xml document */
$xmlfile= __DIR__ . '/xmlfile.xml';
/* whether to display XML in browser or simply save */
$displayxml=true;
/* create DOMDocument and set args */
$dom=new DOMDocument('1.0','utf-8');
$dom->standalone=true;
$dom->formatOutput=true;
$dom->recover=true;
$dom->strictErrorChecking=true;
/* a ROOT node for the document */
$rootnode='programmes';
/* if the file already exists, open it */
if( realpath( $xmlfile ) ){
$dom->load( $xmlfile );
$root=$dom->getElementsByTagName( $rootnode )->item(0);
} else {
/* File does not exist, create root elements & content */
$root=$dom->createElement( $rootnode );
$dom->appendChild( $root );
$ochan=$dom->createElement('channel');
$ochan->setAttribute('id',1);
$root->appendChild( $ochan );
$odisp=$dom->createElement('display-name',1);
$odisp->setAttribute('lang','he');
$ochan->appendChild( $odisp );
}
/* process variables for new record/programme */
if( isset( $channel, $start, $stop, $title, $desc ) ){
$oprog=$dom->createElement('programme');
$root->appendChild( $oprog );
$oprog->setAttribute('start',$start);
$oprog->setAttribute('end',$stop);
$oprog->setAttribute('channel',$channel);
$otitle=$dom->createElement('title',$title);
$oprog->appendChild($otitle);
$otitle->setAttribute('lang','he');
$odescr=$dom->createElement('desc',$desc);
$oprog->appendChild($odescr);
$odescr->setAttribute('lang','he');
}
/* save the file */
$dom->save( $xmlfile );
/* if you want to see the generated xml in the browser */
if( $displayxml ){
header('Content-Type: application/xml');
echo $dom->saveXML();
}
?>
SimpleXML for PHP is fairly simple to use, either for reading or writing XML. In this question How to convert array to SimpleXML you can find a number of suggestions on using SimpleXML in PHP. Documentation can be found here: https://secure.php.net/manual/en/book.simplexml.php

php DOMDocument - Get outer node and Protect <![CDATA[]] blocks as string

I have a xml file and some of it nodes has a CDATA Block like this:
<item>
<content>OneWord</content>
</item>
<item>
<content><![CDATA[Some Text or Serialized arrays]]></content>
</item>
And I tried to get outer node as bellow:
$file = 'file.xml';
$contents = file_get_contents( $file );
$dom = new DOMDocument( '1.0', 'utf-8' );
$dom->loadXML( $contents, LIBXML_NOCDATA );
$xpath = new DOMXPath( $dom );
// -- get outer
$item = $xpath->query( './item' )->item(1);
$str = $dom->saveXML($item);
var_dump($str);
And it print item node without CDATA block but I want that node has CDATA Blocks.
Thanks
Is it not as simple as removing the LIBXML_NOCDATA option ("Merge CDATA as text nodes")?
For me,
$dom = new DOMDocument( '1.0', 'utf-8' );
$dom->loadXML( $contents );
$xpath = new DOMXPath( $dom );
// -- get outer
$item = $xpath->query( './item' )->item(1);
$str = $dom->saveXML($item);
var_dump($str);
outputs
string '<item>
<content><![CDATA[Some Text or Serialized arrays]]></content>
</item>' (length=78)

Plesk XML formatting

In PHP i have this code for making a XML header for the plesk API.
$request = <<<EOF
<packet version="1.6.7.0">
<mail>
<update>
<set>
<filter>
<site-id>$site_id</site-id>
<mailname>
<name>$name</name>
<autoresponder>
<enabled>true</enabled>
<subject>$subject</subject>
<text>$mail_body</text>
<end_date>$date</end_date>
</autoresponder>
</mailname>
</filter>
</set>
</update>
</mail>
</packet>
EOF;
However i get this response: 1014 Parser error: Cannot parse the XML from the source specified
I have put the xml into a formatting of 2, 3 ,4 and tab spacing and it doesnt seem to be able to parse it.
What am i doing wrong?
You can't guess to create a valid XML by string concatenation, especially when you have complex contents like an email text.
No all characters are allowed inside XML tags: you have to properly escape not-allowed characters. Fortunately, php have some parser that do this job for you.
First of all, create an empty XML template (check its validity using a XML validator):
$xml = '<?xml version="1.0" encoding="utf-8" ?>
<packet version="1.6.7.0">
<mail>
<update>
<set>
<filter>
<site-id/>
<mailname>
<name/>
<autoresponder>
<enabled/>
<subject/>
<text/>
<end_date/>
</autoresponder>
</mailname>
</filter>
</set>
</update>
</mail>
</packet>
';
Then, load it into a DOMDocument object and init a DOMXPath object:
$dom = new DomDocument();
$dom->loadXML( $xml );
$xpath = new DOMXPath( $dom );
Then, find each node that you want to change and set/update its node value:
$nodes = $xpath->query( 'mail/update/set/filter/site-id' );
$nodes->item(0)->nodeValue = $site_id;
$nodes = $xpath->query( 'mail/update/set/filter/mailname/name' );
$nodes->item(0)->nodeValue = $name;
For the <autoresponder> children, you can perform a loop through each child, using * at the end of your search pattern:
$nodes = $xpath->query( 'mail/update/set/filter/mailname/autoresponder/*' );
foreach( $nodes as $node )
{
if( 'enabled' == $node->nodeName )
{
$node->nodeValue = 'true';
}
elseif( 'subject' == $node->nodeName )
{
$node->nodeValue = $subject;
}
elseif( 'text' == $node->nodeName )
{
$cdata = $dom->createCDATASection( $mail_body );
$node->appendChild( $cdata );
}
elseif( 'end_date' == $node->nodeName )
{
$node->nodeValue = $date;
}
}
Note the different syntax adopted for mail body: I use a CDATA node here: if your XML doesn't allow CDATA, replace it with standard ->nodeValue syntax. Or — instead — you can have to use CDATA method for all the nodes.
When the XML is ready, you can echo it by:
echo $dom->saveXML();
DOMXPath allow to perform complex searches in the XML tree: it's not mandatory in your case, because you start from a short, empty, unambiguous template. I use it for demonstration purpose, but you can replace a line like this:
$nodes = $xpath->query( 'mail/update/set/filter/site-id' );
with:
$nodes = $dom->getElementsByTagName( 'site-id' );
and it will work fine.
Read more about DOMDocument
Read more about DOMXPath

XML edit in php

In an xml file I have this structure (with <post>repeating) :
<data>
<post>
<deal_id>479</deal_id>
<deal_title><![CDATA[Δίπλωμα Μηχανής, στη Σχολή Οδηγών Παραστατίδης στον Εύοσμο, μόνο με 49€]]></deal_title>
<deal_url>http://domain.com/site/shop/autokinito-el/diplwma-mixanis-sxoli-odigwn-parastatidis-euosmos/</deal_url>
<deal_city><![CDATA[Θεσσαλονίκη]]></deal_city>
<deal_price><![CDATA[49]]></deal_price>
<deal_previous_price><![CDATA[125]]></deal_previous_price>
<deal_discount><![CDATA[60.8]]></deal_discount>
<deal_start><![CDATA[2016-01-10 00:00:00]]></deal_start>
<deal_end><![CDATA[2016-04-01 00:00:00]]></deal_end>
<deal_image>
<image>
<file>http://domain.com/site/wp-content/uploads/2015/09/c700x420.jpg</file>
<title>c700x420</title>
<caption></caption>
<description></description>
<alt></alt>
</image>
<image>
<file>http://domain.com/site/wp-content/uploads/2015/09/diploma1.jpg</file>
<title>diploma1</title>
<caption></caption>
<description></description>
<alt></alt>
</image>
</deal_image>
<deal_sales><![CDATA[0]]></deal_sales>
<deal_active><![CDATA[true]]></deal_active></post></data>
and I would like to transform the <deal_image> to
<deal_image>http://domain.com/site/wp-content/uploads/2015/09/c700x420.jpg</deal_image>
which means keep only the first appearing jpg and discard the rest..and do that for all <post>
How can I do that with php?
So the desired output would be something like this:
<data>
<post>
<deal_id>479</deal_id>
<deal_title><![CDATA[Δίπλωμα Μηχανής, στη Σχολή Οδηγών Παραστατίδης στον Εύοσμο, μόνο με 49€]]></deal_title>
<deal_url>http://domain.com/site/shop/autokinito-el/diplwma-mixanis-sxoli-odigwn-parastatidis-euosmos/</deal_url>
<deal_city><![CDATA[Θεσσαλονίκη]]></deal_city>
<deal_price><![CDATA[49]]></deal_price>
<deal_previous_price><![CDATA[125]]></deal_previous_price>
<deal_discount><![CDATA[60.8]]></deal_discount>
<deal_start><![CDATA[2016-01-10 00:00:00]]></deal_start>
<deal_end><![CDATA[2016-04-01 00:00:00]]></deal_end>
<deal_image>http://domain.com/site/wp-content/uploads/2015/09/c700x420.jpg</deal_image>
<deal_sales><![CDATA[0]]></deal_sales>
<deal_active><![CDATA[true]]></deal_active></post></data>
Note that the deal_image tag kept only the url of the first image and ignored the rest. In my xml file there are lots of <post></post> sections, which should also be processed in an iteration.
First we remove all image childs of deal_image, then we assign the image value to deal_image
<?php
$dom = new DOMDocument();
$dom->formatOutput = true;
$dom->loadXML('<data>
<post>
<deal_id>479</deal_id>
<deal_title><![CDATA[Δίπλωμα Μηχανής, στη Σχολή Οδηγών Παραστατίδης στον Εύοσμο, μόνο με 49€]]></deal_title>
<deal_url>http://domain.com/site/shop/autokinito-el/diplwma-mixanis-sxoli-odigwn-parastatidis-euosmos/</deal_url>
<deal_city><![CDATA[Θεσσαλονίκη]]></deal_city>
<deal_price><![CDATA[49]]></deal_price>
<deal_previous_price><![CDATA[125]]></deal_previous_price>
<deal_discount><![CDATA[60.8]]></deal_discount>
<deal_start><![CDATA[2016-01-10 00:00:00]]></deal_start>
<deal_end><![CDATA[2016-04-01 00:00:00]]></deal_end>
<deal_image>
<image>
<file>http://domain.com/site/wp-content/uploads/2015/09/c700x420.jpg</file>
<title>c700x420</title>
<caption></caption>
<description></description>
<alt></alt>
</image>
<image>
<file>http://domain.com/site/wp-content/uploads/2015/09/diploma1.jpg</file>
<title>diploma1</title>
<caption></caption>
<description></description>
<alt></alt>
</image>
</deal_image>
<deal_sales><![CDATA[0]]></deal_sales>
<deal_active><![CDATA[true]]></deal_active></post></data>');
$featuredde1 = $dom->getElementsByTagName('image');
foreach ($featuredde1 as $node) {
$node->parentNode->removeChild($node);
}
foreach ($featuredde1 as $node) {
$node->parentNode->removeChild($node);
}
$data = $dom->getElementsByTagName( "deal_image" );
$data ->item(0)->nodeValue = "http://domain.com/site/wp-content/uploads/2015/09/c700x420.jpg";
echo $dom->saveXML();
DEMO
http://ideone.com/HlrKM4
You can use DOMDocument with DOMXPath:
$dom = new DOMDocument();
$dom->loadXML( $xml, LIBXML_NOBLANKS );
$xpath = new DOMXPath( $dom );
foreach( $xpath->query( '/data/post/deal_image' ) as $deal_image )
{
$value = $xpath->query( './image/file', $deal_image )->item(0)->nodeValue;
$new_node = $dom->createElement( 'deal_image', $value );
$deal_image->parentNode->replaceChild( $new_node, $deal_image );
}
$dom->formatOutput = True;
echo $dom->saveXML().PHP_EOL;
($xml is your XML string; if you want load XML directly from a file, you can use $dom->load( $filePath ) instead of $dom->loadXML( $xml ) )
After init of DOMDocument and DOMXPath, the foreach loop examine all <deal_image> nodes, find the value of first <image><file>, create a new <deal_image> with this found value and replace old <deal_image> with the new created.
In the demo above I have added two more <post> to test the behavior with 1 or 3 images.
See more about DOMDocument
See more about DOMXPath

Php write XML file (to JW player)

I use the JW player to load a XML playlist. It works fine when I manually write the XML file, but not when I use php to parse...
I want it to look like this:
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:jwplayer="http://developer.longtailvideo.com/trac/">
<channel>
<item>
<title>Albert</title>
<media:content url="../movies/hi.mp4" />
<description></description>
<jwplayer:duration>10</jwplayer:duration>
</item>
</channel>
</rss>
The first problem is the <rss version="2.0" ...
It forces the headers to be: <?xml version="1.0"?>
The second problem is the <media:content url="" ...
How can I print out that with php ?
The third problem is how to add the end rss </rss>
My code is:
<?php
$channel = array();
$channel [] = array(
'title' => 'Albert',
'content' => 'filmer/c1.jpg',
'duration' => "10"
);
$channel [] = array(
'title' => 'Claud',
'content' => 'filmer/c2.jpg',
'duration' => "10"
);
$doc = new DOMDocument();
$doc->formatOutput = true;
$r = $doc->createElement( "channel" );
$doc->appendChild( $r );
foreach( $channel as $item )
{
$b = $doc->createElement( "item" );
$title = $doc->createElement( "title" );
$title->appendChild(
$doc->createTextNode( $item['title'] )
);
$b->appendChild( $title );
$content = $doc->createElement( "media:content" );
$content->appendChild(
$doc->createTextNode( $item['content'] )
);
$b->appendChild( $content );
$duration = $doc->createElement( "jwplayer:duration" );
$duration->appendChild(
$doc->createTextNode( $item['duration'] )
);
$b->appendChild( $duration );
$r->appendChild( $b );
}
echo $doc->saveHTML();
$doc->save("write.xml")
?>
Any ideas?
I'm a newbie in PHP/XML, sorry :/
This line: <?xml version="1.0"?> is called XML Declaration and it is optional. So whether that line is there or not should not make any difference and pose any problems as long as you use valid XML.
As RSS is based on XML, you do not need to worry about that line being there.
I hope this clarifies this part of your question.
And as Q&A normally works best with one question each, here are those other two:
remove xml version tag when a xml is created in php / PHP DomDocument output without <?xml version=“1.0” encoding=“UTF-8”?>
Generate XML with namespace URI in PHP
It's necessary to put a header before the php code in the xml to inform jwplayer what's being loaded.
header("Content-type: text/xml");

Categories