0

I'm having a problem with some RSS feed parsing using YQL and JavaScript. The code works fine as long as there is more than one result. The YQL output is returned as an array (JSON), and I can format it with a for loop. However, when there is only one result, YQL returns an object, and the parsing doesn't work. Any suggestions for a workaround? Been trying different approaches for hours, but to no avail.

<!DOCTYPE html>
<html lang="no">
    <head>
        <title>Kolonnekj&oslash;ring.no</title>

        <link href="css/bootstrap.css" rel="stylesheet">
        <script src="http://yui.yahooapis.com/3.18.1/build/yui/yui-min.js"></script>

        <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
        <!--[if lt IE 9]>
        <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->

    </head>
    <body>
        <nav class="navbar navbar-default">
            <div class="container-fluid">

                <!-- start collapsed navbar-->
                <div class="navbar-header">
                    <button 
                    type="button" 
                    class="navbar-toggle collapsed" 
                    data-toggle="collapse" 
                    data-target="#main_navbar" 
                    aria-expanded="false">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>           
                    <a class="navbar-brand" href="#">Kolonnekj&oslash;ring.no</a>
                </div>
                <!-- / collapsed navbar-->

            <!-- start un-collapsed navbar-->
            <div 
            class="collapse navbar-collapse" 
            id="main_navbar">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="index.html">Aktive kolonner</a></li>
                    <li><a href="sor_norge.html">Fjelloverganger i S&oslash;r-Norge</a></li>
                    <li><a href="nord_norge.html">Fjelloverganger i Nord-Norge</a></li>
                    <li><a href="#">Om Kolonnekj&oslash;ring.no</a></li>
                </ul>
            </div> <!-- / un-collapsed navbar-->

            </div> <!-- /container -->
        </nav>

        <div class="container">
            <h1>Aktive kolonner i Norge</h1>       
            <!-- start breadcrumb -->
            <ol class="breadcrumb">
                <li><a href="index.html">Aktive kolonner</a></li>
            </ol>
            <!-- / breadcrumb -->            
            <div class="row">
                <div class="col-md-12" id="kolonnemeldinger"></div>
            </div>
        </div>

        <script>
            YUI().use('yql', function(Y){
                var query = 'select * from rss where url = "http://www.vegvesen.no/trafikk/xml/search.rss?searchFocus.messageType=18&searchFocus.sortOrder=3"'
                var q = Y.YQL(query, function(r){
                    //r now contains the result of the YQL Query as a JSON
                    var feedmarkup = '<p>'
                    var feed = r.query.results.item // get feed as array of entries
                    for (var i=0; i<feed.length; i++){
                        feedmarkup += '<h4>' + feed[i].title + '</h4>'
                        feedmarkup += feed[i].description + '</p>'
                    }
                    document.getElementById('kolonnemeldinger').innerHTML = feedmarkup
                })
            })
        </script>

        <!-- load JS -->
        <script src="js/jquery.min.js"></script>
        <script src="js/bootstrap.min.js"></script>
        <!-- / load JS -->

    </body>
</html>

2 Answers2

2

Testing for an Array

This is a common problem with web service data. And the solution is to convert single item results to an array.

Using (typeof item == 'Array') as first suggested will NOT work because it is an Object.

Using Array.isArray( item ) will work, but only with modern browsers.

Testing for an array method is another possible solution, e.g., if (item.push) A(); else B();

For more information see: Check if object is array?

YQL SOLUTION

Yet, none of these tests are needed because Yahoo YQL already provides the information in the data preamble: result.query.count

And the solution is simply:

feed = r.query.count > 1 ? r.query.results.item : [r.query.results.item];

Which converts single items to an array that can be processed by the loop.

Run the code snippet below to test:

var xhr, url, r, feedmarkup, feed, i, query;

// remove the query parameter to return multiple items
query = 'select * from rss where ' +
  'url=\'http://www.vegvesen.no/trafikk/xml/search.rss' +
  '?searchFocus.messageType=18\'';


url = 'https://query.yahooapis.com/v1/public/yql' +
  '?diagnostics=true' +
  '&format=json' +
  '&q=' + encodeURI(query) +
  '&callback=';


xhr = new XMLHttpRequest();
xhr.open('GET', url, false); // async for tests only
xhr.send();

r = JSON.parse(xhr.responseText);
document.getElementById('debug').innerHTML = JSON.stringify(r, null, '  ');

feed = r.query.count > 1 ? r.query.results.item : [r.query.results.item];
//feed = r.query.results.item.push ? r.query.results.item : [r.query.results.item];


feedmarkup = '<p>';
for (i = 0; i < feed.length; i++) {
  feedmarkup += '<h4>' + feed[i].title + '</h4>;'
  feedmarkup += feed[i].description + '</p>';
}

document.getElementById('kolonnemeldinger').innerHTML = feedmarkup;
<h3>RSS:</h3>
<div id="kolonnemeldinger">Fetching data...</div>
<h3>JSON</h3>
<xmp id="debug"></xmp>
Community
  • 1
  • 1
Yogi
  • 6,241
  • 3
  • 24
  • 30
  • I'm at my day job at the moment, but will test it when I get home. But from testing the code snippet, it does seem to work. However, I need to generate some queries where I get one result to do the final check. I was trying to find a YQL solution to the issue, but I find the YQL documentation a bit lacking. – John Rønnevik Feb 19 '16 at 05:00
  • Tried the solution. It worked with the query as stated. At the moment, it gave two results. When I changed the query part to `?searchFocus.counties=20&searchFocus.messageType=18&searchFocus.roadTypes=Ev&searchFocus.roadTypes=Rv&searchFocus.sortOrder=0`, it failed. JSON debug information returns `{ "error": { "lang": "en-US", "diagnostics": null, "description": "Query syntax error(s) [line 1:98 mismatched character ' ' expecting ''']" } }`. – John Rønnevik Feb 19 '16 at 05:39
0
YUI().use('yql', function(Y){
                var query = 'select * from rss where url = "http://www.vegvesen.no/trafikk/xml/search.rss?searchFocus.messageType=18&searchFocus.sortOrder=3"'
                var q = Y.YQL(query, function(r){
                    //r now contains the result of the YQL Query as a JSON
                    var feedmarkup = '<p>'
                    var feed = r.query.results.item // get feed as array of entries
                    feed = Array.isArray(feed) ? feed : [feed];
                    for (var i=0; i<feed.length; i++){
                        feedmarkup += '<h4>' + feed[i].title + '</h4>'
                        feedmarkup += feed[i].description + '</p>'
                    }
                    document.getElementById('kolonnemeldinger').innerHTML = feedmarkup
                })
            })
Kelvin
  • 690
  • 3
  • 11
  • Thanks for the input, Kelvin. However, in this instance, it doesn't work. I get unexpected token for typeof; I'm thinking this is because YQL returns the output as an object instead of an array when there's a single result. When there are no results, it's returned as 'null'. – John Rønnevik Feb 18 '16 at 16:35
  • sorry I type error. This is `instance of Array` or you can use `feed.isArray()` or `feed.length` instead – Kelvin Feb 18 '16 at 16:37