Getting Parent Node from XML file into a String in PHP - php

So, I'm parsing data from an XML feed in to php variables and everything is fine with the exception of the "link" element. It's not in a child like the others.
A cleaner, simpler example of the structure is below:
<bookstore>
<book category="children">
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
<link href="http://example.com">
</book>
<book category="web">
<title>Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
<link href="http://example.com">
</book>
</bookstore>
<bookstore>
<book category="children">
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
<link href="http://example.com">
</book>
<book category="web">
<title>Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
<link href="http://example.com">
</book>
</bookstore>
How do I read the link/href part of the XML in the parent node /bookstore/ and put it in to a string? It looks like it's been badly formatted, but I can't change it as it's supplied by a third party.
I thought I could load the entire /bookstore/ parent and search through it for the link and pull the value that way but it won't load the entire bookstore element.
My code is also extracting the other child tags fine and running through a loop to show the data in a list. Any help would be appreciated.
Edit: This is the link to the XML file I have to use: https://www.reddit.com/r/elderscrollsonline.xml

For SimpleXML - this code:
$rss = 'some_url_here';
$xml = simplexml_load_file($rss);
For you xml:
foreach($xml->bookstore as $bookstore) {
foreach ($bookastore as $book)
echo (string)$book->link['href'];
}
For links in https://www.reddit.com/r/elderscrollsonline.xml:
foreach($xml->entry as $book) echo (string)$book->link['href'];

Related

How to get the value of an attribute inside an XML element in PHP?

How do I get the value of an attribute inside an XML element?
For Example:
I want to get the value of attribute category.
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
Use the SimpleXML extension:
<?php
$xml = '<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
</bookstore>';
$doc = simplexml_load_string($xml);
echo $doc->book->attributes()->category; // cooking
echo $doc->book->title.PHP_EOL; // Everyday Italian
echo $doc->book->title->attributes()->lang.PHP_EOL; // en
Demo
Every element will be set as a property on the root object for you to access directly. In this particular case, you can use attributes() to get the attributes of the book element.
You can see in the example that you can keep going through the levels in the same way: to get to the lang attribute in book, use $doc->book->title->attributes()->lang.
$xml=simplexml_load_file("yourfile.xml");
echo $xml->book[0]['category'];
PHP provides a SimpleXML class in the standard library that can be used for parsing XML files.
$data = <<<END
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
</bookstore>
END;
$xml = simplexml_load_string($data);
$categoryAttributes = $xml->xpath('/bookstore/book/#category');
echo $categoryAttributes[0];

xmldiff issues on php

I am having some issues using xmldiff package. I'm using xmldiff package 0.9.2; PHP 5.4.17; Apache 2.2.25.
For example I have two xml files: "from.xml" & "to.xml".
File "from.xml" contains:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<rott>
<NDC>321</NDC>
<NDC>123</NDC>
</rott>
</root>
File "to.xml" contains:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<rott>
<NDC>123</NDC>
<NDC>321</NDC>
</rott>
</root>
I'm using code:
$zxo = new XMLDiff\File;
$dir1 = dirname(__FILE__) . "/upload/from.xml";
$dir2 = dirname(__FILE__) . "/upload/to.xml";
$diff = $zxo->diff($dir1, $dir2);
$file = 'differences.xml';
file_put_contents($file, $diff);
I get result in "differences.xml" file:
<?xml version="1.0"?>
<dm:diff xmlns:dm="http://www.locus.cz/diffmark">
<root>
<rott>
<dm:delete>
<NDC/>
</dm:delete>
<dm:copy count="1"/>
<dm:insert>
<NDC>321</NDC>
</dm:insert>
</rott>
</root>
</dm:diff>
Could you please comment from where this:
<dm:delete>
<NDC/>
</dm:delete>
comes?
Also please kindly inform me if there is a method which differs two xml files without matter of xml nodes order?
What you see is the diff in the libdiffmark format. Right from that page:
<copy/> is used in places where the input subtrees are the same
The documents from your snippet have partially identical sub trees. Effectively the instructions libdiffmark will execute are
delete the whole subtree
copy 1 nodes, that means the node is the same in the both documents, so don't touch it
insert 1 new node
The order of the nodes matters. Please think about how a diff would look like, if the node order were ignored. Say you had 42 nodes and some of those were the same, how it would apply the copy instruction with the count? Much easier for a diff to use the exact node order of two documents. One interesting reading I've found here about why node order can be important.
Thanks.
If the document structure is known, I think you can simply sort the necessary parts. Here's a useful acticle about it. Based on it, I've poked on some examples and could sort a document by node values (just for example), please look here
document library.xml
<?xml version="1.0"?>
<library>
<book id="1003">
<title>Jquery MVC</title>
<author>Me</author>
<price>500</price>
</book>
<book id="1001">
<title>Php</title>
<author>Me</author>
<price>600</price>
</book>
<book id="1002">
<title>Where to use IFrame</title>
<author>Me</author>
<price>300</price>
</book>
<book id="1002">
<title>American dream</title>
<author>Hello</author>
<price>300</price>
</book>
</library>
The PHP code, sorting by the <title>
<?php
$dom = new DOMDocument();
$dom->load('library.xml');
$xp = new DOMXPath($dom);
$booklist = $xp->query('/library/book');
$books = iterator_to_array($booklist);
function sort_by_title_node($a, $b)
{
$x = $a->getElementsByTagName('title')->item(0);
$y = $b->getElementsByTagName('title')->item(0);
return strcmp($x->nodeValue, $y->nodeValue) > 0;
}
usort($books, 'sort_by_title_node');
$newdom = new DOMDocument("1.0");
$newdom->formatOutput = true;
$root = $newdom->createElement("library");
$newdom->appendChild($root);
foreach ($books as $b) {
$node = $newdom->importNode($b,true);
$root->appendChild($newdom->importNode($b,true));
}
echo $newdom->saveXML();
And here's the result:
<?xml version="1.0"?>
<library>
<book id="1002">
<title>American dream</title>
<author>Hello</author>
<price>300</price>
</book>
<book id="1003">
<title>Jquery MVC</title>
<author>Me</author>
<price>500</price>
</book>
<book id="1001">
<title>Php</title>
<author>Me</author>
<price>600</price>
</book>
<book id="1002">
<title>Where to use IFrame</title>
<author>Me</author>
<price>300</price>
</book>
</library>
This way you can sort the parts of the document before comparing. After that you can even use the DOM comparison directly. Even you could reorder the nodes, it were a similar approach.
I'm not sure it'll be very useful in the case if you have a variable node number. Say if the <NDC> tag were repeated some random number of times and it's values were completely different.
And after all, I still think the simplest way were to ask your supplicant to create some more predictable document structure :)
Thanks
Anatol

How to get value of xml element

I need to retrieve the value of the value of "TotalBooks" from an xml file that is structured like the example below.
I can get the equivalent of the "MatchesFound" value by doing a count of "book" and I can successfully get the information for each book.
However, I cannot get the actual value shown in the xml file for "MatchesFound", "TotalBooks", and "Page".
I'm using php with simplexml_load_file. Any help I can get is appreciated. Thanks.
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<MatchesFound>2</MatchesFound>
<TotalBooks>563</TotalBooks>
<Page>1</Page>
<book>
<title>Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price currency="USD">30.00</price>
</book>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price currency="USD">29.99</price>
</book>
</bookstore>
$xml = new SimpleXMLElement($xmlString);
echo $xml->TotalBooks;
Using xpath :
<?php
$string = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<MatchesFound>2</MatchesFound>
<TotalBooks>563</TotalBooks>
<Page>1</Page>
<book>
<title>Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price currency="USD">30.00</price>
</book>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price currency="USD">29.99</price>
</book>
</bookstore>
XML;
$xml = new SimpleXMLElement($string);
$result = $xml->xpath('//TotalBooks');
while(list( , $node) = each($result)) {
echo "$node\n";
}
?>
See http://php.net/manual/en/simplexmlelement.xpath.php

php and xpath - loop through child elements of particular element

I would like to loop through each book_list in the following xml file and for each book_list loop through each book for that book_list.
<inventory>
<book_list>
<book>
<author>Rowling</author>
<title>Harry Potter</title>
</book>
<book>
<author>Blyton</author>
<title>Famous 5</title>
</book>
</book_list>
<book_list>
<book>
<author>Bloggs</author>
<title>Learning XML</title>
</book>
<book>
<author>Jones</author>
<title>Beginning PHP</title>
</book>
</book_list>
</inventory>
How can I, for each book_list, loop through each book, using xpath in a php simplexml script? Here is my code,
$booklistpath = $xml->xpath('//booklist');
foreach ($booklistpath as $booklist) {
$bookpath = $xml->xpath('//book');
foreach ($bookpath as $book) {
...
}
}
The first loop is fine, it goes through each book_list - but the nested loop, which is meant to go through each book for that particular book_list goes through each book in the entire document. I have also tried :-
'.//book' and
'descendant::book'
That's the right result since you're using the second xpath call on the original $xml which is the SimpleXMLElement for your whole XML document.
To get the books for each booklist just iterate them as follow:
$booklists = $sxe->xpath('//book_list');
foreach ($booklists as $booklist) {
foreach ($booklist->book as $book) {
echo $book->asXML();
}
}

PHP reading XML with Where Clause

Let's say I have this XML file.
<book>
<id>1</id>
<title>Harry Potter - bla bla bla</title>
<author>J.K Rowling</author>
</book>
<book>
<id>2</id>
<title>Other book</title>
<author>A Name</author>
</book>
Is there a way where I can read via PHP and get the #2 id, or do I have to use an IF?
Like jQuery selector ':eq(2)', or MySql 'WHERE id=2'
There is, try SimpleXML parser of php: http://php.net/manual/en/book.simplexml.php
If all you want is just the second one you can use DOM. It's simpler.
$dom->loadXML(<<<XML
<book>
<id>1</id>
<title>Harry Potter - bla bla bla</title>
<author>J.K Rowling</author>
</book>
<book>
<id>2</id>
<title>Other book</title>
<author>A Name</author>
</book>
XML;);
$book=$dom->getElementsByTagName('book')->item(1);
Edit: I just saw you say you were looking for second ID, not second element, you need xpath for that.
$xml=new SimpleXMLElement(<<<XML
<book>
<id>1</id>
<title>Harry Potter - bla bla bla</title>
<author>J.K Rowling</author>
</book>
<book>
<id>2</id>
<title>Other book</title>
<author>A Name</author>
</book>
XML;);
$result=$xml->xpath('/book[id=2]');
More on xpath here

Categories