This post describes an initial (internal used) markup for restaurant menus and other pricelists. It is used to semi-automatically parse hundreds of menus into a structured menu format.
A Ruby MenuMarkup parser gem is available on Github.
An example menu
Let’s jump right in with an example menu.
# Lines with a # are comments! # Empty lines are ignored * Main dishes The main dishes can be ordered between 17.00 and 21.00. - Super meat 29.95 euro This is 500 grams of pure super meat. - Some other dish #This dish has the price on a different line. It will be parsed correctly. 12,95 - Daily fish #This differs every day and the price can also change. =depends *Dessert - Special dessert #This dessert has multiple sizes and prices. = small 12,30 = large 23,30 - A desert for 2 = 12,30 per person - 300 grams of chocolate #To not make the price 300 we specify an empty price using '='. =
MenuMarkup is pretty loose. So the following is no problem. You shouldn’t worry about spaces, etc.:
* Starters This are our starters. Enjoy! - Lobster 12 - Meatballs = per person 23,00 Nice round meatbals.
Lines starting with
# are comments. They are used to include for example the source url of the information.
In our (mostly automated) menu scraping and parsing flow we add the following by default:
# Tue Jul 03 2012 15:26:13 GMT+0200 (CEST) # New selection from: http://restaurant.com/menu.pdf
Lines starting with
- are Items. An Item has a
description and a Price.
- The Item Title The item description is here. And goes on for many many lines..
To further specify use:
| ||Vegetarian dish|
| ||Vegan dish|
| ||Kosher dish|
| ||Halal dish|
You can combine the letters above. For example:
-v- This is a vegetarian dish. With a description and a price of 12.30. -kVH- This is a Kosher Vegan Hot dish :) 12.30 The line above is obviously the price and this will be the description.
The most relevant number will be converted to a Price.
A title should not be too long so that the Menu will be pleasurable to watch. You can break down titles by searching for “,” “:” “with” “and” “served”.
Items can be split into Sections. A Section has a
title (single-lined) and a
description. Lines starting with
- are Sections.
- ‘Starters’ (Voorgerechten)
- 'Main courses’ (Hoofdgerechten)
- 'Wine’ (Wijn)
Make sure to put the description about the section directly under the Section Title, and not at the end of the section; Example:
*Starters Starters are served with bread -Soup
* The Section Title The section description is here. And goes on for many many lines.. ** A subsection With more info *** A subsubsection Yep very cool!
When entering the sections make sure they are rather short, so no entire lines. Also make sure there isn’t a “:” behind the section, this is very common in menus but not good for our markup.
If there is a
* at the beginning of an information line in the menu. Make sure you replace it by something else, eg.:
# For example add brackets. (*) All menu items with a * are not available after 18.00 o'clock.
Prices are automagically parsed from Items. However sometimes you might need to be more specific about.
To set a special Price use (for example):
To set multiple Prices using (for example):
=300 gram 12.50 per person =500 gram 19,00 per person
To set min/max Prices use something like:
=Min 12.50 =Max 19,00
If possible while setting the price, make sure the price is the last item in the line:
-Bread = 750 gram € 4,50 = 1,5 kilo € 8,95
So not like:
# This is WRONG -Bread = € 4,50 750 gram = € 8,95 1,5 kilo
To specify an empty Price use:
=glas 2,50 =bottle 10,00 =1/2 bottle 5,00 =8 pieces 12.- =30,00 p.p.
If you find a price in front of the item name. You can use:
-12.20 Some title Some description.
Special Menu Cases
Below you will see some special menu cases that need to be handled in his own way.
Sometimes you are presented with a menu with only a few options with a fixed price. You should represent it in the following markup:
*Keuze Menu =12.50 p.p. alleen per hele tafel **\Voorgerechten -Tomaten Soep -Carpaccio **\Hoofdgerechten -Biefstuk -Kalkoen **\ -Dame Blance -Ijsje
**\ will put the word “or”/“of” in between the dishes to show that it is an option to choose between them.
Rice Tables are menus with a lot of dishes stuffed in to one option. Proposed markup:
-Rice Table 1 (min. 2 personen) =22.50 per person Tod Man Plaa, Viskoekjes Tom Yam Kai, Thaise pikante soep met kipfilet Pad Pak Luom Mid,Thaise groenteschotel met cashewnoten Plaa Sam Rod, Vis filet (tilapia) met chillipepers Keng Kiou Waan Koeng,Garnalen in groene curry saus Koffie Of Thee