Accessing a single XML DOM Document node - php

I am completely new to DOM Documents, basically what I am trying to do, is to load a RSS feed in and select only one node, and then save it to a XML file.
Here is the XML I am loading from a web feed:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Markets</title>
<description/>
<link>http://www.website.com</link>
<language>en-us</language>
<copyright>XML Output Copyright</copyright>
<ttl>15</ttl>
<pubDate>Tue, 16 Nov 2010 09:38:00 +0000</pubDate>
<webMaster>admin#website.com</webMaster>
<image>
<title>title</title>
<url>http://www.website.com/images/xmllogo.gif</url>
<link>http://www.website.com</link>
<width>144</width>
<height>16</height>
</image>
<item>
<title>title</title>
<description>the description goes here
</description>
<enclosure url="http://www.website.com/images/image.png" type="image/png"/>
</item>
</channel>
</rss>
Here is my lame attempt at getting the <description> node and saving it to feed.xml:
<?php
$feed = new DOMDocument();
$feed->load('http://www.website.com/directory/directory/cz.c');
$nodeValue = $feed->getElementsByTagName('description')->item(0)->nodeValue;
$feed->save("feed.xml");
?>
So basically I need to get the description tag, and save it as a XML file.
Any help would be appreciated, thanx in advance!

Almost correct. To get the "outerXml" of a node, you can pass the node to saveXml()
$feed = new DOMDocument();
$feed->load('http://www.website.com/directory/directory/cz.c');
$xml = $feed->saveXml($feed->getElementsByTagName('description')->item(0));
file_put_contents("feed.xml", $xml);
Saving with file_put_contents will not include an XML prolog. Note that in your example, the first description element is empty, so the file will contain <description/>.
If you want to extract the node as standalone XML Document, you have to instantiate a new DOMDocument and import the DOMNode and then use save().
$dom = new DOMDocument($feed->xmlVersion, $feed->xmlEncoding);
$dom->appendChild(
$dom->importNode(
$feed->getElementsByTagName('description')->item(0),
TRUE
)
);
echo $dom->save('new.xml');

$feed = simplexml_load_file('feed.xml');
$descr=$feed->channel->description;
Try this

Related

PHP - Replace child node in XML

I want to replace a child node name in the XML through PHP and also want to append the text in the child node as well. Can you please help me to replace the child node name and append text in the same node in PHP?
PHP Code:
$doc = new DOMDocument;
$doc->load('abc.xml');
$thedocument = $doc->documentElement;
$xpath = new DOMXPath($doc);
// Need a code to replace the name of child node "<id>" to "<link>" and append text "abc.com/" in the node <id>
$doc->formatOutput = true;
$result1 = $doc->saveXML();
$doc->save('abc.xml');
XML (Current):
<rss>
<data>
<item>
<id>1122</id>
<title>Test 123</title>
</item>
</data>
</rss>
XML (Needed):
<rss>
<data>
<item>
<link>abc.com/?qs=1122</link>
<title>Test 123</title>
</item>
</data>
</rss>

PHP SimpleXML read comment with xPath

I'm loading a XML Feed, which works.
But it seems that I am missing something in my xpath query.
Actually I want to read the comment of the title node but it doesn't seem to work.
$xml = simplexml_load_file( $feed_url );
$comment = $xml->xpath('//channel/item[1]/title//comment()');
The feed has the following structure
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>My main feed</title>
<description>feed description</description>
<link>http://www.example.com</link>
<language>en_US</language>
<lastBuildDate>Wed, 26 Nov 2014 11:44:13 UTC</lastBuildDate>
<item>
<title><!-- Special Image --></title>
<link></link>
<guid>http://www.example.com/page/345</guid>
<media:category>horizontal</media:category>
<media:thumbnails>
<media:thumbnail url="www.example.com/test.jpg" type="image/jpeg" height="324" width="545" />
</media:thumbnails>
</item>
<item>
<title>Here's a normal title</title>
<description><![CDATA[Description Text]]></description>
<link></link>
<guid>http://www.example.com/page/123</guid>
<media:category>horizontal</media:category>
</item>
</channel>
</rss>
Does anyone have a clue how I could read the comment?
Alternatively, you could use DOMDocument to access those comments. Example:
$dom = new DOMDocument();
$dom->load($feed_url);
$xpath = new DOMXpath($dom);
$comment = $xpath->evaluate('string(//channel/item[1]/title/comment())');
echo $comment;

PHP+XML changing node order

I've made a simple news script that saves articles to rss which then gets used on the Character Generator Newsticker on TV, the problem is that the CG plays the nodes starting from the top of the rss file.
now the xml looks like this:
<?xml version="1.0" ?>
<rss version="2.0">
<channel>
<title>News</title>
<link>website.com</link>
<description>News</description>
<language>ar-sa</language>
<item>
<title>Headline 1</title>
<description>Headline one the news this hour</description>
</item>
<item>
<title>Headline 2</title>
<description>Fire here flooding over there</description>
</item>
<item>
<title>Headline 3</title>
<description>Fire here flooding over there</description>
</item>
</channel>
</rss>
What i would like todo is have an option to move articles up and down the xml file, so instead of having "Headline 3" third in the list i would like to move it up to be first.
I know with C# you can do this using:
XElement node = ...get the element...
//Move up
if (node.PreviousNode != null) {
node.PreviousNode.AddBeforeSelf(node);
node.Remove();
}
//Move down
if (node.NextNode != null) {
node.NextNode.AddAfterSelf(node);
node.Remove();
Anyone have an idea how i can do this in PHP?
Thanks!
You can have a look at this answer XML reforming with DOM where they use the DOM-parser to rearrange the XML

Parsing XML file

I've got a problem with parsing an XML file (nb. well formed one).
Consider XML file like this:
<?xml version="1.0" encoding="utf-8" ?>
<root>
<list>
<item no="1">
<title>Item's 1 title</title>
<content>Some long content with <special>tags</special> inside</content>
</item>
<item no="2">
<title>Item's 2 title</title>
<content>Some long content with <special>tags</special> inside</content>
</item>
</list>
</root>
I need to get contents contents of each item in the list and put them in an array. Generally not a problem, but in this case, I can't get my head round it.
Problem lays in <content> contents. It is string with tags in-between. I can't find a way to extract the contents. SimpleXML returns/echoes just the string with anything including and inside <special> tags stripped out. Like this:
Some long content with inside.
I'd ideally want it to get a string like this:
Some long content with <special>tags</special> inside
How do I get it?
You could use DOMDocument which is built into PHP.
<?php
$xml = <<<END
<?xml version="1.0" encoding="utf-8" ?>
<root>
<list>
<item no="1">
<title>Item's 1 title</title>
<content>Some long content with <special>tags</special> inside</content>
</item>
<item no="2">
<title>Item's 2 title</title>
<content>Some long content with <special>tags</special> inside</content>
</item>
</list>
</root>
END;
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->loadXML($xml);
$nodes = $doc->getElementsByTagName('content');
foreach ( $nodes as $node )
{
$temp_doc = new DOMDocument('1.0', 'UTF-8');
foreach ( $node->childNodes as $child )
$temp_doc->appendChild($temp_doc->importNode($child, true));
echo $temp_doc->saveHTML(); // Outputs: Some long content with <special>tags</special> inside
}
To select the top level "content" elements (in case there are "content" elements inside), you can use DOMXPath.
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->loadXML($xml); // $xml from the example above
$xpath = new DOMXPath($doc);
$nodes = $xpath->query('/root/list/item/content');
foreach ( $nodes as $node )
{
$temp_doc = new DOMDocument('1.0', 'UTF-8');
foreach ( $node->childNodes as $child )
$temp_doc->appendChild($temp_doc->importNode($child, true));
echo $temp_doc->saveHTML(); // Outputs: Some long content with <special>tags</special> inside
}
SimpleXML just doesn't support mixed content (text nodes with element nodes as siblings). I suggest you use XMLReader instead.
You could use SimpleXML's asXML function. It will return that called node as the xml string;
$xml = simplexml_load_file($file);
foreach($xml->list->item as $item) {
$content = $item->contents->asXML();
echo $content."\n";
}
will print:
<content>Some long content with <special>tags</special> inside</content>
<content>Some long content with <special>tags</special> inside</content>
it's a little ugly but you could then clip out the <content> and </content> with a substr:
$content = substr($content,9,-10);

Need to copy specific XML node from one doc to another

I have two XML files (that have a number of common nodes) that look a bit like these:
DESTINATION FILE: ('destination.xml')
<items>
<item>
<title>Item A</title>
<description>This is the description for Item A</description>
<id>1001</id>
</item>
<item>
<title>Item B</title>
<description>This is the description for Item B</description>
<id>1002</id>
</item>
<item>
<title>Item D</title>
<description>This is the description for Item D</description>
<id>1004</id>
</item>
and
SOURCE FILE: ('source.xml')
<items>
<item>
<title>Item A</title>
<description>This is the description for Item A</description>
<id>1001</id>
</item>
<item>
<title>Item C</title>
<description>This is the description for Item C</description>
<id>1003</id>
</item>
<item>
<title>Item B</title>
<description>This is the description for Item B</description>
<id>1002</id>
</item>
I need to grab the node from SOURCE with the 'id' matching '1003' (in this example) and import it into the DESTINATION. I'm looking for insight in using importNode (or a simpleXML option) and also the xpath in only getting only the node I need.
Just do that and it should work :
<?php
header('Content-type: application/xml'); //Just to test in the browser directly and have a good format
$docSource = new DOMDocument();
$docSource->loadXML(file_get_contents('source.xml'));
$docDest = new DOMDocument();
$docDest->loadXML(file_get_contents('destination.xml'));
$xpath = new DOMXPath($docSource);
$result = $xpath->query('//item[id=1003]')->item(0); //Get directly the node you want
$result = $docDest->importNode($result, true); //Copy the node to the other document
$items = $docDest->getElementsByTagName('items')->item(0);
$items->appendChild($result); //Add the copied node to the destination document
echo $docDest->saveXML();
To get the correct node, I think your XPath should look like this:
$xpath->query('/items/item/id[.="1003"]/..')
To import it to the other document, you'll need to create the document and call importNode with the second parameter set to true:
$newDom = new DOMDocument;
$newDom->load('destination.xml');
$newNode = $newDom->importNode($el, true);
$newDom->firstChild->appendChild($newNode);
file_put_contents('destination.xml', $newDom->saveXML());

Categories