【问题标题】:eBay Finding API - Why are findItemsAdvanced JSON result elements all arrays?eBay Finding API - 为什么 findItemsAdvanced JSON 结果元素都是数组?
【发布时间】:2014-11-16 21:42:57
【问题描述】:

当用RESPONSE-DATA-FORMAT=XML调用findItemsAdvanced时,结果如预期,例如:

<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>

但是用RESPONSE-DATA-FORMAT=JSON调用相同,单个元素都包裹在[]中:

{"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"]
  }]
}

这似乎让使用 Javascript 提取结果变得很痛苦,例如:

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

我是在这里遗漏了什么还是做错了什么? (如果没有,将考虑以 XML 格式请求结果并使用 XML=>JSON 转换工具...)

【问题讨论】:

    标签: javascript json xml ebay-api


    【解决方案1】:

    似乎没有其他人对此感到困扰?

    我正在使用 AngularJS,我希望将 Ebay API 作为后端。我必须写一个 $resource interceptor 来折叠所有只有 1 个子元素的数组以删除多余的 [] 括号。

    通用拦截器可以优雅地解决这个问题,但我确实认为这是一个错误。

    我在 Ebay 开发者表单上提出了这个问题:https://forums.developer.ebay.com/questions/16385/why-does-search-return-json-items-as-array.html#answer-16386

    我在 Ebay 论坛上引用了此页面 - 希望对其他人有所帮助。

    编辑:

    ...为了完整起见,here is the code I used。它可能不漂亮,但它对我有用。 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 );
    

    【讨论】:

      【解决方案2】:

      这与DerekC's 解析函数非常相似,只是要快一些。它旨在简单地查找具有 Array.isArray() 且长度为 1 且值不是对象的数组元素。没什么花哨的,超级干净,超级快。

      该函数名为ebayFormat,就在DerekC 使用的同一响应对象的下方。

      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 );
      

      【讨论】:

        【解决方案3】:

        我遇到了同样的问题,我做了一个递归函数来解决它(当数组长度=1并且不排除时删除数组)

        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 是您希望以数组格式保存的每个元素的数组。 如果您曾经使用它来获取您期望在数组中的产品或其他数据,这可能会很有用

        【讨论】:

          【解决方案4】:

          我遇到了同样的问题,我很好奇如果我选择使用 XML 响应而不是 JSON 响应,并在返回的数据上使用 XML-to-JSON 转换器,我是否还会遇到问题 - 你瞧,还是一样的问题。

          我最终决定使用的转换器名为 xml2js,它似乎在 NPM 上非常受欢迎(根据 NPM 的这个答案,每月下载量超过 350 万次)。

          xml2js 在其 parseString 行为中有一个名为 explicitArray 的选项,其行为与他们记录的一样:

          如果为真,则始终将子节点放入数组中;否则,只有当有多个数组时才会创建一个数组。

          这种行为似乎模仿了这里列出的一些答案,但由于它是广泛使用的社区解决方案的一部分,我觉得使用它比使用本土解决方案更舒服。

          实际上,这看起来很简单:

          import { parseString as xml2js } from 'xml2js';
          
          ...
          
          xml2js(someXmlString, { explicitArray: false }, (err, results) => {
            // do something with `results`
          });
          

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

          【讨论】:

            【解决方案5】:

            这是 JSON。你期望 JSON 是什么样子的? :-)

            {"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"]
              }]
            }
            

            尝试转到 http://jsonviewer.stack.hu/ 并将 JSON 字符串粘贴到“文本”部分,然后单击“查看器”选项卡以直观地显示 JSON 数据。

            您可能希望访问有关 JSON(JavaScript 对象表示法)的 Wikipedia 文章: http://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example

            【讨论】:

            • JSON 中的方括号表示数组,但其中大部分元素不是数组(如 XML 中所示)。我希望 JSON 没有方括号。
            • Arrays or not 不会改变响应是 JSON 格式的事实,正如您对 eBay API 的要求。拥有“[]”(数组)意味着“一个或多个元素”。在 XML 中,您没有“一个或多个元素”的指示,因为所有 XML 节点在某种程度上都是数组,因为它们可以有子节点。然而,我同意你的观点,eBay 的 JSON 响应中的一些数组不应该是数组——“你定义每页的条目数多少次?答案:1”,当然,除非不同类型的页面可以每页有不同数量的条目,但这是另一个设计问题。
            • 是的,同意它是有效的 JSON,但这并不正确。之前的 API(“购物 API”)FindItemsAdvanced 调用并没有以这种奇怪的方式返回结果。将求助于将 XML 转换为 JSON,如 here 所述 - 这会以我想要的形式给出结果,而无需将 [0] 添加到每个元素。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多