Copyright © 2008 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 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 should 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-keywords.
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. They are defined in one
or more special blocks with a selector of a single underscore. Within
these blocks, any property is taken to be a new prefix being defined.
The value must be an IRI conforming to
[IRI], optionally quoted in double or single
quotes, and required to be prefixed with url(
and suffixed
with )
. An example follows.
_ { foaf: url("http://xmlns.com/foaf/0.1/"); xsd: url(http://www.w3.org/2001/XMLSchema#); dc: url('http://purl.org/dc/terms/') }
Figure 2a: Defining CURIE prefixes in RDF-EASE.
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:
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 values.
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-datatype
,
-rdf-property
,
-rdf-rel
,
-rdf-rev
and
-rdf-typeof
-rdf-datatype
, -rdf-property
, -rdf-rel
,
-rdf-rev
, -rdf-typeof
Value: | [‘reset’] URI List | ‘normal’ |
---|---|
Initial: | ‘normal’ |
Applies to: | any element |
Inherited: | no |
These last five 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"; -rdf-datatype: url('http://www.w3.org/2001/XMLSchema#dateTime') "ex:date-time"; } div.event span.place { -rdf-rel: reset "ex:location"; -rdf-rev: reset "ex:event-here"; }
Figure 3c: Example usage of various RDF-EASE properties.
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 |
@@TODO
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.
An empty dictionary structure should be created, called CURIEPrefixes. This will store mappings between CURIE prefixes and URIs.
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].
This 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.
Rule sets that have a selector of “_” should not be added to RuleList, but instead should be parsed, in the order in which they are specified in the file, as CURIE definition blocks. For each property–value pair, a new definition should be created in CURIEPrefixes, such that the RDF-EASE property is the dictionary key and the RDF-EASE value is the dictionary value.
For each item in RuleList the following procedure should be followed:
A list of elements within the document which match the rule’s selector should be generated. For each element E on this list, the following procedure should be followed:
Each property value pair (p, v) within the rule set 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-datatype
,
-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.
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 element in the document, if an
x-rdf-about
attribute is present:
If the about
attribute is not present, then
the about
attribute is set to be the same as the
x-rdf-about
attribute.
The x-rdf-about
attribute is removed, as
it was only ever supposed to be temporary.
For each element in the document, if an
x-rdf-content
attribute is present:
If the content
attribute is not present, then
the content
attribute is set to be the same as the
x-rdf-content
attribute.
The x-rdf-content
attribute is removed, as
it was only ever supposed to be temporary.
For each a from { datatype , property , rel , rev , typeof }:
If there is no attribute x-rdf-a
then skip to the next value of a.
If the element 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.
The document is processed to produce triples, as described in 5. Processing Model of [RDFA].
This sub-section is informative.
Here is the RDF-EASE being used in the example:
_ { foaf: url("http://xmlns.com/foaf/0.1/"); dc: url("http://purl.org/dc/terms/"); ex: url("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 in the reference parsing algorithm, the document will look like this:
<!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 x-rdf-property=" kwijibo:http://purl.org/dc/terms/title" x-rdf-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 x-rdf-typeof=" kwijibo:http://xmlns.com/foaf/0.1/Person kwijibo:http://example.org/ns#ListItem" x-rdf-property=" kwijibo:http://xmlns.com/foaf/0.1/name" >Alice Jones</li> <li title="Robert Smith" x-rdf-content="Robert Smith" x-rdf-typeof=" kwijibo:http://xmlns.com/foaf/0.1/Person kwijibo:http://example.org/ns#ListItem" x-rdf-property=" kwijibo:http://xmlns.com/foaf/0.1/name" >Bob Smith</li> <li property="foaf:nickname" x-rdf-typeof=" kwijibo:http://xmlns.com/foaf/0.1/Person kwijibo:http://example.org/ns#ListItem" x-rdf-property=" kwijibo:http://xmlns.com/foaf/0.1/name" >Carol Black</li> </ul> </body> </html>
After step #9, this has been reduced 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 #10, 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.
_ { audio: url("http://purl.org/media/audio#"); comm: url("http://purl.org/commerce#"); dc: url("http://purl.org/dc/terms/"); foaf: url("http://xmlns.com/foaf/0.1/"); media: url("http://purl.org/media#"); } .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"); }
I will start noting changes to this draft has been published to an HTTP URI.
@@TODO