Copyright © 2008–09 Toby Inkster, some rights reserved.
GRDDL provides a powerful and robust mechanism for extracting RDF
triples from XHTML, and more generally any XML-based markup. By
introducing an initial “tidying” stage beforehand, GRDDL can also be
applied to HTML. GRDDL enables documents authored using the XHTML class
attribute and other semantic XHTML techniques to be
transformed to a more formal knowledge representation.
The GRDDL recommendation allows for transformations to be written in any programming language, but only documents the use of XSLT transformations in detail. XSLT is a full Turing-complete programming language, far more powerful and complex than necessary for most GRDDL use cases.
This document describes a simple new document description language “RDF-EASE”, with a familiar syntax that borrows heavily from Cascading Style Sheets (CSS). The document also describes how RDF-EASE can be used as a transformation language for the purpose of GRDDL.
This document is published by buzzword.org.uk, a web site that hosts various specifications, articles and tools of use to web publishers. This is not a W3C recommendation. It is not even a buzzword.org.uk recommendation yet.
The author welcomes feedback on this draft by e-mail to mail@tobyinkster.co.uk.
This document is available under a licence which allows the creation of derivative works under certain conditions. For the purpose of licensing, implementations of RDF-EASE shall not be considered derivative works.
This section is informative.
Ten second sales pitch: CSS is an external file that specifies how your document should look; RDF-EASE is an external file that specifies what your document means.
This document introduces a document description language called “RDF-EASE”, which may be used to transform an XHTML document to RDF triples.
It is intended to act as an alternative to XSLT in the context of GRDDL. XSLT’s functional programming style can make it tricky for a programmer more accustomed to procedural programming to pick up; and even programmers who are comfortable with functional programming may have difficulty with its unusual syntax.
RDF-EASE is a non-Turing-complete language, with a familiar CSS-like syntax, easy for non-programmers to pick up quickly. Like CSS, it allows authors to use a flexible system of selectors to select groups of elements and apply various rules to them. RDF-EASE also borrows from RDFa in defining what these rules mean and how they work together.
This document defines the syntax of RDF-EASE, how it can be used in conjunction with GRDDL, how it may be parsed, and suggested best practices for mixing RDF-EASE and RDFa.
This section is normative.
The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC2119].
The syntax of RDF-EASE is a subset of the syntax described in §4.1 Syntax of [CSS21]. Any valid CSS 2.1 selector is also a valid RDF-EASE selector.
All properties in RDF-EASE begin with the string -rdf-
,
as per §4.1.2.1 Vendor-specific extensions in [CSS21]. This allows RDF-EASE and CSS to be safely mixed in one
file, as CSS parsers should recognise RDF-EASE properties as unknown CSS
extensions.
There are no at-rules, except as defined below.
RDF-EASE parsers MUST NOT follow @import
links.
There are no media (e.g. CSS “screen”, “print”).
RDF-EASE parsers MUST ignore the media
attribute on GRDDL rel="transformation"
links.
In RDF-EASE, CURIE prefixes are not scoped, but apply to an entire
file. They are defined using a syntax similar to CSS Namespaces
[CSSNS] except that they are introduced with
an at-rule of @prefix
instead of @namespace
, and
there is no default prefix allowed. Examples follow.
@prefix foaf "http://xmlns.com/foaf/0.1/"; @prefix xsd 'http://www.w3.org/2001/XMLSchema#'; @prefix dc 'http://purl.org/dc/terms/';
Figure 2a: Defining CURIE prefixes in RDF-EASE.
Note that although CURIE prefixes do not need to be valid IRIs, CURIEs do.
For convenience, certain prefixes are predefined, though authors may override them by explicitly declaring the prefix to point to a different URI. The predefined prefixes are:
@@ISSUE: Which others? Is this a slippery slope?
In CSS, properties can only take one value, so the cascade is very important. When two CSS rules both match an element, the most “specific” rule is used [CSS21]. In the following example, the element has a width of 10em.
p { width: 20em; } p.narrow { width: 10em; } ... <p class="narrow">A narrow paragraph.</p>
Figure 2b: The CSS Cascade.
With RDF-EASE the cascade works slightly differently, in that most RDFa attributes can take a list of multiple values. An element takes a collection of values from all the CSS rules with selectors matching it.
p { -rdf-property: "foaf:name"; } p.name { -rdf-property: "vcard:fn"; } ... <p class="name" property="dc:title">Joe Bloggs</p>
Figure 2c: In this example, the paragraph takes all three properties.
For instances where this cascading is not required, and you wish for
the more specific rule to completely replace the less specific rule, a
reset
keyword is available. Adding the reset
keyword to a value tells the processor to ignore the input of less
specific rules. RDFa attributes hard-coded in the XHTML cannot be reset,
as they are more specific than any RDF-EASE rules.
p { -rdf-property: "foaf:name"; } p.name { -rdf-property: reset "vcard:fn"; } ... <p class="name" property="dc:title">Joe Bloggs</p>
Figure 2d: The paragraph has properties
vcard:fn
and dc:title
, but not
foaf:name
.
RDF-EASE is a subset of CSS, and may be
intermixed with CSS. When a mixed RDF-EASE+CSS file is served, a media
type of text/css
must be used, in
accordance with [CSS-MIME]. When a pure
RDF-EASE file is served text/x-rdf+css
should be used instead.
In HTTP, and other protocols which serve files with a media type, RDF-EASE implementations must ignore any RDF-EASE files not served with one of these two media types.
This section is normative.
-rdf-about
-rdf-about
Value: | ‘document’ | ‘reset’ | ‘normal’ | nearest-ancestor(SELECTOR) |
---|---|
Initial: | ‘normal’ |
Applies to: | any element |
Inherited: | no |
Setting the RDF-EASE -rdf-about
property is equivalent to
setting the XHTML about
attribute, with a meaning as specified in
§2.1. The RDFa
Attributes of [RDFA]. RDF-EASE does not offer
the ability to specify arbitrary URIs in this attribute, but instead
must take one of four values:
about
attribute to
the empty string. Any properties found within the element will refer
to the document as a whole.-rdf-about
properties on less specific RDF-EASE
selectors that match this element should be ignored.about
attribute to this named blank node.The “nearest ancestor” feature provides a scoping feature useful for transforming microformats with RDF-EASE. It allows for the following hCards to be parsed as meaning the same thing:
.vcard { -rdf-typeof: "foaf:Person"; } .vcard .fn { -rdf-property: "foaf:name"; -rdf-datatype: "xsd:string"; } .vcard .url { -rdf-rel: "foaf:page"; } /* This scopes everything within the hCard as applying to the * hCard as a whole. */ .vcard, .vcard * { -rdf-about: nearest-ancestor(".vcard"); } <div class="vcard"> <a class="fn url" href="http://example.com">Joe Bloggs</a> </div> <div class="vcard"> <span class="fn"><a class="url" href="http://example.com">Joe Bloggs</a></span> </div> <div class="vcard"> <a class="url" href="http://example.com"><span class="fn">Joe Bloggs</span></a> </div>
Figure 3a: The importance of the “nearest ancestor” construct.
Without nearest ancestor scoping, in the third hCard, it would be
impossible for the foaf:name
property to be applied to the
person — instead the foaf:name
would be taken as applying
to the URL.
-rdf-content
-rdf-content
Value: | attr(ATTR) | ‘normal’ |
---|---|
Initial: | ‘normal’ |
Applies to: | any element |
Inherited: | no |
Setting the RDF-EASE -rdf-content
property is equivalent
to setting the XHTML content
attribute, with a meaning as specified
in §2.1. The
RDFa Attributes of [RDFA]. Rather than setting
the XHTML content
attribute to a specific string, it is used to
specify another attribute from whence to read the content value.
abbr { -rdf-content: attr(title); }
Figure 3b: Example usage of -rdf-content
.
The value ‘normal’ is a no-op, equivalent to not having set the property at all.
-rdf-property
,
-rdf-rel
,
-rdf-rev
and
-rdf-typeof
-rdf-property
, -rdf-rel
,
-rdf-rev
, -rdf-typeof
Value: | [‘reset’] URI List | ‘normal’ |
---|---|
Initial: | ‘normal’ |
Applies to: | any element |
Inherited: | no |
These four RDF-EASE properties are equivalent to setting the
similarly named XHTML attributes, with a meaning as specified in §2.1. The RDFa
Attributes of [RDFA]. The typical value these
properties will be set to is a list of tokens, each representing a URI,
separated by whitespace. Optionally, the first item in the list may be
the token reset
instead of a token representing a URI. The
value ‘normal’ is a no-op, equivalent to not having set the property at
all.
Each token in a URI List should conform to one of the following syntaxes:
"dc:title"
'foaf:name'
url(
and suffixed by )
.url(http://purl.org/dc/terms/)
url("http://xmlns.com/foaf/0.1/name")
url('http://zoölogy.example.net/ns#Horse')
An example use of these properties:
div.event { -rdf-typeof: "ex:Event"; } div.event span.starting { -rdf-property: reset "ex:start" "ical:dtstart"; } div.event span.place { -rdf-rel: reset "ex:location"; -rdf-rev: reset "ex:event-here"; }
Figure 3c: Example usage of various RDF-EASE properties.
-rdf-datatype
-rdf-datatype
Value: | ‘normal’ | ‘reset’ | ‘string’ | URL |
---|---|
Initial: | ‘normal’ |
Applies to: | any element |
Inherited: | no |
This RDF-EASE property is equivalent to setting the
datatype
XHTML attributes, with a meaning as specified in §2.1. The RDFa
Attributes of [RDFA]. The default value of
‘normal’ is a no-op, equivalent to not having set the property at all.
Setting -rdf-datatype
to ‘reset’ is equivalent to removing
the datatype
attribute entirely. Setting it to ‘string’ is
equivalent to setting the datatype
attribute to the empty
string. The value of this property may be a URL, using the CURIE or IRI
syntax defined in §3.3.
div.vcard .fn { -rdf-datatype: string; }
Figure 3d: Example usage the
-rdf-datatype
property.
This section is informative.
Authors should refer to [GRDDL] for normative guidance on how to link to GRDDL transformations in any language.
rel="transformation"
The easiest way of linking from an XHTML document to an associated
RDF-EASE file is to use an XHTML <link />
element in the
document head:
<link rel="transformation" href="my-semantics.ease" type="text/x-rdf+css" />
Figure 4a: Standard method of linking to RDF-EASE transformations.
Because RDF-EASE uses a CSS-compatible syntax, it is possible to
intermingle RDF-EASE and CSS in the same file, in which case, you may
wish to link to the RDF-EASE file using
rel="transformation stylesheet"
and
type="text/css"
to ensure that your file is also used
by CSS-capable agents.
Media Type | Link Type | ||
---|---|---|---|
rel="transformation" |
rel="stylesheet transformation" |
rel="stylesheet" |
|
text/css |
Yes | Yes, if file also contains CSS | RDF-EASE is ignored |
text/x-rdf+css |
Yes | No | No |
If you wish to define a formalised set of semantic class names using RDF-EASE and use it on multiple HTML and XHTML pages, then you may wish to create a metadata profile. To do this:
Create an XHTML document at a permanent URI.
In that document (the “profile document”), include a brief statement about the purpose of the profile. For example, “this profile defines a set of class names for marking up automobiles”.
For the benefit of people viewing the profile document and wanting to learn about the profile, use XHTML Metadata Profile [XMDP] markup to define each attribute and attribute value used. For example, define the human-readable meaning of all class names this way.
Create an RDF-EASE transformation to convert these classes to RDF.
Link from the profile document to the RDF-EASE transformation using the following markup:
<a rel="profileTransformation" href="my-semantics.ease" type="text/x-rdf+css">An RDF-EASE transformation</a>.
Figure 4b: Method of linking to RDF-EASE transformations from XHTML metadata profiles.
This section is normative.
The following procedure documents an algorithm for parsing an XHTML document with a linked RDF-EASE transformation. In accordance with [GRDDL], when multiple transformations are supplied, each must be applied to the document separately, yielding separate RDF graphs, which may then be merged or “smushed” if desired.
The algorithm modifies the document by adding attributes to various elements, so should be applied to an in-memory copy of the document rather than to the original. The algorithm assumes that the document is held in a DOM-compatible representation, and that the DOM implementation allows for arbitrary attributes to be created for each element, irrespective of whether they are strictly allowed by the document type definition. RDF-EASE implementations may choose to use other algorithms, provided that the triples they produce match the triples produced by the reference algorithm here.
A dictionary structure should be created, called CURIEPrefixes. This will store mappings between CURIE prefixes and URIs. It is pre-filled with the prefixes defined in §2.2.
Randomly generate a string to use as a CURIE prefix. It must be
a string which is not used as a CURIE prefix anywhere in the
document being processed, nor in the RDF-EASE file. The string
kwijibo
is often a good candidate. We shall refer to
this prefix as the kwijibo.
Add an XML namespace declaration to the document’s root element, defining the namespace kwijibo to be the empty string. e.g.
<html xmlns:kwijibo="">
@@ISSUE: according to [XMLNS] this is a completely illegal namespace. The whole idea of kwijibo is really just an ersatz for placing full URIs into RDFa attributes, where they are not allowed. In my implementation, I simply allow them, which works, but requires the parser to break from strict RDFa conformance. There must be a good way around this. Perhaps something like:
<html xmlns:kwijibohttp="http" xmlns:kwijibourn="urn">
Added after step #6, and after the list of IRI schemes is fully known? Step #2 would still be needed to generate that unique string.
The RDF-EASE file should be parsed, as described in §4. Syntax and basic data types of [CSS21].
All at-rules should be ignored, except @prefix
. For
each prefix defined using an @prefix
rule, an entry
is added to CURIEPrefixes for that prefix. Any existing
entries in CURIEPrefixes for that prefix are overwritten.
The parsing should yield a collection of CSS rule sets, each of
which consists of one or more CSS selectors (such as
div.vcard span.fn
) and zero or more CSS rules. Each
CSS rule consists of a property and value pair.
Any CSS rule sets in the previous collection which contain multiple selectors (separated by comma in the RDF-EASE file), should be split into multiple rule sets, each with the same CSS rules, but each having only a single selector.
The collection of rule sets should be sorted into an ordered list. They must be sorted by specificity of selector, as defined by §6.4.3 Calculating a selector’s specificity of [CSS21], in incresing specificity. When two selectors are of equal specificity, they should be added to the ordered list in the order that they occurred in the RDF-EASE file. Call this list RuleList.
The function in §5.1 of this document should be called on the document's root element.
The document is processed to produce triples, as described in §5. Processing Model of [RDFA].
Given an element E, it must be processed as follows.
For each rule set rs in RuleList:
If the selector of rule set rs does not match element E, move on to the next rule set in RuleList.
Each property value pair (p, v) within rs should be handled as follows:
If p is -rdf-about
and
v is reset
, then the attribute
x-rdf-about
of element E should
be removed if present.
If p is -rdf-about
and
v is document
, then the attribute
x-rdf-about
of element E should
be set to the empty string.
If p is -rdf-about
and
v is nearest-ancestor(S)
,
then the following procedure should be followed:
Obtain a list of all nodes within the document matching the selector S.
Within that list, find any nodes such that they are ancestor nodes of E (including E as an ancestor of itself).
Of those ancestor nodes, find the node which is nested most deeply within the DOM tree. Call this anc.
If anc has an
about
attribute set...
@@TODO: decide what happens here.
Run anc through a hash function to generate a hexadecimal (or other safe) string. This must be a predictable hash function, such that the same node passed through it will always render the same result. Call this hash H.
Set the x-rdf-about
attribute
of E to [_:H]
.
If p is -rdf-content
and
v is reset
, then the attribute
x-rdf-content
of element E should
be removed if present.
If p is -rdf-content
and
v specifies an attribute
attr(a)
, then the attribute
x-rdf-content
of element E
should be set to the value of attribute a of
element E.
If p is one of
-rdf-property
, -rdf-rel
,
-rdf-rev
or -rdf-typeof
(where
the part after the -rdf-
will be referred
to as px) then split v into
whitespace delimited tokens, and for each token
tok:
If tok is reset
, then
remove attribute x-rdf-px
from element E.
If tok is a URI, wrapped in
url(...)
and optionally quoted, then
append to the x-rdf-px
attribute of element E: a single space
character, the kwijibo string, a colon,
and then this URI.
If tok is a string containing a colon, and optionally quoted, then:
Split token tok on the first colon character yielding two strings, pfx and sfx.
If pfx is defined in CURIEPrefixes then let upfx be the URI that the prefix represents.
If upfx is defined, then
append to the x-rdf-px
attribute of element E: a single
space character, the kwijibo string,
a colon, upfx and
sfx.
If p is -rdf-datatype
and v is reset
then remove any
x-rdf-datatype
attribute on element
E.
If p is -rdf-datatype
and v is string
then set the
x-rdf-datatype
attribute on element
E to the empty string.
If p is -rdf-datatype
and v is a URI, wrapped in
url(...)
and optionally quoted, then
set the x-rdf-datatype
attribute of element
E to: the kwijibo string, a colon,
and then this URI.
If p is -rdf-datatype
and v is a string containing a colon,
then:
Split v on the first colon character yielding two strings, pfx and sfx.
If pfx is defined in CURIEPrefixes then let upfx be the URI that the prefix represents.
If upfx is defined, then
set the x-rdf-datatype
attribute of element E to: the
kwijibo string, a colon, upfx
and sfx.
Otherwise, the property–value pair is ignored. A warning message may be emitted if the RDF-EASE file was served with media type text/x-rdf+css.
For each a from { about , content , datatype }:
If E has no attribute x-rdf-a
then skip to the next value of a.
If E has no attribute a then create
an attribute a and set it to a copy of the
string in attribute x-rdf-a
.
The x-rdf-a
attribute is removed,
as it was only ever supposed to be temporary.
For each a from { property , rel , rev , typeof }:
If E has no attribute x-rdf-a
then skip to the next value of a.
If E does not have an attribute a, then a new attribute a is created as an empty string.
Append the value of x-rdf-a
to
the attribute a.
The x-rdf-a
attribute is removed,
as it was only ever supposed to be temporary.
A recurse variable is created. If the E has
a property
attribute, but no datatype
attribute, then recurse is set to false. Otherwise
recurse is set to true.
@@ISSUE: Really, we should set recurse to false
when property
and datatype
are both
set, but datatype
is rdf:XMLLiteral. However, this
doesn't seem especially feasible without comingling the RDF-EASE
and RDFa stages of processing because the RDF-EASE algorithm doesn't
keep track of xmlns
attributes.
If recurse is true, then this function is called on all child elements of E.
This sub-section is informative.
Here is the RDF-EASE being used in the example:
@prefix foaf "http://xmlns.com/foaf/0.1/"; @prefix dc "http://purl.org/dc/terms/"; @prefix ex "http://example.org/ns#"; title { -rdf-about: document; -rdf-property: "dc:title"; } li { -rdf-typeof: "ex:ListItem"; -rdf-property: "ex:contents"; } ul.people li { -rdf-typeof: "foaf:Person"; -rdf-property: reset "foaf:name"; } ul.people li[title] { -rdf-content: attr(title); }
It is being applied to the following XHTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"> <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/"> <head> <title>Example RDF-EASE</title> </head> <body> <h1 property="dc:invalid">Example RDF-EASE</h1> <h2>A List of People</h2> <ul class="people"> <li>Alice Jones</li> <li title="Robert Smith">Bob Smith</li> <li property="foaf:nickname">Carol Black</li> </ul> </body> </html>
After step #6, the document has been transformed to:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"> <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:kwijibo=""> <head> <title property=" kwijibo:http://purl.org/dc/terms/title" about="">Example RDF-EASE</title> </head> <body> <h1 property="dc:invalid">Example RDF-EASE</h1> <h2>A List of People</h2> <ul class="people"> <li typeof=" kwijibo:http://xmlns.com/foaf/0.1/Person kwijibo:http://example.org/ns#ListItem" property=" kwijibo:http://xmlns.com/foaf/0.1/name" >Alice Jones</li> <li title="Robert Smith" content="Robert Smith" typeof=" kwijibo:http://xmlns.com/foaf/0.1/Person kwijibo:http://example.org/ns#ListItem" property=" kwijibo:http://xmlns.com/foaf/0.1/name" >Bob Smith</li> <li property="foaf:nickname kwijibo:http://xmlns.com/foaf/0.1/name" typeof=" kwijibo:http://xmlns.com/foaf/0.1/Person kwijibo:http://example.org/ns#ListItem" >Carol Black</li> </ul> </body> </html>
In step #7, this produces the following triples, expressed using [TURTLE].
@prefix dc : <http://purl.org/dc/terms/> . @prefix ex : <http://example.org/ns#> . @prefix foaf : <http://xmlns.com/foaf/0.1/> . <> dc:title "Example RDF-EASE"@en . _:bnode1 a foaf:Person , ex:ListItem ; foaf:name "Alice Jones"@en . _:bnode2 a foaf:Person , ex:ListItem ; foaf:name "Robert Smith"@en . _:bnode3 a foaf:Person , ex:ListItem ; foaf:name "Carol Black"@en ; foaf:nickname "Carol Black"@en .
Note:
rdf:type
of both
foaf:Person
and ex:ListItem
. This is because
they were matched by two different rules, each of which assigned
an rdf:type
.ex:contents
property set. This is because the reset
keyword on
the -rdf-property
rule of the ul.people li
block overrides the less specific li
selector.foaf:nickname
property is intact
despite the reset. This is because RDFa attributes can never
be overridden by RDF-EASE.dc:invalid
property didn’t work — CURIE prefix
definitions are not copied from the RDF-EASE file to the XHTML
file, so the XHTML cannot make use of prefixes defined in
RDF-EASE.This section is informative.
When writing pages, authors need to take care that visual styles specified as XHTML attributes and CSS properties not only work well together, but also work when the CSS is absent. In the following example, the text “Hello world!” is clearly visible as white text on a blue background when CSS is enabled, but invisible white text on a white background if CSS is disabled or unavailable.
<html> <head> <title>A Contrived Example</title> <style type="text/css"> p { background: blue; } </style> </head> <body bgcolor="white"> <p> <font color="white">Hello world!</font> </p> </body> </html>
Figure 6a: Unsafe usage of CSS.
Similarly, authors using RDF-EASE need to check that the RDF triples generated by a pure RDFa parser, which cannot handle RDF-EASE, still make sense. An example where the meaning is radically changed follows — an RDF-EASE parser would infer that Alice knows Bob, whereas a non RDF-EASE tool would parse this as meaning that Alice’s name is “Bob”!
.knows { -rdf-rel: "foaf:knows"; } ... <div about="#alice"> <p class="knows"> <span property="foaf:name">Bob</span> </p> </div>
Figure 6b: Unsafe usage of RDF-EASE.
RDF-EASE is capable of specifying any combination of the subject, predicate and object of an RDF triple. But only certain combinations are provably safe to combine.
Method of Specifying Resource | Behaviour of Parser | Safe? | |||
---|---|---|---|---|---|
Subject | Predicate | Object | RDFa Parser | RDF-EASE Parser | |
RDFa | RDFa | RDFa | parsed | parsed | Yes |
RDFa | RDFa | RDF-EASE | misinterpreted | parsed | No |
RDFa | RDF-EASE | RDFa | ignored | parsed | Yes |
RDFa | RDF-EASE | RDF-EASE | ignored | parsed | Yes |
RDF-EASE | RDFa | RDFa | misinterpreted | parsed | No |
RDF-EASE | RDFa | RDF-EASE | misinterpreted | parsed | No |
RDF-EASE | RDF-EASE | RDFa | ignored | parsed | Yes |
RDF-EASE | RDF-EASE | RDF-EASE | ignored | parsed | Yes |
For styling, there is a “rule of thumb” that says “whenever you set a
foreground colour, set a background colour.” The equivalent rule to
combine RDF-EASE with RDFa is “whenever you use an RDFa
property
, rel
or rev
attribute,
make sure the subject and object of the triple can be determined through
pure RDFa.”
This section is informative.
A sample transformation for the hAudio 0.9.1 Microformat is below. RDF-EASE is designed to make Microformat-like HTML very easy to transform to RDF.
@prefix audio "http://purl.org/media/audio#"; @prefix comm "http://purl.org/commerce#"; @prefix dc "http://purl.org/dc/terms/"; @prefix foaf "http://xmlns.com/foaf/0.1/"; @prefix media "http://purl.org/media#"; abbr[property][title] { -rdf-content: attr(title); } .haudio { -rdf-typeof: "audio:Recording"; -rdf-about: nearest-ancestor(".haudio"); } .haudio * { -rdf-about: nearest-ancestor(".haudio"); } .haudio .fn { -rdf-property: "dc:title" "rdfs:label"; -rdf-datatype: "xsd:string"; } .haudio .album { -rdf-property: "dc:isPartOf"; -rdf-datatype: "xsd:string"; } .haudio .category { -rdf-property: "dc:type"; -rdf-datatype: "xsd:string"; } .haudio .contributor { -rdf-property: "dc:contributor"; -rdf-datatype: "xsd:string"; } .haudio .description { -rdf-property: "dc:description"; -rdf-datatype: "xsd:string"; } .haudio .position { -rdf-property: "media:position"; -rdf-datatype: "xsd:integer"; } .haudio .photo { -rdf-rel: "media:depiction" "foaf:depiction"; } .haudio .price { -rdf-property: "comm:costs"; -rdf-datatype: "xsd:string"; } .haudio *[rel=~"enclosure"] { -rdf-rel: "media:download"; } .haudio *[rel=~"payment"] { -rdf-rel: "comm:payment"; } .haudio *[rel=~"sample"] { -rdf-rel: "media:sample"; } .haudio .url { -rdf-rel: "foaf:page"; } .haudio .item { -rdf-rel: "media:contains" "dc:hasPart"; -rdf-rev: "dc:isPartOf"; -rdf-about: nearest-ancestor(".haudio .item"); } .haudio .item * { -rdf-about: nearest-ancestor(".haudio .item"); }
Initial public version.
-rdf-datatype
more sensibly.The editor gratefully acknowledges feedback from the Semantic Web Interest Group, particularly: