CookML-Markup-Language
Definiton of an open recipe and menu data exchange format using XML

Revision:

1.1.2

Status:

Latest release version is 1.1.2

Changed:

16. September 2006

Creator:

Jochen 'Nunz' Herz

Authors:

Jochen Herz, Roland Jesse, Ralf Kürbitz, Rolf Wilhelm, 
Robert Freitag, Uwe Klatt, Werner F. Bruhin
Translated by Werner F. Bruhin">


Specification for an XML format for the exchange of cooking recipes, ingredient information and menus between different programs and countries.

CookML is the description of a recipe exchange format, which allows the exchange of any type of recipes between different programs.

CookML was created out of the need to create an exchange format for the recipe program Kalorio which allowed to transfer all available recipe data. The MealMaster (text format) is a widely used format and is easier to read, however it allows only the transfer of the basic recipe data. CookML was created through an open discussion between different programmers of recipe and catering trade software applications, to ensure that the exchange format would allow the exchange of recipe data between different programs and would not become an isolated solution for one program.

The basis for CookML (CML) is XML (Extensible Markup Language, a W3C standard). It provides the possiblity to exchange any type of additional information for a recipe betwenen different users of different recipe book software applications. This format allows to include images to the recipe, menus and allows to asign a "Bundeslebensmittleschlüssel" (BLS) to ingredients.

Should the current revision of CML not allow for a particular type of recipe data to be exchanged it would be possible to extend the format and to create a new revision by making arrangements with the authors (contact email JoHerz@codev.de).

CML is provided free of charge. Any programmer is allowed, even encouraged to use the format in his program, project, tool or internet portal.

The following are the only conditions to be respected when using CML:

  1. The specifications detailed below have to be respected. It is not allowed to add or change "tags" without making arrangements with the authors for a new revision.

  2. All fields ("tags", "elements") defined in the DTD (Document Type Defininitions) as "#Required" are mandatory and have to be supported as defined by the following specifications and have to be passed on. This is the reason to only have defined the most importend fields as mandatory, to allow for an easy implementation of this standard format.

  3. Every program or project has to provide a link to this page, so that everyone can view the specifications for CML.

  4. When a CookML file is transfered/exported it has to use a file extension of ".cml".


Table of contents:

Introduction
Additional technical documents
Definition of the markup language CookML
Encoding used - UTF-8
Constructing the recipe ID (“rid”)
Permited units for the ingredient description

Additional technical documents:

An up to date version of this document can always be found at: A CML sample file with 3 recipes can be downloaded from here: www.kalorio.de/cml/Example.zip 

The Document-Type-Definition (DTD) for validating CML instance files can be found here: http://www.kalorio.de/cml/cookml.dtd

To validate CML instance files created with your export routines you should use a DTD validator.

Following a few tools which are available free of charge:

An XSD (XML schema definition) file is also available from here: www.kalorio.de/cml/cookml.xsd

For a simple display of a CML instance file in the Internet-Explorer you can use the following XSL (Extensible Stylesheet Language Transformations) file: www.kalorio.de/cml/cookml.xsl

To parse or to create CML instance files you should use the appropriate XML library available for your development environment, you should be able to easily find them using a search engine. The author can also provide you a XML parser he wrote on the bases of the Borland C++ compilers.

Suggestions, corrections or notifications that you use CookML can be sent to: JoHerz@codev.de


Definition of the markup language CookML for the exchange of recipes

 Table of contents:

XML-Header

Standard XML-Header

cookml

Root of the actual data

cookml version

Revision number of the CML specification use to create the instance file

cookml name

Name of the recipe collection contained in this file

cookml prog

Name of the program which generated this instance

cookml progver

Version number of “prog”

cookml recipe

Root of the individual recipe

cookml : recipe : lang

Language used in the recipe

cookml : recipe : head

Informational data to a recipe

cookml : recipe : head : title

Title of the recipe

cookml : recipe : head : rid

Unique recipe identifier

cookml : recipe : head : servingqty

Serving quantity

cookml : recipe : head : servingtype

Unit of serving quantity (person, piece, etc.)

cookml : recipe : head : createdate

Creating date

cookml : recipe : head : createuser

Creator/Recorder of recipe

cookml : recipe : head : createemail

EMail of creator

cookml : recipe : head : changedate

Date of the most recent change

cookml : recipe : head : changeuser

Person, who made the most recent change

cookml : recipe : head : changeemail

EMail of “changeuser”

cookml : recipe : head : timeallqty

Total preparation time for the recipe

cookml : recipe : head : timeprepqty

Preparation time

cookml : recipe : head : timecookqty

Cooking time

cookml : recipe : head : costs

Cost of the recipe

cookml : recipe : head : country

Producing country

cookml : recipe : head : proteins Quantity of proteins
cookml : recipe : head : carbohydrates Quantity of carbohydrates
cookml : recipe : head : fat Quantity of fat

cookml : recipe : head : wwpoints

Weight-Watcher points or something like that

cookml : recipe : head : cat

Categories (recipe grouping)

cookml : recipe : head : hint

Key words for the recipe

cookml : recipe : head : sourceline

Free format information to the recipe source

cookml : recipe : head : card

Detailed description of the recipe (e.g. for a restaurant menu)

cookml : recipe : head : allergies Allergic substances
cookml : recipe : head : allergies : allergy Data for an allergic substance
cookml : recipe : head : allergies : allergy : name Name of the allergic substance
cookml : recipe : head : allergies : allergy : contains Is allergic substance in the recipe

cookml : recipe : head : content

Information on substances contained in recipe ingredients

cookml : recipe : head : content : type

Type of substance

cookml : recipe : head : content : value

Value/quantity of substance

cookml : recipe : head : picture

Image of the recipe

cookml : recipe : head : picture : file

Path to the image, either local or on the web

cookml : recipe : head : picbin

Image of the recipe, embedded in the XML file

cookml : recipe : head : picbin : format

Format of the embedded image

cookml : recipe : custom

Field for additional data

cookml : recipe : custom : name

Name of the “custom” field

cookml : recipe : custom : datatype

Data type of the “custom” field

cookml : recipe : custom : value

Value of the “custom” field

cookml : recipe : part

Grouping of an ingredient unit

cookml : recipe : part:: title

Title of the ingredient unit

cookml : recipe : part:: ingredient 

Ingredient (root of each ingredient)

cookml : recipe : part : ingredient : qty

Required quanity of ingredient

cookml : recipe : part : ingredient : unit

Unit of the ingredient

cookml : recipe : part : ingredient : item

Name of the ingredient

cookml : recipe : part : ingredient : inote

Additional information, explanations to the ingredient

cookml : recipe : part : ingredient : bls

The ingredients BLS-Code (BLS - Bundeslebensmittelschlüssel

cookml : recipe : part : ingredient : gram

Approximite value in grams for units which are not directly convertible

cookml : recipe : part : ingredient : shop

Flag, ob Zutat auf Einkaufslisten soll

cookml : recipe : part : ingredient : calc

Flag, to define if ingredient should be considered in the nutrional calculation

cookml : recipe : part : ingredient : ridlink

RID to a recipe which is used as an ingredient

cookml : recipe : part : ingredient : preparation

Preparation instructions for this particular ingredient

cookml : recipe : preparation

Preparation/Recipe instructions

cookml : recipe : preparation : text

Preparation instructions as a block of text

cookml : recipe : preparation : step

Prepartion instructions as individual steps

cookml : recipe : remark

Remarks of a user/cook

cookml : recipe : remark : user

The name of the person making the remark

cookml : recipe : remark : line

The remark

cookml : menu

The root of a menu

cookml : menu : title

Name of the menu

cookml : menu : mcustom

Field for additional data

cookml : menu : mcustom : name

Name of the “mcustom” field

cookml : menu : mcustom : datatype

Data type of the “mcustom” field

cookml : menu : mcustom : value

Value of the “mcustom” field

cookml : menu : mrecipe

Recipe of a menu

cookml : menu : mrecipe : title

Title of the recipe menu item

cookml : menu : mrecipe : rid

rid” - recipe identifier of the recipe menu item

cookml : menu : mrecipe : amount

Quantity for the recipe menu item (in the unit of the recipe)

cookml : menu : mrecipe : persons

Quantity of the menu item (always in the unit “person”)

cookml : menu : mrecipe : desc

Additional information to the recipe menu item




XML-Header

XML-Standard-Header
Following header lines have to be implemented according to the XML-Standard.
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet href="cookml.dtd" type="text/dtd"?>
<?xml-stylesheet href="cookml.xsl" type="text/xsl"?>

Supported:

all


cookml

"cookml" is the root of all recipes and menus.
The tags “prog” and “progver” are programm-specific and should be filled with the program name and its version number of the program generating the XML instance.
<cookml version=" 0.1" prog="cook" progver="2.01">

Supported:

all


cookml : version

Revision number of the specification.
Version contains the revision number of the CookML specifications which were used to create the instance.

Data type:

string, XML-Attribut

Supported:

mandatory.

Compatibility:

all


cookml : name

Name of the recipe collection.
Often recipe collections are put together and these should be named (e.g. "rec.mampf.de 01-03/2002"), in a CML instance this name should be entered here.

Data type:

string, XML-Attribut

Supported:

optional

Compatibility:



cookml : prog

Name of the generating program.
The program which generates the CML instance file has to enter it's name here. This is very important information, together with “progver” it helps in tracking down problems and is therefore mandatory.

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

all


cookml : progver

Version number of the generating program.
Description see 'cookml:prog'.

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

all


cookml : recipe

"recipe" introduces a new recipe.
This tag represents the root of each recipe, it is allowed to include an unlimited number of recipes in an CML instance file.

Data type:

complex typ, XML-Element, sequence

Supported:

mandatory

Compatibility:

Ambrosia, Kalorio


cookml : recipe : lang

"lang" defines the language in which the recipe is written
In prinzipal the program does not care about this, however it is important if a program wants to translate things (e.g. such things like recipe units “oz” to “gram”) or it is helpful for search engines.


The permited entries are defined by the ISO639-2 standard and can be found here: http://lcweb.loc.gov/standards/iso639-2/englangn.html

Data type:

string, XML-Attribut, unique

Supported:

Has to be defined for each recipe and applications have to support it.

Compatibility:

all


cookml : recipe : head

"head" introduces a section with additional information about the recipe

Data type:

complex type, XML-Element, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : title

"title" defines the name of the recipe
The length is in prinicpal unlimited, however one should keep it reasonable to prevent problems when printing or in the case when the recipe is passed on in the “Mealmaster” format which limits this to 64 characters.

Data type:

string, XML-Attribut from head, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : rid

"RID" marks each recipe with a world wide unique indentifier
When a recipe is created a unique ID has to be generated for the recipe, which is unique across different computer systems. This allows to refere to another recipe (e.g. a pastry recipe can become an ingredient in the current recipe), or it can be used when creating menus.

The program which used such an indentifier first was Ambrosio, therefore the format of the “Ambrosio-Ident” has been adopted for CookML.

At the end of this document is a section “Structure of Recipe-ID”, which describes how the RID is constructed.

Data type:

string, XML-Attribut from head, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : servingqty

How many units (persons, pieces etc.) will this recipe make.
In “servingqty” one defines the quantity and in “servingtype” one defines the type of units used.

Data type:

string, XML-Attribut from head, unique

Supported:

mandatory.

Compatibility:

all


cookml : recipe : head : servingtype

In which unit is the quantity defined (person, pieces etc.)
See under cookml:recipe:head:servingqty for description.

Data type:

string, XML-Attribut from head, unique

Supported:

mandatory.

Compatibility:

all


cookml : recipe : head : createdate

Creation date
The date and time of the recipe creation is entered here. It is not allowed to change this!.

The date is encoded in ISO 8601 format, e.g: "2003-02-16T10:00:00"

Data type:

string, XML-Attribut from head, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : createuser

Creator/Recorder of recipe
The name of the creator of the recipe is entered here.

Data type:

string, XML-Attribut from head, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : createemail

EMail of creator/recorder
The Email address of the creator is entered hier, this can be useful when one wants to contact the person.

Data type:

string, XML-Attribut from head, unique

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : head : changedate

Date of the most recent change
The date and time of the recipe change is entered here. The date of the previous change is overwritten.

The date is encoded in ISO 8601 format, e.g: "2003-02-16T10:00:00"

Data type:

string, XML-Attribut from head, unique

Supported:

Each recipe has to have this and the applications have to support it

Compatibility:

all


cookml : recipe : head : changeuser

Person who made the last change(s)
The name of the person who made the changes is entered here, the previous information is overwritten.

Data type:

string, XML-Attribut von head, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : changeemail

EMail of “changeuser”
The Email address of the “changeuser” is entered here, the previous information is overwritten.

Data type:

string, XML-Attribut from head, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head :timeallqty

Total time for the recipe preparation
timeallqty” defines the total time needed to prepare this recipe.

The time is always expressed in minutes.

Data type:

non negative integer, XML-Attribut from head, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : timeprepqty

Time for the preparation of the recipe
Defines the time required to make the preparations for the recipe.

The time is always expressed in minutes.

Data type:

non negative integer, XML-Attribut from head, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : timecookqty

Time for cooking the recipe
Defines the time required to cook the recipe.

The time is expressed in minutes.

Data type:

non negative integer, XML-Attribut from head, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : costs

Cost for the recipe
Defines the cost of the recipe in colloquial language. Programs will do not processing based on this, it is just informational data.

Data type:

string, XML-Attribut from head, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : country

Producing country
Descripes the country or area, from which the recipe comes from.

Data type: string, XML-attribut of head
Supported: optional
Compatibility: KalorioNext

cookml : recipe : head : proteins

Quantity of proteins
Describes the quantity of proteins from the calories.
All data should be given for one portion, so the portion-calculations must not recalc this string-data.

Datentyp: string, XML-Attribut, Singulär
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : carbohydrates

Quantity of carbohydrates
Describes the quantity of carbohydrates from the calories.
All data should be given for one portion, so the portion-calculations must not recalc this string-data.

Datentyp: string, XML-Attribut, Singulär
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : fat

Quantity of fat
Describes the quantity of fat from the calories.
All data should be given for one portion, so the portion-calculations must not recalc this string-data.

Datentyp: string, XML-Attribut, Singulär
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : wwpoints

Weight-Watcher points
The Weight-Watcher users have often contacted me, that they require a field to record the points. The points will be assigned to a recipe as a whole and for all the portions defined for the recipe.

Data type:

float, XML-Attribut, unique

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : head : cat

Categories (recipe groupings)
In each “cat” element one defines a recipe category. The recipe categories are not defined, are therefore left to the user and can be different from user to user.

It is planned to standardise a certain number of categories.

Data type:

string, XML-Element, sequence

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : sourceline

Source
If the source of the recipe is known, one should (to be fair to the original author) use this element to provide this information.

Data type:

string, XML-Element, sequence

Supported:

mandatory

Compatibility:

all


cookml : recipe : head : hint

Key words for the recipe
For each recipe any number of key words can be defined. Often this key words are used for searches. Contrary to “ing:cat” there are not plans to standardize these, therefore anyone can define words which work for them.

Data type:

string, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : card

Detailed description of the recipe (e.g. for restaurant menu)
If a recipe collection is used to create a restaurant menu these elements can be used to provide further explanation of the recipe or to translate the description into other languages.

Data type:

string, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia


cookml : recipe : head : content

Content of a recipe (by substance)
Here you can enter the total of all ingredients for a certain substance as per the Bundelebensmittelschlüssel. Most programs will define here the calories, but it could also be used for things such as vitamines or bread units etc.

A record is made up of 2 parts: The substance (key = short name as per Bundelebensmittelschlüssel) and the quantity (same unit as defined in the Bundelebensmittelschlüssel).

Exceptions:
1. only quantitativ BLS-substances (the BLS database defines this information). Strings like e.g. “BLS-Code” are not useful here, it is also defined in this list.

Example:
<content type="GCAL" value="627"/> // Calories in kCal
<content type="GKB" value="42"/> // bread units

Data type:

complex type, XML-Element, sequence

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : head : content : type

Code of the substance
Description see recipe:content

Data type:

string, XML-Attribut from content

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : allergies

Allergic substances
All allergic substances are collected in this tag

Datentyp: string, XML-Element, Single
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : allergies : allergy

Data of an allergic substance
Data for one allergic substance.

Datentyp: string, XML-Element, Sequenz
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : allergies : allergy : name

Name of the allergic substance

Datentyp: string, XML-Element
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : allergies : allergy : contains

Is the substance containing
'F'=free of this substance, 'C'-contains this substance

Datentyp: string, XML-Element
Unterstützung: Optional
Kompatibilität: Kalorio

cookml : recipe : head : content : value

Quantity of the substance
Description see recipe:content

Data type:

string, XML-Attribut von content

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : picture

Recipe image (file name)
Define here the image of the recipe in the form of a file name, without the path. The file is only locally on the user hard disk, this is only useful if the file hirarchy is always the same or if the images are stored in a defined folder.

Data type:

complex type, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : picture : file

Path to the image file, local or on the network
Define here the image file name or a complet URL (e.g. http://www.somewebsite.com/anyfilename.JPG), the format is not defined but JPG is prefered due to it's common use and support.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : recipe : head : picbin

Recipe image embedded in the XML instance as binary data
The image is embedded in the XML instance file, the image has to be mime64 encoded.

Data type:

mime64, XML-Element, sequence

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : head : picbin : format

Format of the image file
To ensure a good/correct handling of the embedded image, you have to provide the format of the image.

You have to use one of the following extension in upper case only.
Currently supported: BMP, JPG, PNG, TIF

Data type:

string, XML-Attribut, unique

Supported:

mandatory

Compatibility:

Kalorio


cookml : recipe : head : custom

Custom element definiton
This tag allows to include any type of information not currently supported by CookML. Keep in mind that this information will not be processed by other programs and one should not use this extensively, instead you should contact the author and request an enhancement/inclusion into the CookML standard for the type of information you want to pass on using the tag.

"custom" is made up of the attributes "name", "datatype" and "value", which should all be self explanatory.

Data type:

string, XML-Element, sequence

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : head : custom : name

Name of a custom element
Description see "cookml:recipe:custom"

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

Kalorio


cookml : recipe : head : custom : datatype

Data type of a costum field
Description see "cookml:recipe:custom"

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:



cookml : recipe : head : custom : value

Wert eines freien Feldes
Beschreibung siehe "cookml:recipe:custom"

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

Kalorio


cookml : recipe : part

Definition of an ingredient group
Ingredients are often sorted to form groups (e.g. Pastry, Filling). You can define such a group here. You can assign a heading to this group using the attribute title.

Data type:

complex type, XML-Element, sequence

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : title

Definition of an ingredient group
Ingredients are often sorted to form groups (e.g. Pastry, Filling). You can define such a group here. You can assign a heading to this group using the attribute title.

Data type:

complex type, XML-Attribut

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : ingredient

Ingredient (root of an ingredient)
The start of a new ingredient.

Data type:

complex type, XML-Element, sequence

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : ingredient : qty

Quantity of the ingredient
Enter here a number for the quantity of the ingredient. The number refers to “ing:unit”. Only decimal numbers are allowed. Fractions have to be converted to a float.

Data type:

float, XML-Attribut, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : ingredient : unit

Unit of the ingredient
The unit of the ingredient description. To ensure that recipes can easier be exchanged internationaly, it is not allowd to use nationaly accepted units, only american units defined in the following chapter are allowed "Permitted units". These units are based on the quasi-standard “Meal-Master.

Data type:

string, XML-Attribut, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : ingredient : item

Name of the ingredient
The name of the ingredient. Only the name is to be entered here, no description (which is to be entered in “ingredient:inote”). Therefore instead of entering “Finely chopped onions” you are to only enter “Onions” and in the “ingredient:inote” you enter “finely chopped”

Data type:

string, XML-Attribut, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : ingredient : inote

Additional description to the ingredient
See “ingredient:item” for the description.

Data type:

string, XML-Element from head, sequence

Supported:

mandatory

Compatibility:

all


cookml : recipe : part : ingredient : bls

The approriate BLS-Code for the ingredient
The BLS-key which corresponds to the ingredient or comes closest. By assigning a BLS-key to an ingredient it is possible to calculate the substances of the recipe.

Important: Even so your program does not support BLS you have to pass on the BLS information in your Import/Export routines.

Data type:

string, XML-Attribut, unique

Supported:

Support is optional, however you have to pass data through.

Compatibility:

Ambrosia, Kalorio


cookml : recipe : part : ingredient : gram

Approximate value in gram for units which are not directly convertible
Some units can not be converted directly. For a calculation of nutritients when using the BLS-code (Bundelebensmittelschlüssel) it is necessary to have a value in gram, which can be entered here. It allows you to define for example for an ingredient “1 package vanille pouder” that it is 30 gram, having done this ones, during the recipe creation or when changing it, that any time later you can calculate the nutritients of the recipe.

Data type:

non negative integer, XML-Attribut, unique

Supported:

Support is optional, however you have to pass data through.

Kompatibiltät:

Ambrosia, Kalorio


cookml : recipe : part : ingredient : shop

Flag, should ingredient be included in shopping list
If this is “false” then ingredient should not be included in shopping list, is it “true” or missing then ingredient should be included in list.

Data type:

bool ("true" oder "false"), XML-Attribut, unique

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : part : ingredient : calc

Flag, should ingredient be included in nutrient calculation
When calculating the nutrient values there are always ingredients which should not be included (e.g. the oil for a friteuse), if this element is set to “N” then the ingredient will be ignored, if it is set to “Y” or not present then the ingredient will be included in the calculation.

Data type:

string, XML-Attribut, unique

Supported:

Support is optional, however you have to pass data through.

Compatibility:

Kalorio


cookml : recipe : part : ingredient : ridlink

RID of a recipe that is used as an ingredient
Many recipes require an ingredient which in itself is a recipe (a base sauce, a dough, etc). In this case one can define here a “rid” which links to the recipe.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:



cookml : recipe : part : ingredient : preparation

Preparation instructions for the ingredient
Sometimes recipes are recorded/entered with preparation instruction text being linked with the ingredient. An excample could be “100 g butter melted down in a pot”, “200 g onions steamed in it until transparent”.

These should be entered here, however as this tag is optional and not all programs support it it is necessary to duplicate these instructions in cookml:recipe:preparation:text.

Data type:

string, XML-Attribut, unique

Supported:

optional


cookml : recipe : preparation

Preparation instructions for recipe
This element encloses all instruction steps, there are two variations:

  1. All the preparation instructions are entered in the tag “text” as a block of text with paragraphs etc.

  2. Each prepartion step is enclosed in its own tag “step”. One can have an unlimited number of preparation steps.

This element is defined as a “choice”, so you are allowed to include one or the other variation for a recipe, but you are not allowed to mix and match them for the same recipe.

Data type:

string, XML-Element, unique, choice

Supported:

mandatory

Compatibility:

all


cookml : recipe : preparation : text

Preparation instructions as a text block
See description under "preparation"

Data type:

string, XML-Element, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : preparation : step

Preparation instructions as steps
See description under "preparation"

Data type:

string, XML-Element, unique

Supported:

mandatory

Compatibility:

all


cookml : recipe : remark

Remarks of a user
In each “remark” element can a user include specific remarks to the recipe.

Data type:

complex type, XML-Element, sequence

Supported:

optional

Compatibility:



cookml : recipe : remark : user

The name of the user of the remark
Used to record the name of the user having made the remark.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:

Kalorio


cookml : recipe : remark : line

A short remark
Enter here a short remark

Data type:

string, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia, Kalorio


cookml : menu

The start of a menu
Besides recipes cookML supports also the transfer of menus. A menu definition is a list of recipes, which are defined externaly. The recipes has to be included in the same file, however only in the cookml:recipe root element and not as part of the menu.

Data type:

complex type, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia


cookml : menu : title

Name of the menu
Each menu has to have a nice name to be able to sell it, this is were it is recorded.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:

Ambrosia


cookml : menu : mcustom

Custom element definiton
This tag allows to include any type of information not currently supported by CookML. Keep in mind that this information will not be processed by other programs and one should not use this extensively, instead you should contact the author and request an enhancement/inclusion into the CookML standard for the type of information you want to pass on using the tag.

"custom" is made up of the attributes "name", "datatype" and "value", which should all be self explanatory.

Data type:

string, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia


cookml : menu : mcustom : name

Name of the custom field
Description see "cookml:recipe:mcustom"

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

Ambrosia


cookml : menu : mcustom : datatype

Data type of the custom field
Description see "cookml:recipe:mcustom"

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

Ambrosia


cookml : menu : mcustom : value

Value of a custom field
Description see "cookml:recipe:mcustom"

Data type:

string, XML-Attribut

Supported:

mandatory

Compatibility:

Ambrosia


cookml : menu : mrecipe

Recipe of a menu
Here you can define a recipe after the other to create a menu.
Important: All recipes listed in a menu have to be included in the same CML instance file, otherwise it is will happen to often that a recipe is not available when importing the CML instance.

Data type:

complex type, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia


cookml : menu : mrecipe : amount

Quantity of recipe
The quantity defined here defines how much of the recipe should be prepared for this menu. The unit is as per the definition of the recipe.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:

Ambrosia


cookml : menu : mrecipe : persons

Number of persons to be served
This defines the number of persons for which this menu item is to be served.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:



cookml : menu : mrecipe : rid

Recipe “rid” of the menu item
A menu structure does not include recipe data, a recipe is just linked to using recipe:RID.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:



cookml : menu : mrecipe :title

Name of the recipe item
Just to double up, here the title of recipe, just in case that the “rid” is not found.

Data type:

string, XML-Attribut, unique

Supported:

optional

Compatibility:

Ambrosia


cookml : menu : mrecipe : desc

Description of the menu item
You can define here a description of the recipe which is better adapted to the particular position of it in the menu or to provide further details on it.

Data type:

string, XML-Element, sequence

Supported:

optional

Compatibility:

Ambrosia


Encoding used:

CML files have to be encoded using the UTF-8 character set.
UTF-8 is the simpliest form of Unicode:

  • Each ASCII character with a value of <127 ASCII is still used as the ASCII character.

  • Special characters with a value of >127 ASCII will be encoded as 16-bit Unicode (2 bytes per character)

  • Most libraries/development tools will do this encoding for you, however should you have to program this yourself following a translation chart.

Ä (0xC384)

ä (0xC3A4)

À (0xC380)

à (0xC3A0)

Á (0xC381)

á (0xC3A1)

 (0xC382)

â (0xC3A2)

à (0xC383)

ã (0xC3A3)

 

 

È (0xC388)

è (0xC3A8)

É (0xC389)

é (0xC3A9)

Ê (0xC38A)

ê (0xC3AA)

Ë (0xC38B)

ë (0xC3AB)

 

 

Ì (0xC38C)

ì (0xC3AC)

Í (0xC38D)

í (0xC3AD)

Î (0xC38E)

î (0xC3AE)

Ï (0xC38F)

ï (0xC3AF)

Ö (0xC396)

ö (0xC3B6)

Ò (0xC392)

ò (0xC3B2)

Ó (0xC393)

ó (0xC3B3)

Ô (0xC394)

ô (0xC3B4)

Õ (0xC395)

õ (0xC3B5)

Ü (0xC39C)

ü (0xC3BC)

Ù (0xC399)

ù (0xC3B9)

Ú (0xC39A)

ú (0xC3BA)

Û (0xC39B)

û (0xC3BB)

 

 

ß (0xC39F)

Æ (0xC386)

æ (0xC3A6)

Ç (0xC387)

ç (0xC3A7)

Ñ (0xC391)

ñ (0xC3B1)

 

 

 

° (0xC2B0)

© (0xC2A9)

¼ (0xC2BC)

½ (0xC2BD)

¾ (0xC2BE)

ø (0xC3B8)

 

 

 

 


Construction of the recipe id (rid):

The recide id (rid) has to be constructed always in the same way. Here we use the ID structure from Rolf Wilhelm, which he used in his recipe program Ambrosia, which has found general acceptance.

The cookML recipe ID is made up of two 32 bit values.

Value 1:
Coded date Bit 0-30

 

3

2

1

0

 

Bit

1

0

9

8

7

6

5

4

3

2

1

0

9

8

7

6

5

4

3

2

1

0

9

8

7

6

5

4

3

2

1

0

 

 

-

year - 1980
(11 bits)

month
(4 bits)

days
(5 bits)

hours
(5 bits)

minutes
(6 bits)

 

example

12:09, 16-09-2006

0

0

0

0

0

0

0

1

1

0

1

0

1

0

0

1

1

0

0

0

0

0

1

1

0

0

0

0

1

0

0

1

= 27886345


Value 2:

 

3

2

1

0

 

Bit

1

0

9

8

7

6

5

4

3

2

1

0

9

8

7

6

5

4

3

2

1

0

9

8

7

6

5

4

3

2

1

0

 

 

creator ID
(12 bits)

serial ID
(20 bits)

example

creator id 70, serial 783150

0

0

0

0

0

1

0

0

0

1

1

0

1

0

1

1

1

1

1

1

0

0

1

1

0

0

1

0

1

1

1

0

= 74183470



Creator-ID:
The systems user name (login name) is summed up in the following way:
For each character (in upper case): Creator-ID += Ascii(character) * character-position
Character-position: 1-n

 

W

B

R

U

H

I

N

ordinal value

87

66

82

85

72

73

78

*

position

1

2

3

4

5

6

7

=

 

87

132

246

340

360

438

546

= 2149


As over runs are ignored, and the user name is converted to upper case for this calculation the final result is: 101

Serial-ID:
Starting with a random number which is increased by 1 (if multiple serial id's are generated at once), any over runs are ignored.

Updating a RID:
If an object (recipe) has a valid “RID” one updates only the date portion, the Serial-ID and the Creator-ID will never be changed.

This is a change compared to the first version of cookML!



Following some example code (maybe these should be kept in a files and just be linked from here????).

Here is the implementation from Ralf Wilhelm in VB:

VERSION 1.0 CLASS

BEGIN

MultiUse = -1 'True

END

Attribute VB_Name = "ClFingerprint"

Attribute VB_GlobalNameSpace = False

Attribute VB_Creatable = True

Attribute VB_PredeclaredId = False

Attribute VB_Exposed = False

Option Explicit


Private Type TBinFingerprint ' binary type (db storage only)

FP1 As Long

FP2 As Long

End Type


Private Type TFingerprint ' decoded type (analyseable version)

Datum As Date

CreatorID As Long

Counter As Long

End Type


Dim IsInitialised As Boolean

Dim fp As TFingerprint, fpbin As TBinFingerprint

Dim UserNameString As String



Sub UpdateFingerprint(Optional ByVal Userid As String = "", Optional ByVal Datum As Date = 0)


DoInitialize

If Datum = 0 Then Datum = Now

fp.Datum = Datum

If Len(Userid) > 0 Then fp.CreatorID = GetFingerprintAktCreator(Userid)

Convert2Bin

End Sub


Property Let FP1(ByVal FP1 As Long)


IsInitialised = True

fpbin.FP1 = FP1

Convert2Data

End Property


Property Let FP2(ByVal FP2 As Long)

IsInitialised = True

fpbin.FP2 = FP2

Convert2Data

End Property


Property Get FP1() As Long


DoInitialize

FP1 = fpbin.FP1

End Property


Property Get FP2() As Long


DoInitialize

FP2 = fpbin.FP2

End Property


Property Let CreatorID(ByVal ID As Long)

IsInitialised = True

fp.CreatorID = ID

Convert2Bin

End Property


Property Get CreatorID() As Long


DoInitialize

CreatorID = fp.CreatorID

End Property


Property Let Datum(ByVal d As Date)


IsInitialised = True

fp.Datum = d

Convert2Bin

End Property


Property Get Datum() As Date


DoInitialize

Datum = fp.Datum

End Property


Property Let Serial(ByVal Serial As Long)


IsInitialised = True

fp.Counter = Serial

Convert2Bin

End Property


Property Get Serial() As Long


DoInitialize

Serial = fp.Counter

End Property


Sub Update()


If Not IsInitialised Or fp.CreatorID = 0 Or fp.Counter = 0 Then

IsInitialised = False

DoInitialize

End If

IsInitialised = True

fp.Datum = Now

Convert2Bin

End Sub


Sub Convert2Data()


Dim Y As Long, d As Long, m As Long, H As Long, mi As Long

With fpbin

Y = 1980 + ((.FP1 And &HFFF00000) / (2 ^ 20))

m = ((.FP1 And &HF0000) / (2 ^ 16))

d = ((CLng(.FP1) And &HF800&) / (2 ^ 11))

H = ((.FP1 / (2 ^ 6)) And &H1F)

mi = (.FP1 And &H3F)

fp.Datum = DateSerial(Y, m, d) + TimeSerial(H, mi, 0)

fp.CreatorID = (Abs(.FP2) \ (2& ^ 20)) And &H7FF

If .FP2 < 0 Then fp.CreatorID = fp.CreatorID + 2048

fp.Counter = (Abs(.FP2) And &HFFFFF)

'Debug.Print "FP de:"; FP.Datum, FP.CreatorID, FP.Counter, "("; .FP1; .fp2; ")"

End With

If fpbin.FP1 = 0 And fpbin.FP2 = 0 Then IsInitialised = False


End Sub


Sub Convert2Bin()


Dim Y As Long


With fp

Y = Year(.Datum) - 1980

fpbin.FP1 = (Y * (2& ^ 20)) + _

(Month(.Datum) * (2 ^ 16)) + _

(Day(.Datum) * (2 ^ 11)) + _

(Hour(.Datum) * (2 ^ 6)) + _

Minute(.Datum)

fpbin.FP2 = ((.CreatorID And &H7FF) * (2& ^ 20)) + _

(.Counter And &HFFFFF)

If .CreatorID > 2047 Then fpbin.FP2 = -fpbin.FP2

' Debug.Print "FP en:"; FP.Datum, FP.CreatorID, FP.Counter, "("; FPBin.FP1; FPBin.fp2; ")"

End With


End Sub



Function CompareFingerprint(ByVal FPBIN1 As Long, ByVal FPBIN2 As Long) As Long

' Ergebnis:

' 0 = Identisch

'-1 = FP1 älter wie FP2

'+1 = FP2 jünger wie FP2

'-2 = unterschiedliche Objekte, aber Objekt 1 ist älter wie Objekt 2

'+2 = unterschiedliche Objekte, aber Objekt 1 ist jünger wie Objekt 2


Dim ObjectID As Long

Dim FPB2 As TBinFingerprint

Dim a As String, i As Long

FPB2.FP1 = FPBIN1

FPB2.FP2 = FPBIN2


' Gleichheit schneller auf binärer Ebene klären ...

If fpbin.FP1 = FPB2.FP1 And fpbin.FP2 = FPB2.FP2 Then

CompareFingerprint = 0

Else

ObjectID = 1

If fpbin.FP2 <> FPB2.FP2 Then

ObjectID = 2 ' es liegen verschiedene Objekte vor !

End If

i = Sgn(fpbin.FP1 - FPB2.FP1) * ObjectID

If fpbin.FP1 = 0 And FPB2.FP2 <> 0 Then i = 1 * ObjectID

If FPB2.FP1 = 0 And fpbin.FP1 <> 0 Then i = -1 * ObjectID

CompareFingerprint = i

End If

End Function


Property Get FingerprintInfoTextCRLF() As String

FingerprintInfoTextCRLF = GetFingerprintInfoText(True)

End Property


Property Get FingerprintInfoText() As String

FingerprintInfoText = GetFingerprintInfoText(False)

End Property


Private Function GetFingerprintInfoText(ByVal IncludeCRLF As Boolean) As String


Dim a As String, crlf As String

crlf = Switch(IncludeCRLF, vbCrLf, True, " ")

If fp.CreatorID = 0 And fp.Counter = 0 Then

a = ResolveResString(609)

Else

a = Switch(IncludeCRLF, ResolveResString(610) & crlf & ResolveResString(611), True, ResolveResString(612)) & _

fp.Datum & ResolveResString(613) & Format$(fp.Counter, "000,000") & ")." & crlf & _

ResolveResString(614)

If fp.CreatorID <> GetFingerprintAktCreator Then a = a & ResolveResString(615)

a = a & ResolveResString(616)

End If

GetFingerprintInfoText = a

End Function



Private Sub Class_Initialize()


IsInitialised = False


End Sub


Private Sub DoInitialize()


If Not IsInitialised Then

IsInitialised = True

With fp

.Datum = Now

If EditLastFPCounter = 0 Then

Randomize CLng(CDbl(Now - CLng(Now)) * 10000&)

EditLastFPCounter = Rnd * &HFFFFF

End If

EditLastFPCounter = ((EditLastFPCounter + 1) And &HFFFFF)

.Counter = EditLastFPCounter

.CreatorID = GetFingerprintAktCreator And &H7FF

End With

Convert2Bin

End If

End Sub


Sub Initialize()


IsInitialised = False

DoInitialize

End Sub



Function GetWinuserid() As String


Dim i As Long

If Len(UserNameString) = 0 Then

UserNameString = Space$(64)

If GetUserName(UserNameString, 63) Then

i = InStr(UserNameString, Chr$(0))

If i > 0 Then UserNameString = Left$(UserNameString, i - 1)

End If

UserNameString = UCase$(UserNameString)

End If

GetWinuserid = UserNameString

End Function


Public Function GetFingerprintAktCreator(Optional ByVal UserIDX As String = "", Optional ByVal OldModeUser As Boolean = False) As Long


Static LastUI As Long

Dim Userid As String

Dim i As Long, tempui As Long


If Len(UserIDX) Then

UserIDX = UCase$(UserIDX)

tempui = 0

For i = 1 To Len(UserIDX)

tempui = tempui + (Asc(Mid$(UserIDX, i, 1)) * i)

Next i

If Not OldModeUser Then tempui = tempui And &HFFF

ElseIf LastUI = 0 Then

Userid = GetWinuserid()

LastUI = 0

For i = 1 To Len(Userid)

LastUI = LastUI + (Asc(Mid$(Userid, i, 1)) * i)

Next i

If Not OldModeUser Then LastUI = LastUI And &HFFF

tempui = LastUI

Else

tempui = LastUI

End If

GetFingerprintAktCreator = tempui

End Function


Property Get Winuserid() As String

Winuserid = GetWinuserid()

End Property



Function InfotextAndSource(ByVal Source As Long, ByVal IDate As Date) As String


Dim a As String

Dim Erg As String

Erg = ""

If fpbin.FP2 = 0 Then

'

Else

Erg = Me.FingerprintInfoText()

End If

a = ""

If Source = 0 Then

a = ResolveResString(710)

ElseIf Source = 1 Then

a = ResolveResString(711)

Else

Select Case Source

'2=MM Text-Import, 3=MM Base-Import, 4=MasterCook, 5=..., 6=CookML

Case 2: a = ResolveResString(712)

Case 3: a = ResolveResString(713)

Case 4: a = ResolveResString(714)

Case 5: a = ResolveResString(715)

Case 6: a = ResolveResString(730)

End Select

a = ResolveResString(716) & IDate & ResolveResString(717) & a & ResolveResString(718)

End If

If Len(a) Then Erg = Erg & vbCrLf & a


InfotextAndSource = Erg

End Function




And here an example in Python with some test output from Werner Bruhin.

import wx


import datetime

import math

import random

def GenerateRID():

# first part, the date

rdate = datetime.datetime.now()

print 'input date: %s' % rdate

datebin = int(((rdate.year - 1980) * math.pow(2, 20)) + \

(rdate.month * math.pow(2, 16)) + \

(rdate.day * math.pow(2, 11)) + \

(rdate.hour * math.pow(2, 6)) + \

rdate.minute)


# second part, creator id and serial id

uid = wx.GetUserId()

## uid = 'letstrywithareallylongone' # test for a longer id

uid = 'wbruhin'

print 'input user id: %s' %uid


# creator id calculation

uidBin = int(0)

for x in range(len(uid)):

cval = ord(uid[x].upper()) * (x+1)

## print 'char calc: %s, ord: %s, value: %s' % (uid[x].upper(), ord(uid[x].upper()), cval)

uidBin += cval

print 'creator id before cut off: %s' % uidBin

uidBin = uidBin & 0xff

print 'creator id: %s' % uidBin


# serial id

serial = random.randint(0, 999999)

print 'serial id: %s' % serial

part2 = int(((uidBin & 0x7ff) * math.pow(2, 20)) + (serial & 0xfffff))


if uidBin > 2047:

part2 = - part2

return '%s, %s' % (datebin, part2)



def DecodeRID(rid):

p1, p2 = rid.split(',')

datebin = int(p1)

part2 = int(p2)

# decode the date part

y = int(1980 + ((datebin & 0xfff00000) / math.pow(2, 20)))

m = int(((datebin & 0xf0000) / math.pow(2, 16)))

d = int(((datebin & 0xf800) / math.pow(2, 11)))

h = int((datebin / math.pow(2, 6))) & 0x1f

min = int(datebin) & 0x3f

rdate = datetime.datetime(y, m, d, h, min)


# decode part 2

if part2 < 0:

uid = int((part2) / math.pow(2, 20)) & 0x7ff

uid += 2048

serial = int(-part2) & 0xfffff

else:

uid = int((part2) / math.pow(2, 20)) & 0x7ff

serial = int(part2) & 0xfffff

return (rdate, uid, serial)


# get a rid

rid = GenerateRID()

print 'generated rid: %s' % rid


print '--------------'

# decode the rid

rdate, uid, serial = DecodeRID(rid)

print 'decoded date: %s' % rdate

print 'decoded uid: %s' % uid

print 'decoded serial: %s' % serial



It will produce the following result when running it (obviously the date would change):

input date: 2007-12-27 13:19:30.113000

input user id: wbruhin

creator id before cut off: 2149

creator id: 101

serial id: 637108

generated rid: 29154131, 106543284

--------------

decoded date: 2007-12-27 13:19:00

decoded uid: 101

decoded serial: 637108




Permited units for ingredients

CookML is an international format. Due to this all units have to use the american format detailed below and if necessary have to do the required conversion.
The following list shows on the left the permitted units and on the right the approximate German equivalent.

The list is based on the units used by the Mealmaster standard, this should facilitat the exchange of recipes with that format.

fl fluid ounce

~ 30 ml

x per serving 

pro Portion

c cup 

= 250 ml

sm small 

klein

pt pint 

1/2 Liter

md medium 

mittel

qt quart 

1 Liter

lg large

gross

ga gallon 

4 Liter

cn can 

Dose

oz ounce 

~ 30 g

pk package 

Packung

lb pound 

~ 450 g

pn pinch 

Prise, Msp.

ml milliliter 

ccm

cb cubic cm 

ccm

dr drop 

Tropfen

ds dash

Schuss, Spur

cl centiliter 

10 ccm

ct carton 

Karton

dc deciliter 

100 ccm = 0,1 Liter

bn bunch

Bund 

l liter 

Liter

sl slice

Scheibe

mg milligram 

Milligramm

ea each 

pro Portion

cg centigram 

1/100 Gramm

t teaspoon

Teeloeffel 

dg decigram 

1/10 Gramm

ts teaspoon

Teeloeffel 

g gram 

Gramm

T tablespoon

Essloeffel 

tb tablespoon

Essloeffel 

kg kilogram 

Kilogramm

Zurück zum Seitenanfang


  

Weitere Hinweise zu den Seiten finden Sie in unserem Impressum
Hier finden Sie Hinweise zu unseren Datenschutzbestimmungen
Copyright © 2023 CODEV, Jochen Herz, www.kalorio.de