Eat Drink Feel Good Markup Language

February 16, 2005

Aaron Straup Cope

I was lucky enough to be raised by a family that places a high premium on food, cooking, and the "art of eating." My memories of childhood are of large parties in the kitchen preparing meals and even larger parties sitting around the dinner table enjoying them.

Over the years, we've accumulated an impressive collection of recipe cards. I am not one of those people who thinks that paper is either dead or even close to being doomed. I will choose a hand-written recipe on an index card over the latest fancy electronic device almost every time. It is easier of use and, over time, each card develops its own character and history.

That said, there are real and tangible benefits in converting recipes to an electronic format. Multiple outputs, ease of sharing, and the ability to search and aggregate a collection of recipes are all "good things" that would be facilitated by a machine-readable recipe format.

When the Eatdrinkfeelgood Markup Language was conceived, a review of the existing work of describing recipes in XML yielded two observations. First, most applications simply lacked the features I was looking for. Second, the rest seemed only to exist as an effort to "monetize the recipe space." So, I sat down and wrote my own.

The Eatdrinkfeelgood Markup Language

The Eatdrinkfeelgood Markup Language is an XML application for describing recipes, meal courses, and entire menus. It was created with three principles in mind: maximum reusability, higher-order functions, and the "view source" rule.

Maximum Reusability

The design criteria for reusability can be summarized as: multiple output formats, content reuse, and the broadest possible set of tools for doing so.

For instance, if I am visiting friends in Italy and have need for a particular recipe, I'd like to be able to fetch it from a web server. If I have a mailing list for new recipes, I'd like to send them as plain text attachments. When I am in the kitchen, where no computers are allowed, I would like to generate PDF files which can be printed on index cards.

Reusability is not only multiple output formats but also a wide range of tools for creating them. In the first iteration of the language, I wrote a set of tools for manipulating recipes in Perl. Eventually, I decided it would be nice to have similar tools in Python and maybe even PHP. I probably got as far as the first Python class definition before I decided that down the path of writing and maintaining so many different language bindings lay only madness.

XSLT was chosen as the primary method for developing output filters. It has a robust feature set, there are a variety of stand-alone processors that work across operating systems, and many already have bindings for the most popular programming languages. XSLT suffers in its own special ways, but it comes the closest of any solution to meeting the goal of maximum reusability.

Finally, the ability to reuse one part of a recipe in another is crucial. If I have six recipes for pies and they all use the same crust recipe, I am not well-served by having to write it down every time and likewise when referencing entire recipes for creating a menu. This goal is met by using XInclude, a short, simple standard for including one part of a document in another using nonlinear search criteria. It encourages reuse and facilitates the maintenance of large recipe collections.

Higher-Order Functions

The challenge of designing any language is finding the right measure of markup to accurately describe a topic in order to do something useful with that information. The atomizing of a recipe's component parts has always been with a specific goal in mind rather than being an exercise in and of itself.

A good example of a higher-order function is automatic unit conversion based on locale. Even now, after all my years cooking, I'm still not sure what a cube of yeast is measured in teaspoons. Being able to dynamically convert a recipe from one system of measurements to another would be incredibly useful. Likewise, so is generating a digest of ingredient names, separate from other related properties, in order to quickly review whether everything needed to prepare a meal is available.

How, or whether, any of these features are implemented is ultimately application-dependent, but it is important that the language lend itself to the possibilities.

The "View Source" Rule

...what I consider to be the central lesson of the World Wide Web [is] the "View Source" lesson. The way the Web grew was, somebody pointed their browser at a URI, were impressed by what they saw, wondered "How'd they do that?", hit View Source, and figured it out by trial and error.

--Tim Bray

Writing a document should be possible with nothing more than a text editor and a little bit of patience, a straightforward, albeit boring affair. Hiding the details of the markup behind a user-friendly graphical interface would be a welcome improvement for many but it should not be a requirement. Similarly, a document should afford the reader the ability to easily understand its structure and content as well as the option of using it as a template for creating their own recipes. [1]

The ease with which an Eatdrinkfeelgood document may be written is an important factor, but it is tempered by the inherent verbosity of any XML-based description.

Benefits of a Native RDF Format

Eatdrinkfeelgood was not initially developed with RDF in mind which, in hindsight, was a mistake. A recipe is essentially a long list of metadata about a dish, so why not use a framework designed specifically to describe metadata as a model? Basing the Eatdrinkfeelgood Markup Language on RDF would enable the data and the metadata to exist in the same document. Combining the two saves an author from having to create a second file which, it can be reasonably assumed, might not happen if it required an extra step on their part. In turn, the internet would be seeded with ever more machine-friendly content that, the history of the web shows us, people will find new and interesting ways of using.

Formal Grammar

RDF's data model is refreshingly simple: one or more statements comprised of a subject, a predicate, and a value. Subjects and predicates are identified using URIs. Values are sometimes referred to as "objects" to better reflect the fact that they can be either an arbitrary string value or a pointer to another statement, as represented by a URI.

RDF is not the first attempt at a formalized grammar for metadata, nor is it likely to be the last. Relative to an isolated, domain-specific application, it may not even be the best solution. RDF, by constrast, was created to help manage disparate collections of metadata across a large information-space whose boundaries are unknown or in flux. It is, and was, developed using an open, consensus-driven process under the aegis of the World Wide Web Consortium (W3C).

The W3C has a proven track record of nuturing and promoting a number of successful standards including XML and the family of HTML formats, CSS and XSLT. W3C specifications are also free of patent and licensing restrictions.

The benefit of a formalized grammar, for the purposes of the Eatdrinkfeelgood Markup Language, is as a common point of reference for content producers, aggregators, and other software agents that addresses the "how" of describing things, leaving people to concentrate on the "what."

Extensibility and Flexibility

RDF was designed as an infrastructure for blending input from multiple, unrelated sources and creating a single, coherent representation. This makes it easier to negotiate properties that fall outside the scope of the language itself but that are otherwise related nutritional data about individual ingredients, contact information for a recipe's author, legal notices, and glossary definitions.

This kind of extensibility is not unique to RDF, but its inclusion as part of a formal specification has an important impact when considering it over another approach. If a particularly useful feature is mandated then, in this case, parsers must support it in order to be compliant, and the criteria for broad tool support is better satisfied.

Ontologies and Unambiguous Reference

Naming and classifying things is a bit like designing a markup language: it pays to know where to stop. Whether or not RDF will enable machines to "infer" meaning is the source of heated debate. My own feeling is that it won't succeed in the ways that many of the Semantic Web's supporters hope but that a judicious implementation of RDF identifiers and ontologies still offers significant rewards.

First, the harvesting and indexing of metadata, across an arena the size of the internet, will yield a wealth of unexpected associations. The promise of the Semantic Web is not only a "more structured, more efficient search engine" but also the happy, sometimes tangential surprise that leads to new avenues of exploration.

Secondly, if tagging the component parts of a recipe's measurements allows for automatic unit conversion, then assigning unique identifiers to individual properties gives computers a fighting chance to establish the relationship between one resource and another. For example, if individual ingredients were defined as URIs, it would be possible to create rule-sets to catalog recipes across multiple languages.

Any amount of automated learning is liable to suffer in the absence of human hand-holding and verification; a machine may be able to recognize that I am drawing by watching my actions, but is it able to discern that I am drawing upside down? This is likely to be reality of computer-based reasoning for the foreseeable future, but in many cases it may not matter and still prove to be a better solution that what we have today.

Design Challenges

Despite its many merits, marrying RDF with existing internet technologies, particularly XML, remains difficult. Harnessing all the benefits of RDF requires an entirely new suite of applications, many of which have yet to be created. Those that have are often unpolished and difficult to use without formal technical skills.

Parsers--Using Java is Not an Answer

RDF parsers still suffer from a deficit of language implementations. There are parsers for almost every language, but their quality and the thoroughness with which they tackle the specification vary wildly. The most robust tools today are written in Java. This limits the range of possible applications, specifically web-based applications, available for Eatdrinkfeelgood documents. Every commercial web-hosting service offers Perl-based CGI-scripting. Most offer a suite of PHP tools. Many offer Python support. Some offer Java-based solutions. By contrast, all four have support for XSLT processing.

The web-hosting test is not an absolute measure but it is an important one. Whole sections of the internet "cloth" have been built as grass-roots efforts by people with no formal training in computer science. Their projects are cobbled together with only an idea, spare time, tools that are easy to install and learn, healthy doses of sample code, informal tutorials, and how-tos.

Complex languages like Java will always have a role and are sometimes the only solution, but they raise the barrier of entry too high for most. In order for RDF to flourish, there needs to be a wider range and more forgiving set of tools that can be used by the tinkerers and enthusiasts who make up the grass-roots internet and whose endeavours have made it a richer place.


Processing an RDF graph, which may have been described using one of several but all equally valid representations, with XML-based technologies is often problematic. More often than not, the burden of juggling multiple possible outputs using XPath, XSLT, or XInclude is either impractical or simply impossible.

Effectively manipulating RDF/XML using XSLT can be a frustrating experience. Frequently, users are forced into a position where the only way to achieve a desired result is to engage in bad, or inefficient, coding practices. For example, locating a single node among many, by its unique identifier, requires inspecting all of them because there is no way of knowing, in advance, any of its relationships. This is an expensive operation for small documents and one that does not scale well across larger collections. Tools for more easily processing RDF/XML using XSLT do exist and more will become available in the future. Unfortunately, the current crop are typically wrappers around existing Java-based parsers and end by incurring the same unrealistic "costs" of operation described above.

Where XSLT doesn't play well with RDF, XInclude goes one step further and breaks completely. XInclude in an RDF context requires crippling the former's feature set in order to fit the latter's data model. Defining an XInclude fallback element is impossible given the constraints of the RDF/XML syntax. The XInclude spec mandates a fatal error when a parser encounters a resource error (for instance, the document does not exist or can not be accessed because a user is working offline) and no fallback element is defined. This kind of behavior is unnecessary and ill-suited for a recipe application. In theory, a similar framework for merging disparate documents could be achieved using rdfs:seeAlso. In reality, the ambiguities that surround how and when an RDF parser fetches resources make for an unsatisfactory solution.


"[A] URL is a type of URI that identifies a resource via a representation of its primary access mechanism (e.g., its network "location") rather than by some other attributes it may have. Thus as we noted, "http:" is a URI scheme. An http URI is a URL." -- URI Planning Interest Group, W3C/IETF

URIs are the primary identifiers for statements in RDF. These include the subset of URIs known as URLs (Universal Resource Locators) which are best known as the way to address and retrieve items on the World Wide Web. Of all decisions made designing the RDF specification, perhaps the most curious was that URLs need not be resolvable. For the purposes of an RDF parser, a URL that identifies and groups a set of statements need only be unique. There is no expectation that the URL necessarily "exists" as a resource on the web.

The net result of this decision is that in order to use RDF's powerful facilities for merging multiple documents, you must have all of them available to pass to the parser as input. RDF parsers do not know to recognize a statement's object as a reference to an external resource which should be downloaded and included in the result-tree. This is not an insurmountable problem, technically, but the absence of a formal specification for identifying and treating resources that should be retrieved versus those that should not means it is a solution that, in all likelihood, would be implemented differently across languages or not at all.

Another subset of URIs are Uniform Resource Names (URN) which are defined as "persistent labels" that use a set of namespaces registered with, and managed by, the Internet Assigned Numbers Authority (IANA). The IANA defines several reserved namespaces including x-urn which may be used by any application for its own purposes and is analagous to the RFC 822 (email) X-Header.

Informal URNs are a useful mechanism for handling private data. If I have a RDF resource that describes a recipe author, including their full name, I may want to refer to that resource rather than entering the same information a second time. If the document also contains sensitive information, I may not want to store it on the internet — that is, identify the resource as a URL — where it may be accessible to anyone. A URN allows a user to refer to a resource using an explicitly non-resolvable resource. It also highlights another shortcoming working with URIs in RDF.

XML, and SGML before it, developed the concept of catalogs to address a different, but similar, problem. Catalogs allow parsers to resolve missing identifiers declared in a document's DTD or to simply override existing ones. A catalog is simply a lookup table read by the parser that tells it to replace one URI with another : "a flexible, transparent mapping of resources." [2] A similar system for RDF [3] would help to manage and reference a large collection of interrelated but not necessarily homologous descriptions. Like the issue of how URLs are resolved, this is a technical problem that could be fixed, easily enough, in isolation but risks being incompatible across applications without standardization.

Finally, using URIs as referents is attractive in theory but in practice places an unrealistic burden on the user. It forces an unnatural form of naming things that is subject to constraints foreign to the day-to-day lives of most people: the formal grammar of URIs, awkward namespace URIs and prefixes, inflexibility towards spelling mistakes, and the other subtleties of language. In short, writing URIs by hand is too much trouble for most people and hoping that third-party developers will include logic for tracking human labels and all their ambiguities to URIs is an unrealistic expectation.


Making the Eatdrinkfeelgood Markup Language "natively" RDF-friendly is unlikely. The potential benefits of an RDF-compatible language do not outweigh the additional overhead and headaches required to maintain existing features. Modifying the specification so that it more easily maps to RDF is possible and should be the focus of most of the work moving towards a 2.0 release.

Specific attention will be given to methodologies for automating the creation of RDF output and generating reliable URIs for ingredients, measures, and other "named" items:

  • XSLT 2.0 has the ability to construct multiple result trees as well as multiple result documents. This should make it possible to generate a secondary RDF document simultaneously when a source recipe is transformed. Requiring a creator to upload both their primary output, say an HTML file, and its associate RDF data is not ideal since it demands more work of the user than they may be willing to endure.

    One alternative would be to create a centralized web service to harvest recipe metadata. Rather than rendering the RDF "result tree" as a static file, it could be serialized and sent to a REST web service, using XSLT's document() function [4], for automatic indexing.

    The XSLT 2.0 specification is still being finalized and application support is limited, at this time.

  • Adding optional attributes to allow users to specify a unique RDF property for an element independent of whatever string value was chosen to describe a subject. In the absence of a user-defined property, XSLT stylesheets could attempt to use the WordNet RDF database [5], or some other natural language processing equivalent, to determine a unique identifier. The Web Proper Names proposal [6] is another interesting approach since URIs for ingredients could be computed using existing properties and without requiring additional input from a recipe author.

RDF is a valuable addition to the internet landscape. Its success, however, will not be a function of its philosophical rigor alone. How well it can be integrated with the internet that came before it, including many of the problems it tries to address, in a neighbourly fashion will ultimately determine whether RDF achieves widespread adoption.


[1] A plain-text format, closer in nature to a traditional recipe, that could be converted into an XML-based Eatdrinkfeelgood document would no doubt help. My hope is that this will be possible when the specification, and tools, for XSLT 2.0 reach maturity.

[2] Caching in with Resolvers, Norman Walsh

[3] For example, x-urn:aaronstraupcope:knows:who# might be resolved as file:///home/asc/knows/who

[4] Bob DuCharme's XSLT Web Service Clients is a more complete treatment of this subject.

[5] wn-find-class is a XSLT stylesheet that tries to match phrases with a WordNet RDF Class.

[6] Web Proper Names: Naming Referents on the Web, Harry Halpin and Henry S. Thompson