MenuMarkup specification

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.

MenuMarkup

MenuMarkup is a super simple markup to specify menu data in plain text. When the MenuMarkup is parsed it creates a Menu. A Menu consists of two types: Items and Sections. Items have multiple Prices.

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.

Markup drilldown

MenuMarkup is based on OpenMenu.org Menu information and Single Platform Menu information.

Comments

Lines starting with # are comments. They are used to include for example the source url of the information.

Sidenotes

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

Items

Lines starting with - are Items. An Item has a title, description and a Price.

- The Item Title
The item description is here.
And goes on for many
many
lines..

To further specify use:

Notation Info
-v- Vegetarian dish
-V- Vegan dish
-k- Kosher dish
-h- Halal dish
Specify spicyness
-n- None
-m- Mild
-M- Medium
-H- Hot

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.

Sidenotes

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

Sections

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

Example:

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

Sidenotes

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

Prices are automagically parsed from Items. However sometimes you might need to be more specific about.

To set a special Price use (for example):

=dagprijs

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:

=

Other examples:

=glas 2,50
=bottle 10,00
=1/2 bottle 5,00

=8 pieces 12.-
=30,00 p.p.

Edge cases

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.

Table d'hôte

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

the **\ will put the word “or”/“of” in between the dishes to show that it is an option to choose between them.

Rice Tables

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