microformats2-parsing-rdf
Draft Microformats2-to-RDF mapping
Tantek asked me to draft up a Microformats2-to-RDF mapping. It's pretty straightforward to do. This is rough and will need cleaning up.
RDF model
In the document below, the RDF model is represented using the Notation3 syntax.
All RDF examples presume at least these basic external prefixes:
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
In addition, we shall use the profile defined on microformats-2 as an RDF URI prefix:
@prefix uf: <http://microformats.org/profile/> .
What is the subject?
In RDF, all data is in the form of subject, predicate, object triples. These map roughly to English statements. Subjects can be either URI references or blank nodes.
Mapping these adequately is problematic.
If the element which has the root class name for a microformats2 object also has an about attribute, that SHOULD be used to set the subject for the microformat.
If the element does not have an about
attribute, or the HTML processor does not support parsing about
attributes, then the subject for the microformat should be an RDF blank node.
If a parser is also parsing RDFa, it should use the same blank nodes as the subjects for microformats2 objects as it does for statements expressed in RDFa. Given this HTML:
<div class="h-card p-name" typeof="foaf:Person" property="foaf:name">Tom Morris</div>
A microformats2 and RDFa-aware processor should produce Notation3 output with a singular blank node:
_:a a uf:h-card, foaf:Person;
foaf:name "Tom Morris";
uf:p-name "Tom Morris";
rdfs:label "Tom Morris" .
It should not separate out these two resources into separate blank nodes:
_:a a uf:h-card;
uf:p-name "Tom Morris";
rdfs:label "Tom Morris" .
_:b a foaf:Person;
foaf:name "Tom Morris" .
Representing root class names
Root class names map neatly to rdf:type
. In Notation3, this is represented with the shorthand a
.
<div class="h-card">Tom Morris</div>
_:bnode01 a uf:h-card .
This is compatible with the RDF specification, but differs from RDF best practice. As with Java and most programming languages, in RDF, it is customary to capitalize class names.
Representing properties
Once we have inferred the class name, we need simply declare the properties.
For each p-
prefixed property, an RDF statement should be produced with the subject being that of the microformats2 object, the property being the namespaced microformats property, and the object being either a plain literal or a language literal containing the string representation of the object (see language section below). This should be equal to the string value in the JSON output.
Multiple properties
If there are multiple instances of a property, this should result in multiple statements using the same property name.
This example hCard contains two category properties and two URL properties:
<div class="h-card">
<img class="u-photo" alt="photo of Mitchell"
src="https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg"/>
<a class="p-name u-url"
href="http://blog.lizardwrangler.com/"
>Mitchell Baker</a>
(<a class="u-url"
href="https://twitter.com/MitchellBaker"
>@MitchellBaker</a>)
<span class="p-org">Mozilla Foundation</span>
<p class="p-note">
Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities.
</p>
<span class="p-category">Strategy</span>
<span class="p-category">Leadership</span>
</div>
_:lizardwrangler a uf:h-card;
uf:u-photo <https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg>;
uf:p-name "Mitchell Baker";
rdfs:label "Mitchell Baker";
uf:u-url <http://blog.lizardwrangler.com>;
uf:u-url <https://twitter.com/MitchellBaker>;
uf:p-org "Mozilla Foundation";
uf:p-note "Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities.";
uf:p-category "Strategy";
uf:p-category "Leadership" .
(In Notation3, it is possible to use commas as a shorthand form to represent multiple statements. This has been avoided in order to better illustrate the point in question.)
To convert from RDF to JSON, one should take all statements that have the same subject and property and group them together into an array.
Language
RDF allows three types of literal: plain literals, language literals and typed literals.
Typed literals contain a datatype annotation, language literals contain a language annotation (the same ISO country codes as is used in HTML's lang
attribute and XML's xml:lang
attribute).
Processors should work out the language tag (if any) of the elements containing microformat properties (using the latest RDFa specification) and emit language-tagged literals for p- prefixed properties. If no language tag is set in the HTML, emit plain literals for all p- prefixed properties.
For instance:
<div class="h-card p-name" lang="ja">内閣総理大臣</div>
<div class="h-card p-name" lang="he">בִּנְיָמִין נְתַנְיָהוּ</div>
_:a a uf:h-card;
uf:p-name "内閣総理大臣"@ja .
_:b a uf:h-card;
uf:p-name "בִּנְיָמִין נְתַנְיָהוּ"@he .
rdfs:label
It is generally good practice for each resource to have an rdfs:label property. This maps to p-name.
Using Notation3 rules syntax:
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
@forall ?s ?o .
{ :s uf:p-name :o . } log:implies { :s rdfs:label :o . } .
It is arguable that one may wish to then omit the p-name property from RDF representations of Microformats2 objects. The minor cost of extra duplication is outweighed by ensuring faithful representation and the ability to bidirectionally convert from RDF representations and JSON representations of Microformats2 objects.
Representing nested microformats
This is easy. Each new object becomes a new RDF resource, and there is a relationship going from the parent object to the child object.
<div class="h-event">
<a class="p-name u-url" href="http://indiewebcamp.com/2012">
IndieWebCamp 2012
</a>
from <time class="dt-start">2012-06-30</time>
to <time class="dt-end">2012-07-01</time> at
<span class="p-location h-card">
<a class="p-name p-org u-url" href="http://geoloqi.com/">
Geoloqi
</a>,
<span class="p-street-address">920 SW 3rd Ave. Suite 400</span>,
<span class="p-locality">Portland</span>,
<abbr class="p-region" title="Oregon">OR</abbr>
</span>
</div>
In Notation3, this would emit:
_:hevent1 a uf:h-event;
rdfs:label "IndieWebCamp 2012";
uf:p-name "IndieWebCamp 2012";
uf:u-url <http://indiewebcamp.com/2012>;
uf:dt-start "2012-06-30"^^xsd:date;
uf:dt-end "2012-07-01"^^xsd:date;
uf:location [
a uf:h-card;
rdfs:label "Geoloqi";
uf:p-name "Geoloqi";
uf:p-org "Geoloqi";
uf:u-url <http://geoloqi.com/>;
uf:p-street-address "920 SW 3rd Ave. Suite 400";
uf:p-locality "Portland";
uf:p-region "Oregon" .
].
Mapping
- See also: microformats2-rdf-mapping
The RDF semantics of an hCard can be declared as an RDF document available from microformats.org. This can be used by RDF-minded parsers to draw inferences. In the case of hCard...
uf:h-card a owl:Class;
owl:sameAs <http://www.w3.org/2006/vcard/ns#VCard> .
Equivalent properties can also be declared:
uf:p-phone a owl:DatatypeProperty;
owl:sameAs <http://xmlns.com/foaf/0.1/phone>;
<http://schema.org/telephone> .
Advanced: parsing microformats in context
Representative hCard parsing
- See also: representative hCard algorithm, which operates on an already parsed data model, and thus works the same way.
If the parser is able to infer that a representative hCard is present on the page, one can represent this by using foaf:primaryTopic from the FOAF specification.
<> foaf:primaryTopic _:a .
_:a a uf:h-card;
uf:p-name "Tom Morris" .