Ebay api GetSellerList, Parsing response XML - php

I am using the ebay trading api to get a sellers stock which is currently listed. I am using the call GetSellerList.I am having trouble parsing the xml which I would then insert into there website shop.
This is the xml request.
<GetSellerListRequest xmlns='urn:ebay:apis:eBLBaseComponents'>
<UserID>".$user_id."</UserID>
<DetailLevel>ReturnAll</DetailLevel>
<ErrorLanguage>RFC 3066</ErrorLanguage>
<WarningLevel>Low</WarningLevel>
<Version>".$compat_level."</Version>
<RequesterCredentials>
<eBayAuthToken>".$auth_token."</eBayAuthToken>
</RequesterCredentials>
<StartTimeFrom>2012-06-12T23:35:27.000Z</StartTimeFrom>
<StartTimeTo>2012-08-30T23:35:27.000Z</StartTimeTo>
<Pagination>
<EntriesPerPage>200</EntriesPerPage>
</Pagination>
<OutputSelector>ItemArray.Item.Title</OutputSelector>
<OutputSelector>ItemArray.Item.Description</OutputSelector>
<OutputSelector>ItemArray.Item.BuyItNowPrice</OutputSelector>
<OutputSelector>ItemArray.Item.Quantity</OutputSelector>
</GetSellerListRequest>
I am not the best with php, I am still learning so i have looked through w3schools and php docs and found nothing. I have been using this (off of ebay tuts) to try and get the values of the xml tags by using getElementsByTagName.
$dom = new DOMDocument();
$dom->loadXML($response);
$titles = $dom->getElementsByTagName('Title')->length > 0 ? $dom->getElementsByTagName('Title')->item(0)->nodeValue : '';
Now i was hoping that i would be able to create an array with this then use foreach to insert them into the db but when i use this it only gets the value of the first 'Title' tag
Im sure there is a way to create an array with all values of 'Title' in it.
All help is appreciated.

This would be easier to answer if you posted the response XML (just the relevant portion) rather than the request.
The code you have will only grab the first item - specifically this part:
$dom->getElementsByTagName('Title')->item(0)->nodeValue
Rather, you'll want to loop through all the Title elements and extract their nodeValue. This is a starting point:
$dom = new DOMDocument();
$dom->loadXML($response);
$title_nodes = $dom->getElementsByTagName('Title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
}

Related

Reading and writing Associative array to XML file

I am trying to add an array $item to an XML file in order to then be able to read all of the items in a later time.
I have the following PHP to perform this action:
<?php
$item = array();
$item['rating'] = $_GET['rating'];
$item['comment'] = $_GET['comment'];
$item['item_id'] = $_GET['item_id'];
$item['status'] = "pending";
//Defining $xml
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($item, array($xml, 'addChild'));
$xml = $xml->asXML();
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xml);
//Save XML as a file
$dom->save('reviews.xml');
However, when run what I get this in my XML file:
< ?xml version="1.0"?>
Basically my array is no where to be seen.
A var_dump of $item gives
array(4) { ["rating"]=> string(1) "8" ["comment"]=> string(17) "I Really Like it!" ["item_id"]=> string(1) "9" ["status"]=> string(7) "pending" }
How could I modify my code in order to have it save an array (and if there are many keep them all) in the file reviews.xml?
Also How could I make it so that later on I would be able to access the data; for instance changing the status from pending to approved?
EDIT:
Using the following code I have been able to save my item to the file:
$item = array();
$item[$_GET['rating']] = 'rating';
$item[$_GET['comment']] = 'comment';
$item[$_GET['item_id']] = 'item_id';
$item['pending'] = 'status';
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($item, array($xml, 'addChild'));
$xml->asXML('reviews.xml');
However I am still unable to append new data to the root rather than overwriting the current saved data.
As I was saying in my comment... The code you provided errors with WARNING DOMDocument::loadXML(): Empty string supplied as input. You never assigned anything to $xml'...
Proper error reporting/logging would help spot these mistakes.
<?php
$item = array();
$item['rating'] = 'a';
$item['comment'] = 'b';
$item['item_id'] = 'c';
$item['status'] = "pending";
//Defining $xml
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($item, array($xml, 'addChild'));
//THIS IS THE LINE YOU WERE MISSING
$xml = $xml->asXML();
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xml);
//Save XML as a file
$dom->save('reviews.xml');
If you echoed it out...
var_dump($dom->saveHTML());
> string(80)
> "<root><a>rating</a><b>comment</b><c>item_id</c><pending>status</pending></root>"
Please avoid updating your existing question with additional questions.
A database would make the task easier. Using a flat file works fine though, XML, or some other format. You will need to be able to retrieve a record by item_id, at which point you modify it, then replace it. That is the gist of it.
So here's an overhaul of your code, with some changes to both your approach and the scheme of your XML, based on your various comments and updates.
So first, instead of creating XML that looks like this:
<root>
<rating>a</rating>
<comment>b</comment>
<item_id>c</item_id>
<status>pending</status>
</root>
You're going to store the XML like this:
<root>
<item id="c">
<rating>a</rating>
<comment>b</comment>
<status>pending</status>
</item>
</root>
This is based on a few of your comments:
You are wanting to add to the XML file rather than overwrite the existing file content. That suggests that you want to store multiple items. This would also explain why you have a property item_id. So rather than having a mess of XML like :
<root>
<rating>a</rating>
<comment>b</comment>
<item_id>c</item_id>
<status>pending</status>
<rating>d</rating>
<comment>e</comment>
<item_id>f</item_id>
<status>pending</status>
<rating>g</rating>
<comment>h</comment>
<item_id>i</item_id>
<status>pending</status>
</root>
where it is impossible to know which item is which, you store each set of item properties on an <item> element. Since you are going to want to easily grab an item based on its item_id in order to update that item, making item_id an attribute of the <item> makes more sense than making it a child of the <item>.
You want to be able to update the status. This is where having the item_id stored on the item comes in handy. If someone submits a request with an existing item_id, you can update that item, including its status element. Or you could do it whenever you need to from some other process, etc.
Here's the code I drummed up for this. Note that it currently isn't set up to look for an existing element with that item id, but that should be possible using existing SimpleXML functions/methods.
$item = array();
$item_id = "c";
$item['rating'] = 'a';
$item['comment'] = 'b';
$item['status'] = "pending";
$xml = simplexml_load_file('ratings.xml');
//if ratings.xml not found or not valid xml, create clean XML with <root/>
if($xml === false) {
$xml = new SimpleXMLElement('<root/>');
}
$xml_item = $xml->addChild("item");
$xml_item->addAttribute("id", $item_id);
foreach($item as $name => $value) {
$xml_item->addChild($name, $value);
}
$xml->asXML('ratings.xml');
Notice that one of the major changes I made to your existing code is changing from using array_walk_recursive to a simple foreach. array_walk_recursive for this purpose is a short cut that causes more issues than it solves. For instance, you had to swap your key and value on the $item array, which is confusing. It also isn't necessary for what you currently are doing, since you don't have a multi-dimensional array. And even if you did, array_walk_recursive isn't the right choice to handle looping over the array recursively because it would add each array member to the root of the XML, not add sub-arrays as children of their parent entry as they show up in the actual array. Point being, it's confusing, it doesn't add any value, and using a foreach is a lot more clear on what you are actually doing.
I've also changed
$item['item_id'] = 'c';
to
$item_id = 'c';
and then added it to the item element as an attribute like:
$xml_item->addAttribute("id", $item_id);
This is consistent with the new schema I outlined earlier.
Finally, instead of passing the XML to DOMDocument, I'm just using
$xml->asXML('ratings.xml');
SimpleXML already removes any extra whitespace, so there is no need to use DOMDocument to achieve this.
Based on some of the counterintuitive parts of your original code, it looks like you may have done a decent amount of copy and pasting to get it going. Which is where most of us start, but it's a good idea to be upfront about things like "I don't understand quite what this code is doing, I just grabbed it from a script that did some of what I need." It will save us all a lot of time and grief if we're not assuming you are using the code you have because you need to or it was a conscious decision, etc, and that we have to work within the constraints of that code.
I hope this gets you off to a good start.
Update
I was messing around with it, and came up with the following for updating existing <item> if an item with id set to $item_id already exists. It's a bit clunky, but it tested and it works.
This assumes the $item_id and $item array get set as normal, as well as retrieving the exiting XML, as covered above. I'm providing the lines just before the changes for reference:
$xml = simplexml_load_file('ratings.xml');
//if ratings.xml not found or not valid xml, create clean XML with <root/>
if($xml === false) {
$xml = new SimpleXMLElement('<root/>');
}
//query with xpath for existing item with $item_id
$item_with_id = $xml->xpath("/root/item[#id='{$item_id}']");
// if the xpath returns a result, update that item with new values.
if(count($item_with_id) > 0) {
$xml_item = $item_with_id[0];
foreach($item as $name => $value) {
$xml_item->$name = $value;
}
} else {
// if the xpath returns no results, create new item element.
$xml_item = $xml->addChild("item");
$xml_item->addAttribute("id", $item_id);
foreach($item as $name => $value) {
$xml_item->addChild($name, $value);
}
}

Using PHP DOM to extract a certain node value, only if another node value is > 0

I am using php dom to parse xml from another platform, extract certain data from it, and upload to my own platform. I am however stuck when it comes to extracting a certain node value, only if another node value is greater than 0 for the child node 'row'. In the example below, I would like to iterate over the xml and pull out the 'affcustomid' value only if the CPACommission node value is greater than 0. Does anyone have any ideas how I can do this? The below code is a shortened version, in reality, i would get back 100's of rows in the same format as below.
<row>
<rowid>1</rowid>
<currencysymbol>€</currencysymbol>
<totalrecords>2145</totalrecords>
<affcustomid>11159_4498302</affcustomid>
<period>7/1/2014</period>
<impressions>0</impressions>
<clicks>1</clicks>
<clickthroughratio>0</clickthroughratio>
<downloads>1</downloads>
<downloadratio>1</downloadratio>
<newaccountratio>1</newaccountratio>
<newdepositingacc>1</newdepositingacc>
<newaccounts>1</newaccounts>
<firstdepositcount>1</firstdepositcount>
<activeaccounts>1</activeaccounts>
<activedays>1</activedays>
<newpurchases>12.4948</newpurchases>
<purchaccountcount>1</purchaccountcount>
<wageraccountcount>1</wageraccountcount>
<avgactivedays>1</avgactivedays>
<netrevenueplayer>11.8701</netrevenueplayer>
<Deposits>12.4948</Deposits>
<Bonus>0</Bonus>
<NetRevenue>11.8701</NetRevenue>
<TotalBetsHands>4</TotalBetsHands>
<Product1Bets>4</Product1Bets>
<Product1NetRevenue>11.8701</Product1NetRevenue>
<Product1Commission>30</Product1Commission>
<Commission>0</Commission>
<CPACommission>30</CPACommission>
</row>
Thanks in advance!
Mark
The easiest way to fetch data from an XML DOM is Xpath:
$dom = new DOMDocument();
$dom->load('file.xml');
$xpath = new DOMXpath($dom);
var_dump(
$xpath->evaluate('string(//row[CPACommission > 0]/affcustomid)')
);
It would be easier using SimpleXML:
$doc = simplexml_load_file('file.xml');
foreach ($doc->row AS $row) {
if($row->CPACommission > 0){
echo $row->affcustomid;
}
}
But if you still need to use DOMDocument:
$doc = new DOMDocument();
$doc->load('file.xml');
foreach ($doc->getElementsByTagName('row') AS $row) {
if($row->getElementsByTagName('CPACommission')->item(0)->textContent > 0){
echo $row->getElementsByTagName('affcustomid')->item(0)->textContent;
}
}

Using DOMXml and Xpath, to update XML entries

Hello I know there is many questions here about those three topics combined together to update XML entries, but it seems everyone is very specific to a given problem.
I have been spending some time trying to understand XPath and its way, but I still can't get what I need to do.
Here we go
I have this XML file
<?xml version="1.0" encoding="UTF-8"?>
<storagehouse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="schema.xsd">
<item id="c7278e33ef0f4aff88da10dfeeaaae7a">
<name>HDMI Cable 3m</name>
<weight>0.5</weight>
<category>Cables</category>
<location>B3</location>
</item>
<item id="df799fb47bc1e13f3e1c8b04ebd16a96">
<name>Dell U2410</name>
<weight>2.5</weight>
<category>Monitors</category>
<location>C2</location>
</item>
</storagehouse>
What I would like to do is to update/edit any of the nodes above when I need to. I will do a Html form for that.
But my biggest conserne is how do I find and update a the desired node and update it?
Here I have some of what I am trying to do
<?php
function fnDOMEditElementCond()
{
$dom = new DOMDocument();
$dom->load('storage.xml');
$library = $dom->documentElement;
$xpath = new DOMXPath($dom);
// I kind of understand this one here
$result = $xpath->query('/storagehouse/item[1]/name');
//This one not so much
$result->item(0)->nodeValue .= ' Series';
// This will remove the CDATA property of the element.
//To retain it, delete this element (see delete eg) & recreate it with CDATA (see create xml eg).
//2nd Way
//$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
// $result->item(0)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
header("Content-type: text/xml");
echo $dom->saveXML();
}
?>
Could someone maybe give me an examples with attributes and so on, so one a user decides to update a desired node, I could find that node with XPath and then update it?
The following example is making use of simplexml which is a close friend of DOMDocument. The xpath shown is the same regardless which method you use, and I use simplexml here to keep the code low. I'll show a more advanced DOMDocument example later on.
So about the xpath: How to find the node and update it. First of all how to find the node:
The node has the element/tagname item. You are looking for it inside the storagehouse element, which is the root element of your XML document. All item elements in your document are expressed like this in xpath:
/storagehouse/item
From the root, first storagehouse, then item. Divided with /. You already know that, so the interesting part is how to only take those item elements that have the specific ID. For that the predicate is used and added at the end:
/storagehouse/item[#id="id"]
This will return all item elements again, but this time only those which have the attribute id with the value id (string). For example in your case with the following XML:
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<storagehouse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="schema.xsd">
<item id="c7278e33ef0f4aff88da10dfeeaaae7a">
<name>HDMI Cable 3m</name>
<weight>0.5</weight>
<category>Cables</category>
<location>B3</location>
</item>
<item id="df799fb47bc1e13f3e1c8b04ebd16a96">
<name>Dell U2410</name>
<weight>2.5</weight>
<category>Monitors</category>
<location>C2</location>
</item>
</storagehouse>
XML;
that xpath:
/storagehouse/item[#id="df799fb47bc1e13f3e1c8b04ebd16a96"]
will return the computer monitor (because such an item with that id exists). If there would be multiple items with the same id value, multiple would be returned. If there were none, none would be returned. So let's wrap that into a code-example:
$simplexml = simplexml_load_string($xml);
$result = $simplexml->xpath(sprintf('/storagehouse/item[#id="%s"]', $id));
if (!$result || count($result) !== 1) {
throw new Exception(sprintf('Item with id "%s" does not exists or is not unique.', $id));
}
list($item) = $result;
In this example, $titem is the SimpleXMLElement object of that computer monitor xml element name item.
So now for the changes, which are extremely easy with SimpleXML in your case:
$item->category = 'LCD Monitor';
And to finally see the result:
echo $simplexml->asXML();
Yes that's all with SimpleXML in your case.
If you want to do this with DOMDocument, it works quite similar. However, for updating an element's value, you need to access the child element of that item as well. Let's see the following example which first of all fetches the item as well. If you compare with the SimpleXML example above, you can see that things not really differ:
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
$result = $xpath->query(sprintf('/storagehouse/item[#id="%s"]', $id));
if (!$result || $result->length !== 1) {
throw new Exception(sprintf('Item with id "%s" does not exists or is not unique.', $id));
}
$item = $result->item(0);
Again, $item contains the item XML element of the computer monitor. But this time as a DOMElement. To modify the category element in there (or more precisely it's nodeValue), that children needs to be obtained first. You can do this again with xpath, but this time with an expression relative to the $item element:
./category
Assuming that there always is a category child-element in the item element, this could be written as such:
$category = $xpath->query('./category', $item)->item(0);
$category does now contain the first category child element of $item. What's left is updating the value of it:
$category->nodeValue = "LCD Monitor";
And to finally see the result:
echo $doc->saveXML();
And that's it. Whether you choose SimpleXML or DOMDocument, that depends on your needs. You can even switch between both. You probably might want to map and check for changes:
$repository = new Repository($xml);
$item = $repository->getItemByID($id);
$item->category = 'LCD Monitor';
$repository->saveChanges();
echo $repository->getXML();
Naturally this requires more code, which is too much for this answer.

Get child elements in xml with PHP

I have an xml file that I need to parse through and get values. Below is a snippit of xml
<?xml version="1.0"?>
<mobile>
<userInfo>
</userInfo>
<CATALOG>
<s0>
<SUB0>
<DESCR>Paranormal Studies</DESCR>
<SUBJECT>147</SUBJECT>
</SUB0>
</s0>
<sA>
<SUB0>
<DESCR>Accounting</DESCR>
<SUBJECT>ACCT</SUBJECT>
</SUB0>
<SUB1>
<DESCR>Accounting</DESCR>
<SUBJECT>ACCTG</SUBJECT>
</SUB1>
<SUB2>
<DESCR>Anatomy</DESCR>
<SUBJECT>ANATOMY</SUBJECT>
</SUB2>
<SUB3>
<DESCR>Anthropology</DESCR>
<SUBJECT>ANTHRO</SUBJECT>
</SUB3>
<SUB4>
<DESCR>Art</DESCR>
<SUBJECT>ART</SUBJECT>
</SUB4>
<SUB5>
<DESCR>Art History</DESCR>
<SUBJECT>ARTHIST</SUBJECT>
</SUB5>
</sA>
So, I need to grab all the child elements of <sA> and then there are more elements called <sB> etc
But I do not know how to get all of the child elements with <sA>, <sB>, etc.
How about this:
$xmlstr = LoadTheXMLFromSomewhere();
$xml = new simplexml_load_string($xmlstr);
$result = $xml->xpath('//sA');
foreach ($result as $node){
//do something with node
}
PHP does have a nice class to access XML, which is called SimpleXml for a reason, consider heavily using that if your code is going to access only a part of the XML (aka query the xml). Also, consider doing queries using XPath, which is the best way to do it
Notice that I did the example with sA nodes only, but you can configure your code for other node types really easily.
Hope I can help!
you should look into simplexml_load_string() as I'm pretty sure it would make your life a lot easier. It returns a StdObject that you can use like so:
$xml = simplexml_load_string(<your huge xml string>);
foreach ($xml->hpt_mobile->CATALOG->sA as $value){
// do things with sA children
}
$xml = new DOMDocument();
$xml->load('path_to_xml');
$htp = $xml->getElementsByTagName('hpt_mobile')[0];
$catalog = $htp->getElementsByTagName('CATALOG')[0]
$nodes = $catalog->getElementsByTagName('sA')->childNodes;

PHP DOMDocument getting Attribute of Tag

Hello I have an api response in xml format with a series of items such as this:
<item>
<title>blah balh</title>
<pubDate>Tue, 20 Oct 2009 </pubDate>
<media:file date="today" data="example text string"/>
</item>
I want to use DOMDocument to get the attribute "data" from the tag "media:file". My attempt below doesn't work:
$xmldoc = new DOMDocument();
$xmldoc->load('api response address');
foreach ($xmldoc->getElementsByTagName('item') as $feeditem) {
$nodes = $feeditem->getElementsByTagName('media:file');
$linkthumb = $nodes->item(0)->getAttribute('data');
}
What am I doing wrong? Please help.
EDIT: I can't leave comments for some reason Mark. I get the error
Call to a member function getAttribute() on a non-object
when I run my code. I have also tried
$nodes = $feeditem->getElementsByTagNameNS('uri','file');
$linkthumb = $nodes->item(0)->getAttribute('data');
where uri is the uri relating to the media name space(NS) but again the same problem.
Note that the media element is of the form not I think this is part of the problem, as I generally have no issue parsing for attibutes.
The example you provided should not generate an error. I tested it and $linkthumb contained the string "example text string" as expected
Ensure the media namespace is defined in the returned XML otherwise DOMDocument will error out.
If you are getting a specific error, please edit your post to include it
Edit:
Try the following code:
$xmldoc = new DOMDocument();
$xmldoc->load('api response address');
foreach ($xmldoc->getElementsByTagName('item') as $feeditem) {
$nodes = $feeditem->getElementsByTagName('file');
$linkthumb = $nodes->item(0)->getAttribute('data');
echo $linkthumb;
}
You may also want to look at SimpleXML and Xpath as it makes reading XML much easier than DOMDocument.
Alternatively,
$DOMNode -> attributes -> getNamedItem( 'MyAttribute' ) -> value;

Categories