RDFa with schema.org codelab: Library holdings

By Dan Scott,

About this codelab

In a previous exercise, you marked up holdings in a catalog page with the schema.org vocabulary using RDFa attributes. However, when you identified the library that holds a given copy of a resource, you only used a text string--and as there are many library branches named "Main Branch" or "Central Library" in the world, general consumers of your structured data such as search engines may not be able to determine basic information such as where your library is located, and fail to connect potential patrons with your library's resources. In this exercise, you will mark up library web pages with address information, contact information, and opening hours, then link your catalog pages to the library web pages to complete the relationship between your resources and your library.

When you search for a library on different search engines, you will probably get different and conflicting sets of information about the library. The results often depend on where the information is pulled from, which in turn depends on relationships that the search engines have with various data providers. For example, comparing searching for my home library J.N. Desmarais Library:

This is a sad state of affairs, and while our library certainly could work harder on outreach and search engine optimization, we are hardly alone.

Having to maintain information such as address, contact information, and hours of operation in multiple places is inefficient and error-prone. Rather than pushing information to multiple sites, it makes much more sense to allow interested sites to pull the information from one authoritative source. OCLC has positioned themselves to provide this information to the various commercial companies, but the simplest possible method would be for libraries to simply mark up their own library home pages (where that information almost certainly already exists for the benefit of human readers) with the relevant schema.org structured data so that the machines can benefit as well.

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.

Identifying the Library entity

The core information that many users want to find when they look for a business online include locations, operating hours, contact information, and branch relationships. For libraries, schema.org models this information in the Organization -> LocalBusiness -> Library hierarchy.

In this exercise, you will take a simple library web page and identify some of the core information in it using the Library type and its properties.

View the library page source HTML

Open step1/centennial_branch.html in a text editor. You should see something like the following HTML source for the web page:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LVCCLD-Centennial Hills Library</title></head>
<body>
  <div id="main-content">
...
    <div id="main-copy">
      <!-- #main-copy-->

      <p id="breadcrumb"><a href="../index.cfm">Home</a> / <a href="locations.cfm">Locations & Hours</a></p>

      <h2>Centennial Hills Library</h2>

      <div class="photo"><img src="../images/library.png" width="180" height="165" alt="Centennial Hills Library Photo"></div>

      <div style="float:left; margin:0 0 0 15px;">
        <div style="font-weight:bold">
          Address:
        </div>Centennial Hills Library<br>
        6711 N. Buffalo Dr.<br>
        Las Vegas, NV 89131<br>

        <div style="font-weight:bold">
          Hours:
        </div>M - Th, 10 a.m. - 8 p.m.<br>
        F - Sun, 10 a.m. - 6 p.m.
      </div>

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).

Declare the core type of the page as Library

Edit the <body> element to include your @vocab declaration for the schema.org vocabulary, add a @typeof value of Library, and set a @resource value. Check the results with one or more of the structured data testing tools.

You should see that the page is now recognized as describing a Library entity.

Check your markup
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LVCCLD-Centennial Hills Library</title>
</head>
<body vocab="http://schema.org/" typeof="Library" resource="#library">
  <div id="main-content">
...

Mark the basic name, image, and description properties

As most schema.org types inherit from Thing, some of the core properties are name, image, and description. These properties are often used to generate rich snippets (short summaries displayed in search results).

Declare the appropriate name, image, and description properties for this library.

Check your markup
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LVCCLD-Centennial Hills Library</title>
</head>

<body vocab="http://schema.org/" typeof="Library" resource="#library">
  <div id="main-content">
...
      <h2 property="name">Centennial Hills Library</h2>

      <div class="photo">
        <img src="../images/library.png" alt="Centennial Hills Library Photo" property="image">
      </div>
...
      <div style="font-weight:bold">
        About the Library:
      </div>

      <div property="description">
        <p>Opened in 2009, the 45,555 SF Centennial
          Hills Library is located at the intersection of N. Buffalo Drive and Deer
          Springs Way, adjacent to the Centennial Hills Park. The building is
          LEED certified gold, meaning it is constructed to reduce negative environmental
          impacts and improve occupant health and well-being.
        </p>

        <p>The library offers:</p>

        <ul>
          <li>A well-rounded collection of books, magazines, newspapers, DVDs, music CDs and audio books</li>

          <li>A 22-seat Adult Computer Lab, 12 family resource computers, 8 children's computers, free Wi-Fi, and wireless printing</li>

          <li>A dedicated Homework Help Center that includes 20 laptops</li>

          <li>Weekly storytimes and special programs for a wide variety of ages</li>

          <li>One meeting room with a 60-seat capacity</li>

          <li>A used bookstore and café area</li>

          <li>Knowledgeable, friendly staff to assist you</li>
        </ul>
      </div>
    </div><!-- /#main-copy-->
...

Declare the address

Identifying the address for the branch helps consuming applications provide a geographic context for their users. For example, the application could order search results based on proximity to the searcher's own geolocation. The Organization type from which Library inherits includes a address property for this purpose. address expects a PostalAddress entity for its value, which includes the following properties:

addressCountry
The country for the address, in either plain text or ISO 3166-1 alpha2 format.
addressLocality
The name of the city.
addressRegion
The name of the state or province.
postOfficeBoxNumber
The PO box number, if applicable.
postalCode
The postal code or zip code.
streetAddress
The number and name of the street.

Mark up the address for this branch.

Check your markup
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LVCCLD-Centennial Hills Library</title>
</head>

<body vocab="http://schema.org/" typeof="Library" resource="#library">
...
  <div style="font-weight:bold">
    Address:
  </div>
  <div property="address" typeof="PostalAddress">
    Centennial Hills Library<br>
    <span property="streetAddress">6711 N. Buffalo Dr.</span><br>
    <span property="addressLocality">Las Vegas</span>,
    <span property="addressRegion">NV</span> <span property="postalCode">89131</span>
  </div>
...

Highlight the operating hours

Operating hours are one of the most frequently consulted pieces of information for any organization. The schema.org vocabulary provides two different ways of marking up operating hours. In this exercise, you will use the much more structured openingHoursSpecification (which was derived from the GoodRelations vocabulary) instead of the similarly named but less structured openingHours.

The openingHoursSpecification property expects a OpeningHoursSpecification type, which is composed of the following properties:

closes
The time at which the business closes, in hh:mm:ss[Z|(+|-)hh:mm] format.
dayOfWeek
Use the following values:
DayValue
Monday http://purl.org/goodrelations/v1#Monday
Tuesday http://purl.org/goodrelations/v1#Tuesday
Wednesday http://purl.org/goodrelations/v1#Wednesday
Thursday http://purl.org/goodrelations/v1#Thursday
Friday http://purl.org/goodrelations/v1#Friday
Saturday http://purl.org/goodrelations/v1#Saturday
Sunday http://purl.org/goodrelations/v1#Sunday
Public holidays http://purl.org/goodrelations/v1#PublicHolidays
opens
The time at which the business opens, in hh:mm:ss[Z|(+|-)hh:mm] format.
validFrom
The point in time when the opening hours data becomes valid.
validThrough
The point in time when the opening hours data will no longer be valid.

Given this information, mark up the operating hours for this branch.

Check your markup
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LVCCLD-Centennial Hills Library</title>
</head>

<body vocab="http://schema.org/" typeof="Library" resource="#library">
...
  <div style="font-weight:bold">
    Hours:
  </div>
  <div property="openingHoursSpecification" typeof="OpeningHoursSpecification">M - Th,
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Monday">
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Tuesday">
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Wednesday">
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Thursday">
    <span property="opens" content="10:00:00">10 a.m.</span> - 
    <span property="closes" content="20:00:00">8 p.m.</span>
  </div>
  <div property="openingHoursSpecification" typeof="OpeningHoursSpecification">F - Sun,
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Friday">
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Saturday">
    <link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Sunday">
    <span property="opens" content="10:00:00">10 a.m.</span> -
    <span property="closes" content="18:00:00">6 p.m.</span>
  </div>
...

Mark up email and telephone contact information

Library patrons frequently want to find an email address or telephone number to contact their library. The contactPoint property from Organization expects a ContactPoint type, which bundles together contact properties such as email and telephone.

Use a ContactPoint entity to define the telephone property for your branch. Note: although it is not required by schema.org, providing a machine-readable telephone number via a content attribute is recommended by Google and therefore probably a good idea.

Check your markup
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LVCCLD-Centennial Hills Library</title>
</head>

<body vocab="http://schema.org/" typeof="Library" resource="#library">
...
  <div class="contact" property="contactPoint" typeof="ContactPoint">
    <div style="font-weight:bold">
      Phone:
    </div>
    <meta property="contactType" content="customer service">
    <span property="telephone" content="+17025076100">(702) 507-6100</span><br>

    <div style="font-weight:bold">
      Branch manager:
    </div>Tamara Gieseking<br>
    <br>

    <a href="http://maps.google.com/maps?f=q&hl=en&geocode=&q=6711+N.+Buffalo+Dr.+Las+Vegas+NV+89131&sll=36.285173,-115.258427&sspn=0.057217,0.096989&ll=&ie=UTF8&z=14&iwloc=addr" target="_blank" style="text-decoration:none; float:left">
      <span style="width:66px; height:64px; background:url(../images/compass.png) no-repeat top left; padding:0 10px 0 0; float:left"></span><span style="float:left; line-height:64px;">View Map</span>
    </a>
  </div>
...

Checkpoint: Your original HTML library branch page should now look like step1/branch_check_a.html.

Lessons learned

In this exercise, you learned how to express locations, operating hours, and contact information for a library branch.

Linking holdings to a library entity

When you marked up holdings in your catalog page in the previous exercise, you simply used the name of the library as the value of the seller property. However, the seller property expects an Organization, not a text value. Now that you have marked up your library branch web page as a Library entity, you can link your holdings directly to the entity in your library branch web page. This provides much more contextual information about that holding (such as location, hours of operation, and contact information) to consumers of your linked data.

Edit step1/rdfa_book.html to link the "Centennial Hills YPL" holdings to the Library entity in your library branch web page.

Check your markup
<!DOCTYPE html>
<html>
<head>
  <title>Las Vegas-Clark County Library District /All Locations</title>
</head>

<body vocab="http://schema.org/" typeof="Book Product" resource="#book">
...
  <tr class="bibItemsEntry" property="offers" typeof="Offer">
    <td><link property="seller" href="branch_check_a.html#library">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><link property="seller" href="branch_check_a.html#library">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><link property="seller" href="branch_check_a.html#library">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>
...

Checkpoint: Your catalog page should now look like step1/book_check_a.html.

About the author

Dan Scott is a systems librarian at Laurentian University.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.