Targeting an item of an object when the number of items changes?

Hi,

I have a json feed that I would like to extract information out from but for the last few days I’ve been struggling. I can target the item using the key but because the number of items in the object can vary which obviously then breaks my method.

E.g

var dayone1260 = data.SiteRep.DV.Location.Period[0].Rep[0];
      console.log(dayone1260.Pp);

My Json feed looks like this:


<DV dataDate="2012-11-01T18:00:00Z" type="Forecast">
<Location i="310069" lat="50.7179" lon="-3.5327" name="EXETER" country="ENGLAND" continent="EUROPE">
<Period type="Day" value="2012-11-01Z">
<Rep D="W" F="5" G="25" H="71" Pp="48" S="9" T="8" V="EX" W="10" U="1">900</Rep>
<Rep D="W" F="5" G="47" H="78" Pp="59" S="4" T="7" V="EX" W="13" U="0">1080</Rep>
<Rep D="SW" F="3" G="25" H="82" Pp="58" S="9" T="6" V="EX" W="13" U="0">1260</Rep>
</Period>
<Period type="Day" value="2012-11-02Z">
<Rep D="WSW" F="3" G="34" H="85" Pp="38" S="11" T="6" V="GO" W="19" U="0">0</Rep>
<Rep D="WSW" F="3" G="20" H="80" Pp="1" S="9" T="6" V="EX" W="2" U="0">180</Rep>
<Rep D="SW" F="3" G="18" H="86" Pp="9" S="7" T="5" V="VG" W="2" U="0">360</Rep>
<Rep D="SSW" F="5" G="13" H="82" Pp="4" S="4" T="6" V="VG" W="3" U="1">540</Rep>
<Rep D="WNW" F="6" G="22" H="77" Pp="28" S="7" T="8" V="VG" W="3" U="1">720</Rep>
<Rep D="WSW" F="8" G="22" H="68" Pp="8" S="9" T="10" V="EX" W="3" U="1">900</Rep>
<Rep D="WSW" F="5" G="18" H="78" Pp="1" S="7" T="7" V="EX" W="2" U="0">1080</Rep>
<Rep D="SW" F="5" G="13" H="81" Pp="7" S="7" T="6" V="VG" W="2" U="0">1260</Rep>
</Period>
<Period type="Day" value="2012-11-03Z">
<Rep D="WSW" F="4" G="13" H="82" Pp="2" S="7" T="6" V="EX" W="2" U="0">0</Rep>
<Rep D="SW" F="3" G="16" H="83" Pp="7" S="7" T="6" V="EX" W="2" U="0">180</Rep>
<Rep D="W" F="3" G="11" H="84" Pp="2" S="7" T="5" V="VG" W="2" U="0">360</Rep>
<Rep D="W" F="2" G="18" H="85" Pp="38" S="9" T="5" V="GO" W="10" U="1">540</Rep>
<Rep D="W" F="4" G="20" H="76" Pp="43" S="9" T="7" V="EX" W="10" U="1">720</Rep>
<Rep D="WSW" F="2" G="18" H="82" Pp="44" S="9" T="5" V="VG" W="10" U="1">900</Rep>
<Rep D="N" F="2" G="11" H="86" Pp="15" S="4" T="4" V="VG" W="7" U="0">1080</Rep>
<Rep D="SSW" F="1" G="11" H="86" Pp="6" S="7" T="4" V="EX" W="0" U="0">1260</Rep>
</Period>
....More reports
</Location>
</DV>
</SiteRep>

Is there a better way to obtain the .Pp value in a variable so I can then use / display it on the page. Using the ‘value’ of <Rep>?

My javascript knowledge is limited to jquery front end stuff to date so sorry if I’ve not explained this very well.

Well, firstly, that definitely does not look like a JSON feed at all, that looks more like XML.

If it were JSON, you would expect your data object to look like a JavaScript Object (http://www.json.org/js.html)
e.g.


data = {
    "DV": {
        "dataDate":"2012-11-01T18:00:00Z",
        "type": "Forecast",
        "Location": {
            "i": "310069",
            "lat": "50.7179",
            ...
            ...
            "Period": {
                "type": "Day",
                ...
                "Rep":[
                    {
                        "TextValue": 900,
                        "D": "W",
                        "F": "5",
                        ...
                        ...
                    },
                    ...
                    ...
                ]
            }
            
        }
    }
  
}

In any case, the way that you are currently retrieving the data is about as good as it gets, you can of course shorten the path a little if you only need to get access to the reps in a particular section of the code.


// currently you have a rather long path to get to a rep
var rep = data.SiteRep.DV.Location.Period[0].Rep[0];

// you could shorten it like this
var periods = data.SiteRep.DV.Location.Period;

//you can now access the periods/reps like so:
rep = periods[0].Rep[0];

Hi John,

Thanks for your reply.

Sorry. It is definately json. However, I have an extension for Chrome that displays the feed like that and I had just cut and paste it without thinking.

The json looks like this:

"units":"C","$":"Feels Like Temperature"},{"name":"G","units":"mph","$":"Wind Gust"},{"name":"H","units":"%","$":"Screen Relative Humidity"},{"name":"T","units":"C","$":"Temperature"},{"name":"V","units":"","$":"Visibility"},{"name":"D","units":"compass","$":"Wind Direction"},{"name":"S","units":"mph","$":"Wind Speed"},{"name":"U","units":"","$":"Max UV Index"},{"name":"W","units":"","$":"Weather Type"},{"name":"Pp","units":"%","$":"Precipitation Probability"}]},
"DV":{"dataDate":"2012-11-02T07:00:00Z","type":"Forecast","Location":{"i":"310069","lat":"50.7179","lon":"-3.5327","name":"EXETER","country":"ENGLAND","continent":"EUROPE",
"Period":[{"type":"Day","value":"2012-11-02Z",
"Rep":[{"D":"SSW","F":"5","G":"18","H":"81","Pp":"45","S":"2","T":"6","V":"EX","W":"13","U":"0","$":"180"},{"D":"SW","F":"3","G":"13","H":"86","Pp":"17","S":"4","T":"5","V":"EX","W":"2","U":"0","$":"360"},{"D":"WSW","F":"5","G":"13","H":"83","Pp":"38","S":"4","T":"6","V":"VG","W":"10","U":"1","$":"540"},{"D":"WSW","F":"7","G":"22","H":"71","Pp":"39","S":"9","T":"9","V":"EX","W":"10","U":"1","$":"720"},{"D":"W","F":"4","G":"40","H":"80","Pp":"64","S":"11","T":"7","V":"VG","W":"14","U":"1","$":"900"},{"D":"WSW","F":"4","G":"18","H":"84","Pp":"35","S":"7","T":"6","V":"VG","W":"9","U":"0","$":"1080"},{"D":"W","F":"4","G":"13","H":"86","Pp":"11","S":"7","T":"6","V":"EX","W":"2","U":"0","$":"1260"}]},{"type":"Day","value":"2012-11-03Z",
"Rep":[{"D":"S","F":"3","G":"11","H":"89","Pp":"16","S":"4","T":"5","

Is there some way the the value of a Rep object ($ in the JSON representation) can be used to target the Pp from that report?

The problem is the value of a Rep object denotes the number of minutes after midnight for that report. Once these have passed the reports are removed. Therefore …

periods[0].Rep[0];

would be the ‘first’ report available but not necessarily the first report for the day.

Ah yesh. I did see were using JSON notation to address the object’s properties.

When you drill down you can just use the dot-notation to access that property, or if for some reason you need to get a property based on another property then you can also use the bracket-notation to do it that way.

e.g.


precipitationPercent = periods[0].Rep[0].Pp

Or


// get the property name from one of the previous objects 
// let's say that units[9].name contains the string "Pp"
// based on {"name":"Pp","units":"%","$":"Precipitation Probability"}

precipitationPercent = periods[0].Rep[0][ units[9].name ];

Hope this helps, not 100% sure if I understood your question correctly, feel free to clarify if I haven’t :slight_smile:

Thank you so much - I think I finally got it from your input!

Ok. I think Im winning with this now so thank you.

However, I have another json feed which I can’t seem to target items from in the same way. The json looks like this

{
  "Locations":{
    "Location":[{
        "id":"3002",
        "latitude":"60.749",
        "longitude":"-0.854",
        "name":"Baltasound"
      },
      {
        "id":"3005",
        "latitude":"60.139",
        "longitude":"-1.183",
        "name":"Lerwick (S. Screen)"
      },
      {
        "id":"3006",
        "latitude":"60.447",
        "longitude":"-1.277",
        "name":"Sella Ness"
      },

Im trying this:


function(data) {
$.each(data.Locations, function(place){
      console.log('location name: '+place.Location.name);
         
    });

and this


function(data) {
$.each(data.Locations.Location, function(place){
      console.log('location name: '+place.name);
         
    });

= but ‘cannot read property name of undefined’ error.

What am I doing wrong?

Yay, always good to hear :slight_smile:

What happens is that when you put “place” as the parameter for the callback function of the .each() method, it uses that as the key.

The jQuery.each() callback can be used in 2 different ways, the first is if you pass in the key/value parameters, the second is by using the “this” keyword the current element that is being iterated over.

In this case, your second example is almost done! All you need to do is use “this” instead of “place”.


$.each(data.Locations.Location, function(){
    console.log('location name: '+this.name);
});

In contrast, the other way would do it is like this:


$.each(data.Locations.Location[0], function(key, val){
    console.log(key, val);
});

I purposely used data.Locations.Location[0] here to demo, as this second method is better for looping over objects rather than arrays. You can use that method as well to loop over arrays of course, the key will then be the array index and val will be the value of the item at that index in the array. However, when I know that I’m looping over an array I tend to use the first method as all I’m usually interested in the value.

Wow. Thank you.

I’ll give that a try.

Would you ever have an array stored in a object? How would I tell them apart in the json feed? Sorry if that’s an obvious question!

I guess normally, since you’d be processing the data somehow, you would know which nodes are objects and which are arrays. Though, strictly speaking if you’re using the $.each() method you don’t need to know whether you’re iterating over an array or an object.

Of course you can inspect the JSON object in your debugger (Dev tools, firebug, whatever) to see which nodes are what.

The actual question of whether you could/should/would store an array in an object, it all comes down to “what” the data is. Let me illustrate this in code:


var someObject = {

    "title": "Some string",

    "messages": [ //messages is a list of "something", so it's in an array

        // a "message" consists of "content" and an "id" - so an object would be better to represent this.
        { 
           "content": "Hello", 
           "id": 1
        },
        {
           "content": "World",
           "id": 2
        }
    ]

};

Thank you!

Your suggestion worked and I can now get the locations.

But better than that I think I’ve actually got a handle on it. Until the next time I’m left scratching my head that is. :slight_smile:

Thank you for your time to explain.