In a previous exercise, you marked up a catalog page with the schema.org vocabulary using RDFa attributes. In this exercise, you will focus on marking up the library holdings so that they can be recognized as Products with associated Offers by search engines (analogous to products available in online stores).
Audience: Intermediate
Prerequisites: To complete this codelab, you should already be familiar with HTML, RDFa, and schema.org. The previous exercise offers a practical introduction to those concepts.
schema.org adopted the existing GoodRelations vocabulary as a way of expressing products and services that are available for sale. As it turns out, although some of the property and type names reflect a commercial bias, you can use the same vocabulary elements can to express non-commercial offers--such as the offer to lend a library resource to a patron.
In this exercise, you will turn the existing Book
entity into a
multi-typed entity by adding Product
to the type declaration. This enables the described resource to satisfy
properties expecting a value of either Book
or
Product
, and also makes a union of the properties from
those types available to further describe the resource.
Open step1/rdfa_book.html
in a text
editor. You should see something like the following HTML source for the
web page:
<!DOCTYPE html>
<html>
<head>
<title>Las Vegas-Clark County Library District /All Locations</title>
</head>
<body vocab="http://schema.org/" typeof="Book" resource="#book">
<link property="sameAs" href="https://www.googleapis.com/freebase/v1/rdf/m/01069fkb">
<link property="sameAs" href="http://worldcat.org/entity/work/id/1782516719">
<link property="sameAs" href="http://www.scholastic.ca/books/view/spirit-animals-book-three-blood-ties">
<meta property="typicalAgeRange" content="8-12">
<div id="coverImage">
...
Note: In a pinch, you can use the browser development tools to
view and edit the source of the web page (CTRL-Shift-i
in
Chrome or Firefox, in the Elements or Inspector tab
respectively).
Product
to the type declaration
Add Product
to the typeof
attribute in the
<body>
element. Check the results with one or more
of the structured data testing tools.
You should see that both the Book
and Product
types are recognized. You may note, however, that Google's SDTT only
recognizes the first declared type; this is a limitation of their tool and does
not necessarily represent the results of their actual search engine.
<!DOCTYPE html>
<html>
<head>
<title>Las Vegas-Clark County Library District /All Locations</title>
<style>...</style>
</head>
<body vocab="http://schema.org/" typeof="Book Product" resource="#book">
...
Offer
Products link to their offers via the offers
property. The
expected range of the offers
property is an Offer
entity.
Declare each holding in the catalog record as a separate Offer
.
<!DOCTYPE html>
<body vocab="http://schema.org/" typeof="Book" resource="#book">
...
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td>Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td>Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF</td>
</tr>
...
Offer
While sellers of bibliographic items have a fairly clear mapping to
Offer
, the applicability
for libraries is a bit less obvious. To express individual items that are
available to purchase or borrow, begin by mapping your holding properties to
Offer
properties as follows:
seller
:
the attribute name is commercial, but it will be treated by schema.org
processors as the organization or individual offering the item; the fact that
it may be a loan instead of a sale can be handled as part of the Offer.
businessFunction
:
the closest match for "loan" is http://purl.org/goodrelations/v1#LeaseOut
and this overrides the default value of "for sale".
price
; if
your library does not charge for regular loans, set a price of
0.00
so that consuming applications can display a price
accordingly.
<!DOCTYPE html>
<body vocab="http://schema.org/" typeof="Book" resource="#book">
...
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>DUE 06-10-14
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Enterprise YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>AVAILABLE
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
...
The item holding status best maps to the availability
property, which can take one of the following values:
<link property="availability" href="http://schema.org/InStock">
<link property="availability" href="http://schema.org/OutOfStock">
<link property="availability" href="http://schema.org/PreOrder" />
<link property="availability" href="http://schema.org/InStoreOnly">
If you have chosen to publicly display due dates in your system, you can
also use the availabilityStarts
property to provide an estimate of when the item will be available. The
property expects a date/time value in ISO8601 format following the pattern
YYYY-MM-DDThh:mm:ss
(with an optional positive or negative time
appended to indicate a time zone offset). Reminder: use the
content
attribute to supply the machine-readable counterparts for
human-readable values.
Reflect the availability of each holding in the markup of the page.
<!DOCTYPE html>
<body vocab="http://schema.org/" typeof="Book" resource="#book">
...
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF
<link property="availability" href="http://schema.org/OutOfStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF
<link property="availability" href="http://schema.org/OutOfStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td property="availabilityStarts" content="2014-06-10T00:00:00">DUE 06-10-14
<link property="availability" href="http://schema.org/OutOfStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Enterprise YPL</td>
<td><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>AVAILABLE
<link property="availability" href="http://schema.org/InStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
...
Earlier, you identified with which library each item is associated;
however, that may not be enough to identify the location of a given copy
of a resource. There are a number of other Offer
properties
that are suitable for providing more granular location information for
items:
sku
:
the attribute name stock keeping unit is overly specific, but
the intended role as an inventory identifier and physical locator for a
specific organization is a reasonable match for a call number.
serialNumber
:
as a unique identifier for a single item, serialNumber
is a
good match for barcodes.
availableAtOrFrom
:
ideally, one would use a Place
->
containedIn
-> Place
relationship to identify a
location within a given building, but in practice most sites will likely supply
a simple text value like "Stacks" or "Reference"
Add markup for the call number in the holdings page.
<!DOCTYPE html>
<body vocab="http://schema.org/" typeof="Book" resource="#book">
...
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td property="sku"><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF
<link property="availability" href="http://schema.org/OutOfStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td property="sku"><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>ON HOLDSHELF
<link property="availability" href="http://schema.org/OutOfStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Centennial Hills YPL</td>
<td property="sku"><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td property="availabilityStarts" content="2014-06-10T00:00:00">DUE 06-10-14
<link property="availability" href="http://schema.org/OutOfStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
<tr class="bibItemsEntry" property="offers" typeof="Offer">
<td property="seller">Enterprise YPL</td>
<td property="sku"><a href="/search~S12?/hJ/hj/-3,-1,,B/browse">J</a></td>
<td>AVAILABLE
<link property="availability" href="http://schema.org/InStock">
<link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut">
<meta property="price" content="0.00">
</td>
</tr>
...
Checkpoint: Your original HTML page should now look like step1/check_a.html.
In this exercise, you learned how to express library holdings using the GoodRelations agent-promise-object model, adapting commercial properties to non-commercial usage where necessary.
Dan Scott is a systems librarian at Laurentian University.
This work
is licensed under a Creative
Commons Attribution-ShareAlike 4.0 International License.