3

When calling findItemsAdvanced with RESPONSE-DATA-FORMAT=XML, the results are as expected, e.g:

<findItemsAdvancedResponse xmlns="http://www.ebay.com/marketplace/search/v1/services">
  <ack>Success</ack>
  <version>1.13.0</version>
  <timestamp>2014-11-16T20:59:57.588Z</timestamp>
  <searchResult count="0"/>
  <paginationOutput>
    <pageNumber>0</pageNumber>
    <entriesPerPage>100</entriesPerPage>
    <totalPages>0</totalPages>
    <totalEntries>0</totalEntries>
  </paginationOutput>
  <itemSearchURL>http://www.ebay.co.uk/sch/i.html?_nkw=mytest1</itemSearchURL>
</findItemsAdvancedResponse>

But calling the same with RESPONSE-DATA-FORMAT=JSON, individual elements are all wrapped in []:

{"findItemsAdvancedResponse":[
  {"ack":["Success"],
   "version":["1.13.0"],
   "timestamp":["2014-11-16T20:58:14.639Z"],
   "searchResult":[
    {"@count":"0"}],
   "paginationOutput":[
     {"pageNumber":["0"],
      "entriesPerPage":["100"],
      "totalPages":["0"],
      "totalEntries":["0"]}],
   "itemSearchURL":["http:\/\/www.ebay.co.uk\/sch\/i.html?&_nkw=mytest1"]
  }]
}

This seems to make it a pain to extract results using Javascript e.g:

response.findItemsAdvancedResponse[0].paginationOutput[0].pageNumber[0]

Am I doing missing something here or doing something wrong? (If not will consider requesting the results in XML and using an XML=>JSON conversion tool...)

Cray
  • 2,774
  • 7
  • 22
  • 32
Steve Chambers
  • 37,270
  • 24
  • 156
  • 208

5 Answers5

2

Seems no-one else is bothered by this?

I'm using AngularJS and I want to have the Ebay API as a backend. I have to write a $resource interceptor to collapse all arrays that only have 1 child to remove the redundant [] brackets.

A generic interceptor could solve this elegantly however I do think this is a bug.

I've asked the question on the Ebay Developer Form here: https://forums.developer.ebay.com/questions/16385/why-does-search-return-json-items-as-array.html#answer-16386

I have referenced this page on the Ebay forum - hope that helps others.

Edit:

... and for completeness, here is the code I used. It might not be pretty, but it worked for me. YMMV

var resp = {"findItemsAdvancedResponse":[
   {"ack":["Success"],
    "version":["1.13.0"],
    "timestamp":["2014-11-16T20:58:14.639Z"],
    "searchResult":[
     {"@count":"0"}],
    "paginationOutput":[
      {"pageNumber":["0"],
       "entriesPerPage":["100"],
       "totalPages":["0"],
       "totalEntries":["0"]}],
    "itemSearchURL":["http:\/\/www.ebay.co.uk\/sch\/i.html?&_nkw=mytest1"]
   }]
 };

var flatten = function( obj ) {
    var ret = {};

  if( String === obj.constructor || Number === obj.constructor ) {
    return obj;
  }

  for(var prop in obj) {
    if(!obj.hasOwnProperty(prop)) continue;

    if( String === obj[prop].constructor || Number === obj[prop].constructor ) {
        ret[prop] = obj[prop];
      continue;
    }

    if( Object.prototype.toString.call( obj[prop] ) === '[object Array]' ) {
      if( obj[prop].length==0 )
        ret[prop] = null;
      if( obj[prop].length==1 && "0" in obj[prop] ) {
        ret[prop] = flatten(obj[prop][0]);
      } else {
        ret[prop] = flatten(obj[prop]);
      }
      continue; // skip below: all arrays are Objects...!
    }

    if( Object === obj[prop].constructor ) {
      ret[prop] = flatten( obj[prop] );
      continue;
    }

  }
  return ret;
};

console.log( resp );
resp = flatten( resp );
console.log( resp );
console.log( resp.findItemsAdvancedResponse.ack );
Community
  • 1
  • 1
DerekC
  • 762
  • 5
  • 10
1

This is very similar to DerekC's parse function just quite a bit faster. It is geared towards simply finding elements that are arrays with Array.isArray() and a length of 1 with values that are not objects. Nothing fancy, super clean and super fast.

The function is called ebayFormat, just below the same response object that DerekC used.

var resp = {"findItemsAdvancedResponse":[
   {"ack":["Success"],
    "version":["1.13.0"],
    "timestamp":["2014-11-16T20:58:14.639Z"],
    "searchResult":[
     {"@count":"0"}],
    "paginationOutput":[
      {"pageNumber":["0"],
       "entriesPerPage":["100"],
       "totalPages":["0"],
       "totalEntries":["0"]}],
    "itemSearchURL":["http:\/\/www.ebay.co.uk\/sch\/i.html?&_nkw=mytest1"]
   }]
 };

  function ebayFormat(item) {
    if (typeof item === 'object') {
      if (Array.isArray(item) && item.length === 1 && typeof item[0] !== 'object') item = item[0];
      else {
        var keys = Object.keys(item),
          i = 0,
          len = keys.length;
        for (; i < len; i++) {
          if (typeof item[keys[i]] === 'object') item[keys[i]] = ebayFormat(item[keys[i]]);
        }
      }
    }
    return item;
  }

console.log( resp );
resp = ebayFormat( resp );
console.log( resp );
console.log( resp.findItemsAdvancedResponse.ack );
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
1

I got the same problem, I made a recursive function to solve it (remove array when array length=1 and is not exclude)

objJsonFromEbay = findAndCorrect(objJsonFromEbay);

    function findAndCorrect(obj){

        let o = obj,
            exclu = ['item'];

        for (const key in o) {
            if (o.hasOwnProperty(key)) {
                const val = o[key];

                if(Array.isArray(val) && val.length == 1){
                    if(exclu.indexOf(key) == -1)
                        o[key] = val[0];
                    o[key] = findAndCorrect(o[key]);
                }else if(!Array.isArray(val) && typeof val == 'object'){                        
                    o[key] = findAndCorrect(val);
                }
            }
        }
        return o;
    }

exclu is a Array for each element that you expect keep in a Array format. Could be useful if ever you use it to get products or another data that you expect in a Array

waliby
  • 61
  • 6
1

I had the same issue, and was curious if I'd still have issues if I chose to use an XML response versus a JSON response, and use an XML-to-JSON converter on the returned data -- lo and behold, still the exact same issue.

The converter I would end up deciding to use is called xml2js, which seems to be extremely popular on NPM (north of 3.5M monthly downloads according to NPM at the time of this answer).

xml2js has an option called explicitArray within its parseString behavior, which behaves as they document:

Always put child nodes in an array if true; otherwise an array is created only if there is more than one.

This behavior seems to emulate some of the answers listed here, but because it's a part of a widely-used community solution, I feel more comfortable using it versus a home-grown solution.

In practice, this looks as simple as:

import { parseString as xml2js } from 'xml2js';

...

xml2js(someXmlString, { explicitArray: false }, (err, results) => {
  // do something with `results`
});

https://www.npmjs.com/package/xml2js

wdews
  • 352
  • 2
  • 17
-6

This is JSON. What did you expect JSON to look like? :-)

{"findItemsAdvancedResponse":[
  {"ack":["Success"],
   "version":["1.13.0"],
   "timestamp":["2014-11-16T20:58:14.639Z"],
   "searchResult":[
    {"@count":"0"}],
   "paginationOutput":[
     {"pageNumber":["0"],
      "entriesPerPage":["100"],
      "totalPages":["0"],
      "totalEntries":["0"]}],
   "itemSearchURL":["http:\/\/www.ebay.co.uk\/sch\/i.html?&_nkw=mytest1"]
  }]
}

Try going to http://jsonviewer.stack.hu/ and pasting the JSON string into the "Text"-section and clicking the "Viewer" tab for a visual representation of the JSON data.

You may want to visit the Wikipedia article on JSON (JavaScript Object Notation): http://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example

  • 2
    Square brackets in JSON indicate arrays but most of these elements are not arrays (as shown in the XML). I expected the JSON to not have the square brackets. – Steve Chambers Nov 16 '14 at 22:09
  • Arrays or not does not change the fact that the response is in JSON as you requested of eBay API. Having the "[]" (arrays) means "one or more elements". In XML you do not have an indication of "one or more elements" as all XML nodes are arrays in a way since they can have child nodes. I would however agree with you that some of the arrays in the eBay's JSON response should not have been arrays - "How many times do you define the number of entries per page? Answer: 1", unless of course that different types of pages can have different number of entries per page, but that's another design issue. – LiveLongAndProsper Nov 16 '14 at 22:40
  • 1
    Yes, agree it's valid JSON but that doesn't make it right. The previous API ("shopping API") FindItemsAdvanced call didn't return the results in this odd manner. Will resort to converting XML to JSON as described [here](http://stackoverflow.com/questions/8830599/php-convert-xml-to-json#19391553) - this gives the results in the form I want them without having to add [0] to each element. – Steve Chambers Nov 17 '14 at 19:38