How to sort xml based on attribute value - php

$books = new DOMDocument();
$books->load( 'books.xml' );
$id = $_GET['id'];
$xml = '<?xml version="1.0" encoding="UTF-8"?>';
$xml .= '<results><course>'.$id.'</course>';
$xml .= '<books>';
$items = $books->getElementsByTagName("item");
foreach( $items as $item )
{
$item_id = $item->getAttribute("id");
if($id == $item_id){
....
}
}
$xml .= '</books></results>';
header ("Content-Type:text/xml");
echo ($xml);
My code above will return me :
<results>
<course>1111</course>
<books>
<isbn id="0134582667" common="10" before="4" same="1" after="5" total="248"/>
.....
</books>
</results>
This page contains the following errors:
error on line 772 at column 12: XML declaration allowed only at the
start of the document Below is a rendering of the page up to the first
error.

You could get you items into an array, and then sort the array, something like this...
books.xml
<?xml version="1.0"?>
<results>
<course>1111</course>
<books>
<isbn id="0134582667" common="10" before="4" same="1" after="5" total="248">248</isbn>
<isbn id="0134582667" common="10" before="4" same="1" after="5" total="3">3</isbn>
<isbn id="0134582667" common="10" before="4" same="1" after="5" total="224">224</isbn>
<isbn id="0134582667" common="10" before="4" same="1" after="5" total="25">25</isbn>
</books>
</results>
test.php
$books = new DOMDocument();
$books->load( 'books.xml' );
$items = $books->getElementsByTagName("isbn");
$nodeArray = array();
foreach ($items as $item) {
$nodeArray[$item->getAttribute('total')] = $item;
}
ksort($nodeArray);
echo "<pre>". print_r($nodeArray, true) ."</pre>";

Related

create one in xml with php multiple inputs with same name

I have an XML file in which one child has two categories, but with the same name. I want to add one title to each one. How can we do it in PHP?
This is my XML
<root>
<result>
<node>
<title> Some Title Name</title>
<categories>
<category> categor_one </category>
<category> categor_two </category>
</categories>
</node>
<node>
<title> Some Title Name</title>
<categories>
<category> categor_one </category>
<category> categor_tree </category>
</categories>
</node>
</result>
</root>
But I want to obtain this
<root>
<result>
<node>
<title> Some Title Name</title>
<category>categor_one///categor_two </category>
<category1>categor_one///categor_tree</category1>
</node>
</result>
</root>
I managed to impement a function that only gets correctly the category, but if the title is the same it doesn't work as it just creates a new one.
function solve_something($xml, $destination)
{
$xml = simplexml_load_file($xml, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$items = json_decode($json, TRUE);
$products = array();
$product_data = array();
foreach($items['result']['node'] as $item){
$product_data['title'] = $item['title'];
foreach ($item['categories'] as $category) {
if (is_array($category)) {
$product_data['category'] = implode('///', $category);
} else {
$product_data['category'] = $category;
}
}
$products[] = $product_data;
unset($product_data);
}
$path = createXML($products, $destination);
return $path;
}
function createXML($data, $destination)
{
$xmlDoc = new DOMDocument('1.0', 'UTF-8');
$root = $xmlDoc->appendChild($xmlDoc->createElement("root"));
foreach ($data as $key => $product) {
$productA = $root->appendChild($xmlDoc->createElement('product'));
foreach ($product as $key1 => $val) {
if (!empty($val)) {
if ($key1 == 'price' || $key1 == 'tax' || $key1 == 'stockAmount') {
$productA->appendChild($xmlDoc->createElement($key1, $val));
} else {
$ProductKey = $productA->appendChild($xmlDoc->createElement($key1));
$ProductKey->appendChild($xmlDoc->createCDATASection($val));
}
}
}
}
$xmlDoc->formatOutput = true;
fn_rm($destination);
$xmlDoc->save($destination);
return $destination;
}
The output of my code is something like this
<root>
<product>
<title> Some Title Name</title>
<category>categor_one///categor_two </category>
</product>
<product>
<title> Some Title Name</title>
<category>categor_one///categor_tree</category>
</product>
</root>
If you want to keep the data together with the same title, one approach could be to collect that data upfront by using the title as an array key (if it is a valid array key)
When you create the xml, you have the title in the outer foreach loop as the key, and in the inner foreach you can create elements using implode.
Note that in your code you started using product so I took that as a node name.
Example code, which you could use in your code:
$products = array();
$product_data = array();
$xml = simplexml_load_file($xml, "SimpleXMLElement", LIBXML_NOCDATA);
foreach ($xml->result->node as $node) {
$product_data['title'] = (string)$node->title;
foreach($node->categories as $category) {
if (is_array($category)) {
$product_data['category'] = implode('///', $category);
continue;
}
$product_data['category'] = (array)$category->category;
}
$products[(string)$node->title][] = $product_data;
}
$xmlDoc = new DOMDocument('1.0', 'UTF-8');
$root = $xmlDoc->appendChild($xmlDoc->createElement("root"));
foreach ($products as $key => $product) {
$productA = $root->appendChild($xmlDoc->createElement('product'));
$productA->appendChild($xmlDoc->createElement("title", $key));
for ($i = 0; $i < count($product); $i++) {
$productA->appendChild($xmlDoc->createElement("category" . $i, implode("///", $product[$i]["category"])));
}
}
$xmlDoc->formatOutput = true;
echo $xmlDoc->saveXML();
Output
<?xml version="1.0" encoding="UTF-8"?>
<root>
<product>
<title> Some Title Name</title>
<category0> categor_one /// categor_two </category0>
<category1> categor_one /// categor_tree </category1>
</product>
</root>
Php demo

PHP to create XML File not generating properly

I am trying to add another element to to my xml file.
Here is what it generates right now.
flipsnack>
<title>Book 1</title>
<date>6-6-2016</date>
<link>google.com</link>
<embed>this is hetml code</embed>
<order>1</order>
<show>1</show>
<flipsnack>
<title/>
<link>hotmail.com</link>
<embed>html code all the way</embed>
<order>2</order>
<postdate/>
<show>1</show>
</flipsnack>
</flipsnack>
Here is what i think it should be....
<?xml version="1.0" encoding="UTF-8"?>
<flipsnack>
<book>
<title>Book 1</title>
<date>6-6-2016</date>
<link>google.com</link>
<embed>this is hetml code</embed>
<order>1</order>
<show>1</show>
</book>
<book>
<title>Book 1</title>
<date>6-6-2016</date>
<link>google.com</link>
<embed>this is hetml code</embed>
<order>1</order>
<show>1</show>
</book>
</flipsnack>
Here is my php code:
$title=$_POST["post"];
$date=$_POST["date"];
$link=$_POST["link"];
$html=$_POST["html"];
$order=$_POST["order"];
$show=$_POST["show"];
$xml = simplexml_load_file("db.xml");
$sxe = new SimpleXMLElement($xml->asXML());
$newItem = $sxe->addChild("flipsnack");
$newItem->addChild("title", $title);
$newItem->addChild("link", $link);
$newItem->addChild("embed", $html);
$newItem->addChild("order", $order);
$newItem->addChild("postdate", $postdate);
$newItem->addChild("show", $show);
$sxe->asXML("db.xml");
I dont quite under stand how i get from what its doing now to what i want it to do? Could anyone give me some direction?
See the code and take the idea what you are doing wrong.
<?php
$title = 'Book 1';
$link = 'google.com';
$order = 1;
$postdate = 'some postdate';
$show = 'some show';
$sxe = new SimpleXMLElement ( '<flipsnack/>' );
for($i = 0; $i < 2; $i ++) {
$newItem = $sxe->addChild ( "book" );
$newItem->addChild ( "title", $title );
$newItem->addChild ( "link", $link );
$newItem->addChild ( "order", $order );
$newItem->addChild ( "postdate", $postdate );
$newItem->addChild ( "show", $show );
}
echo $sxe->asXML ();
?>
Output
<?xml version="1.0"?>
<flipsnack>
<book>
<title>Book 1</title>
<link>google.com</link>
<order>1</order>
<postdate>some postdate</postdate>
<show>some show</show>
</book>
<book>
<title>Book 1</title>
<link>google.com</link>
<order>1</order>
<postdate>some postdate</postdate>
<show>some show</show>
</book>
</flipsnack>
Here is what i was trying to do.
$title=$_POST["title"];
$date=$_POST["date"];
$link=$_POST["link"];
$html=$_POST["html"];
$order=$_POST["order"];
$show=$_POST["show"];
$xml = simplexml_load_file("db.xml");
$sxe = new SimpleXMLElement($xml->asXML());
$newItem = $sxe->addChild("book");
$newItem->addChild("title", $title);
$newItem->addChild("date", $date);
$newItem->addChild("link", $link);
$newItem->addChild("embed", $html);
$newItem->addChild("order", $order);
$newItem->addChild("show", $show);
$sxe->asXML("db.xml");

Can I use SQL syntax on SimpleXML?

Can I use a WHERE selector (like SQL syntax) on SimpleXML?
Example XML
<?xml version="1.0" encoding="utf-8" ?>
<documentElement>
<row>
<id>1</id>
<name>David</name>
<surname>Johnson</surname>
</row>
<row>
<id>2</id>
<name>Jack</name>
<surname>Nixon</surname>
</row>
</documentElement>
My Example Where Selector
$where = "Jack";
$xml = "example.xml";
$sxml = simplexml_load_string($xml);
foreach ($sxml->row as $data=>$row)
{
if ($where == $data->name) // some code here
else // other some code here
}
Please let me know.
Thank you.
Yes, there is a way: XPath
$where = "Jack";
$xml = "example.xml";
$sxml = simplexml_load_string($xml);
var_dump($sxml->xpath('/documentElement/row/name[.="'.$where.'"]/..'));
No, but you can do this:
$where = "Jack";
$xml = "example.xml";
$sxml = simplexml_load_string($xml);
foreach ($sxml->row as $row)
{
if ($row->name == $where) {
// ...
} else {
// other some code here
}
}

How do extract child element in XML using DOM in PHP 5.0?

I am having the XML like this
<?xml version="1.0" encoding="utf-8"?>
<root>
<mynode catid="10" catname="Animals" label="Animals" catdesc="" parent_id="2">
<mynode catid="11" catname="Lions" label="Lions" catdesc="" parent_id="10">
<mynode catid="12" catname="lion" label="lion" catdesc="" parent_id="11"/>
<mynode catid="13" catname="lioness" label="lioness" catdesc="" parent_id="11"/>
</mynode>
</mynode>
</root>
From this I want to remove
<?xml version="1.0" encoding="utf-8"?>
<root>
and
</root>
So expected result is
<mynode catid="10" catname="Animals" label="Animals" catdesc="" parent_id="2">
<mynode catid="11" catname="Lions" label="Lions" catdesc="" parent_id="10">
<mynode catid="12" catname="lion" label="lion" catdesc="" parent_id="11"/>
<mynode catid="13" catname="lioness" label="lioness" catdesc="" parent_id="11"/>
</mynode>
</mynode>
How can I do this?
Edit 1:TO Phil
$dom = new DomDocument();
//$dom->preserveWhitespace = false;
$dom->load('treewithchild.xml');
function DOMinnerHTML($element)
{
$innerHTML = "";
$children = $element->childNodes;
foreach ($children as $child)
{
$tmp_dom = new DOMDocument();
$tmp_dom->appendChild($tmp_dom->importNode($child, true));
$innerHTML.=trim($tmp_dom->saveXML());
echo $tmp_dom->saveXML();
}
return $innerHTML;
}
$dom->preserveWhiteSpace = false;
$domTable = $dom->getElementsByTagName("mynode");
foreach ($domTable as $tables)
{
//echo $tables;
DOMinnerHTML($tables);
}
As you want the inner markup of the <root> node, that is the element who's child nodes you'll want to iterate. You can access this element using the DOMDocument::documentElement property.
Try this (tested and working)
$doc = new DOMDocument;
$doc->load('treewithchild.xml');
$inner = '';
foreach ($doc->documentElement->childNodes as $child) {
$inner .= $doc->saveXML($child);
}
echo $inner;
I expect that the root element is returned also, you have to know that for each xml file an is added impliicitly, even if it exists in your file. so try to do this
$children = $element->childNodes->childNodes;
i think that would help you.

xml:lang parse in PHP

<?xml version="1.0" encoding="UTF-8"?>
<answer>
<describe data="aircompany">
<data>
<code xml:lang="ru">FW</code>
<code xml:lang="en">FW</code>
</data>
<data>
<code xml:lang="ru">UT</code>
<code xml:lang="en">ЮТ</code>
</data>
</describe>
</answer>
I need get nodes value, there xml:lang="en". How can do it in PHP?
Yes, SimpleXML works but try adding the xml namespace if you run into trouble.
E.g.:
<?php
$xmlstr = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<answer xmlns:xml="http://www.w3.org/XML/1998/namespace">
<describe data="aircompany">
<data>
<code xml:lang="ru">ФВ</code>
<code xml:lang="en">FW</code>
</data>
<data>
<code xml:lang="ru">УТ</code>
<code xml:lang="en">UT</code>
</data>
</describe>
</answer>
XML;
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml->xpath('//data/code[#xml:lang="en"]') as $code) {
echo $code, '<br/>', PHP_EOL;
}
?>
XPath has a special construct for dealing with xml:lang attribute:
$xml = new SimpleXMLElement($strXML);
$data = $xml->describe->data[0];
$elCode = $data->xpath("code[lang('en')]"); // returns array of SimpleXMLElement
assert(count($elCode)==1);
$code_en = (string) $elCode[0];
P.S. greetings to the Sirena ;)
Thanks.
I use this method:
$XMLObj = new SimpleXMLElement($XML);
print_r($XMLObj->xpath('/answer/describe/data/code[#xml:lang = "en"]'));
Has been answered before:
$dom =new DOMDocument;
$dom->loadXML( $xml );
$xPath = new DOMXPath( $dom );
$nodes = $xPath->query( '/answer/describe/data/code[#xml:lang = "en"]' );
foreach( $nodes as $node ) {
echo $node->nodeValue;
}
Alternative without XPath:
$dom =new DOMDocument;
$dom->loadXML ($xml );
foreach( $dom->getElementsByTagName( 'code' ) as $node ) {
if( $node->getAttribute( 'xml:lang' ) === 'en') {
echo $node->nodeValue;
}
}
Have a look at the PHP SAX parser decribed here.

Categories