Reputation: 476
I have 15 LI items on a page, and I am trying to reconstruct the data from the heavily nested html to a simple JSON object with name, latitude and longitude.
For example, one record could look like:
{name: "Pied a Terre", lat: "51.5191", "lng: "-0.1399435"}
This is a slightly simplified version of the each LI in the HTML I'm working with:
<li class="has-distance link-block" itemtype="http://schema.org/Restaurant">
<meta content="Yes" itemprop="acceptsReservations">
<div class="item" data-id="109054" data-weight="-42.4101">
<img class="photo loaded" src="http://img.static-bookatable.com/heeltap-london-bridge-london-1.jpg?id=218ab1c679b5a543c0a6b53012c379d5.jpg=" width="140" height="100" alt="Heeltap - London">
<div class="detail">
<span itemprop="reviews" itemscope="" itemtype="http://schema.org/AggregateRating">
<meta content="0" itemprop="ratingValue">
<meta content="0" itemprop="reviewCount">
<span class="star rating" title="Not yet rated">
<span class="average"><span>*****</span></span>
</span>
</span>
<h3 class="fn" itemprop="name">Heeltap</h3>
<p class="adr wide" itemprop="address">Chaucer House, White Hart Yard, London, SE1 1NX</p>
<p class="cuisine" itemprop="servesCuisine">British </p>
<span itemprop="geo" itemscope="" itemtype="http://schema.org/GeoCoordinates">
<meta content="51.50418" itemprop="latitude">
<meta content="-0.08918" itemprop="longitude">
</span>
</div> <!-- detail end tag -->
</div> <!-- item end tag -->
<a class="block-link" data-analytics="Restaurant List|Restaurant Click|offpage" href="heeltap-london-bridge-london" itemprop="url" title="Heeltap (Not yet rated)">Heeltap</a>
</li>
This is the latest code I've tried (out of many, many different attempts):
(I refactored it previously storing the long jQuery selector in variable, and using $(this), but I thought this could be affecting the code so I did it in a straightforward but verbose manner below):
$('.has-distance').each(function(){
var obj = {};
obj["name"] = $(this).find('.block-link').html();
// console.log(nameObject);
// $('.has-distance').find('span[itemprop="geo"]').children().each(function(){
if ( $(this).find('span[itemprop="geo"]').children().attr('itemprop') === "latitude" ) {
obj["lat"] = $(this).find('span[itemprop="geo"]').children().attr('content');
}
else if ( $(this).find('span[itemprop="geo"]').children().attr('itemprop') === "longitude" ) {
obj["lng"] = $(this).find('span[itemprop="geo"]').children().attr('content');
}
console.log(obj);
});
Unfortunately the console log only returns the below, and refuses to also extract the longitude and put it in the object (even though when I do it as a separate .each function the if / else if logic works).
Object {name: "Momo", lat: "51.5112371"}
Object {name: "Pied a Terre", lat: "51.5191"}
Object {name: "Crazy Bear - Fitzrovia", lat: "51.5196971"}
Object {name: "Les Deux Salons", lat: "51.5094799"}
Object {name: "The National Café", lat: "51.508929"}
Object {name: "Athenaeum", lat: "51.50464"}
Object {name: "inamo", lat: "51.5149166"}
Object {name: "The Grill at The Dorchester", lat: "51.50729"}
Object {name: "Planet Hollywood London", lat: "51.5092777"}
Object {name: "The Ritz Restaurant - London", lat: "51.50718"}
Object {name: "Homage Restaurant at The Waldorf Hilton", lat: "51.5121546"}
Object {name: "DSTRKT Restaurant and Bar", lat: "51.5110772"}
Object {name: "Marconi Lounge at ME London", lat: "51.51163"}
Object {name: "Kaspar's Seafood Bar and Grill", lat: "51.510012"}
Object {name: "Hakkasan - Hanway Place", lat: "51.5169686"}
Please help, I'm really stuck here! Many thanks in advance!
Upvotes: 0
Views: 123
Reputation: 659
The sections of your code that extract latitude and longitude are separate branches of an if/else statement, which means only one of them will run for each element matched by the '.has-distance' jQuery selector. If you must test for the existence of the values first, you could just use separate if statements:
$('.has-distance').each(function(){
var obj = {};
obj["name"] = $(this).find('.block-link').html();
if ( $(this).find('span[itemprop="geo"]').children().attr('itemprop') === "latitude" ) {
obj["lat"] = $(this).find('span[itemprop="geo"]').children().attr('content');
}
if ( $(this).find('span[itemprop="geo"]').children().attr('itemprop') === "longitude" ) {
obj["lng"] = $(this).find('span[itemprop="geo"]').children().attr('content');
}
console.log(obj);
});
Though, as noted in my comment below, children().attr() does not iterate through the children automatically. From the jQuery docs on .attr():
Get the value of an attribute for the first element in the set of matched elements or set one or more attributes for every matched element.
So you'll have to iterate through them somehow. You could use .each():
$('.has-distance').each(function(){
var obj = {};
obj["name"] = $(this).find('.block-link').html();
$(this).find('span[itemprop="geo"]').children().each(function() {
if( $(this).attr('itemprop') === "latitude" ) {
obj["lat"] = $(this).attr('content');
}
else if ( $(this).attr('itemprop') === "longitude" ) {
obj["lng"] = $(this).attr('content');
}
});
console.log(obj);
});
Or if you know the structure of the data you're parsing, and you only need a few elements rather than hundreds, you could get rid of the if statement(s) and the nested each() and use something simpler like this:
$('.has-distance').each(function(){
var obj = {};
obj["name"] = $(this).find('.block-link').html();
obj["lat"] = $(this).find('span[itemprop="geo"] > meta[itemprop="latitude"]').attr('content');
obj["lng"] = $(this).find('span[itemprop="geo"] > meta[itemprop="longitude"]').attr('content');
console.log(obj);
});
You might also consider changing how you collect the "name" attribute for your object to something more appropriate:
obj["name"] = $(this).find('[itemprop="name"]').html();
Upvotes: 0
Reputation: 34178
You don't even need the conditionals if you put them in the selector:
$('.has-distance').each(function() {
var obj = {};
obj.name = $(this).find('.block-link').html();
obj.lat = $(this).find('span[itemprop="geo"]').children('meta[itemprop="latitude"]').attr('content');
obj.lng = $(this).find('span[itemprop="geo"]').children('meta[itemprop="longitude"]').attr('content');
console.log(obj);
});
alternately:
$('.has-distance').each(function() {
var obj = {};
obj.name = $(this).find('.block-link').html();
var geo = $(this).find('span[itemprop="geo"]');
obj.lat = geo.children('meta[itemprop="latitude"]').attr('content');
obj.lng = geo.children('meta[itemprop="longitude"]').attr('content');
console.log(obj);
});
Upvotes: 1
Reputation: 366
Try this.
if ($(this).find('span[itemprop="geo"] meta[itemprop="latitude"]').length > 0) {
obj["lat"] = $(this).find('span[itemprop="geo"] meta[itemprop="latitude"]').attr('content');
}
if ( $(this).find('span[itemprop="geo"] meta[itemprop="longitude"]').length > 0) {
obj["lng"] = $(this).find('span[itemprop="geo"] meta[itemprop="longitude"]').attr('content');
}
Or you can do it with $.each loop
$(this).find('span[itemprop="geo"]').children().each(function() {
if ($(this).attr('itemprop') === "latitude" ) {
obj["lat"] = $(this).attr('content');
} else if ( $(this).attr('itemprop') === "longitude" ) {
obj["lng"] = $(this).attr('content');
}
});
Upvotes: 1