=== added directory 'modules/rdf'
=== added file 'modules/rdf/rdf.api.php'
--- modules/rdf/rdf.api.php	1970-01-01 00:00:00 +0000
+++ modules/rdf/rdf.api.php	2009-06-15 09:15:22 +0000
@@ -0,0 +1,51 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Hooks provided by the RDF module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Allow modules to define their own RDF mappings.
+ * 
+ * @return
+ *   An associative array of mappings. Most keys will be bundle names, but 
+ *   mappings can also be defined for non-bundles.
+ */
+function hook_rdf_mapping() {
+  return array(
+    'blog' => array(
+      'rdftype' => 'sioc:Post',
+      'title'   => array('dc:title'),
+      'created' => array(
+        'properties' => array('dc:date', 'dc:created'),
+        'datatype' => 'xsd:dateTime',
+        'callback' => 'date_iso8601',
+      ),
+      'name'    => array('foaf:name'),
+      'uid'     => array('sioc:has_creator', 'foaf:maker'),
+    )
+  );
+} 
+ 
+/**
+ * Allow modules to override existing mappings.
+ *  
+ * @param $mappings
+ *   An associative array of mappings
+ * @return
+ *   void
+ *
+ */
+function hook_rdf_mapping_alter(&$mapping) {
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

=== added file 'modules/rdf/rdf.info'
--- modules/rdf/rdf.info	1970-01-01 00:00:00 +0000
+++ modules/rdf/rdf.info	2009-06-15 08:23:40 +0000
@@ -0,0 +1,6 @@
+; $Id$
+name = RDF
+description = Supports RDF mappings.
+package = Core
+core = 7.x
+files[] = rdf.module

=== added file 'modules/rdf/rdf.module'
--- modules/rdf/rdf.module	1970-01-01 00:00:00 +0000
+++ modules/rdf/rdf.module	2009-06-15 08:36:20 +0000
@@ -0,0 +1,114 @@
+<?php
+
+// $Id: $
+
+/**
+ * @file
+ * Support for RDF mappings
+ */
+
+/**
+ * Base class for all exceptions thrown by RDF functions.
+ *
+ * This class has no functionality of its own other than allowing all
+ * RDF exceptions to be caught by a single catch block.
+ */
+class RdfException extends Exception {}
+
+/**
+ * Returns the mapping for the attributes of the given bundle as an
+ * associative array.
+ *
+ * @param $bundle
+ *   A bundle name
+ * @return array
+ *   The mappings
+ */
+function rdf_get_mapping($bundle) {
+  $rdf_mapping = module_invoke_all('rdf_mapping');
+  
+  // Allow other modules to alter RDF mappings.
+  drupal_alter('rdf_mapping', $rdf_mapping);
+    
+  if (!array_key_exists($bundle, $rdf_mapping)) {
+    $rdf_mapping[$bundle] = array();
+  }
+  
+  return $rdf_mapping[$bundle];
+}
+
+/**
+ * Stores the page level RDF mapping in the dictionary.
+ *
+ * @param $mapping
+ * @return array
+ *   the stored mapping
+ */
+function drupal_set_rdf_page_mapping($mapping = NULL) {
+  $default_mapping = array(
+    'title' => 'dc:title',
+  );
+  $stored_mapping = &drupal_static(__FUNCTION__, $default_mapping);
+  
+  if (!is_null($mapping)) {
+    $stored_mapping = $mapping;
+  }
+  
+  return $stored_mapping;
+}
+
+/**
+ * Returns the page level RDF mapping from the dictionary.
+ *
+ * @return array
+ *   the page level RDF mapping
+ */
+function drupal_get_rdf_page_mapping() {
+  return drupal_set_rdf_page_mapping();
+}
+
+/**
+ * Returns RDFa attributes for output in XHTML elements.
+ *
+ * @param $mapping
+ *   An array containing either a simple mapping or a complex array with
+ *   property, datatype and callback.
+ * @param $data
+ * @return string
+ *   An XHTML string ready for insertion into a tag.
+ */
+function drupal_rdfa_attributes($mapping, $data = NULL) {
+  if (!isset($mapping['property'])) {
+    $attributes['property'] = implode(' ', $mapping);
+  }
+  else {
+    $attributes['property'] = implode(' ', $mapping['property']);
+    
+    if (isset($mapping['callback']) && !is_null($data)) {
+      $callback = $mapping['callback'];
+      
+      if (drupal_function_exists($callback)) {
+        $attributes['content'] = call_user_func($callback, $data);
+      }
+      if (isset($mapping['datatype'])) {
+        $attributes['datatype'] = $mapping['datatype'];
+      }
+    }
+  }
+  
+  return drupal_attributes($attributes);
+}
+
+/**
+ * Allow the module to redefine its variables for the page metadata.
+ *
+ * This could allow us to avoid modifying theme.inc so much.
+ *
+ * @param $variables
+ *   An array of variables to be exposed to the page template.
+ * @return
+ *   None.
+ */
+function rdf_preprocess_page(&$variables) {
+	// dsm(array("rdf_preprocess_page" => drupal_get_rdf_page_mapping()));
+}
\ No newline at end of file

=== added file 'modules/rdf/rdf.test'
--- modules/rdf/rdf.test	1970-01-01 00:00:00 +0000
+++ modules/rdf/rdf.test	2009-06-08 20:33:05 +0000
@@ -0,0 +1,94 @@
+<?php
+// $Id$
+
+class RdfMappingTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('RDF mappings'),
+      'description' => t('Test RDF mapping hooks.'),
+      'group' => t('RDF'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rdf', 'rdf_test');
+  }
+
+  /**
+   * Test that the mappings are correctly returned and processed by the hooks.
+   */
+  function testMappings() {
+    // Test that the mapping is returned correctly by the hook.
+    $mapping = rdf_get_mapping('rdf_test_container');
+    $this->assertIdentical($mapping['rdftype'], array('sioc:Post'), t('Mapping for rdftype is sioc:Post.'));
+    $this->assertIdentical($mapping['title'], array('dc:title'), t('Mapping for title is dc:title.'));
+    $this->assertIdentical($mapping['created'], array('dc:created'), t('Mapping for created is dc:created.'));
+    $this->assertTrue(in_array('sioc:has-creator', $mapping['uid']), t('Mapping for uid contains sioc:has-creator'));
+    $this->assertTrue(in_array('dc:creator', $mapping['uid']), t('Mapping for uid contains dc:creator'));
+
+    // Test that an empty array is returned when a container has no mappings.
+    $mapping = rdf_get_mapping('rdf_test_nonexistent_container');
+    $this->assertTrue(is_array($mapping) && empty($mapping), t('Empty array returned for container with no mappings'));
+
+    // Test that the mappings are altered correctly.
+    $mapping = rdf_get_mapping('rdf_test_another');
+    $this->assertTrue(in_array('dc:title', $mapping['title']), t('Mapping for title contains dc:title'));
+    $this->assertTrue(in_array('sioc:title', $mapping['title']), t('Mapping for title contains sioc:title'));
+    $this->assertTrue(in_array('sioc:has-creator', $mapping['uid']), t('Mapping for uid contains sioc:has-creator'));
+    $this->assertTrue(in_array('foo:bar', $mapping['uid']), t('Mapping for uid contains foo:bar'));
+    $this->assertFalse(in_array('dc:creator', $mapping['uid']), t('Mapping for uid does not contain dc:creator'));
+    $this->assertTrue(in_array('foaf:Person', $mapping['name']), t('Mapping for name contains foaf:Person'));
+    $this->assertFalse(in_array('dc:creator', $mapping['name']), t('Mapping for name does not contain dc:creator'));
+    $this->assertIdentical($mapping['rdftype'], array('foaf:Person'), t('Mapping for rdftype was changed'));
+    $this->assertFalse(isset($mapping['foobar']), t('Mapping for foobar was removed.'));
+  }
+
+  /**
+   * Test manually setting and getting the page mapping.
+   */
+  function testPageMapping() {
+    // Default value should be returned if nothing was explicitly set.
+    $this->assertEqual(drupal_get_rdf_page_mapping(), array('title' => 'dc:title'), t('Default mapping is set correctly.'));
+
+    // If we manually set a mapping, that should replace the default.
+    drupal_set_rdf_page_mapping(array('foobar' => 'foo:bar'));
+    $this->assertEqual(drupal_get_rdf_page_mapping(), array('foobar' => 'foo:bar'), t('Custom mapping overrides default mapping.'));
+  }
+}
+
+class RdfaMarkupTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('RDFa markup'),
+      'description' => t('Test RDF markup generation.'),
+      'group' => t('RDF'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rdf', 'rdf_test');
+  }
+  
+  function testDrupalRdfaAtributes() {
+    $date = '2009-05-14';
+    $isoDate = date(DATE_ISO8601, strtotime($date));
+    
+    $expectedType = 'datatype="xsd:dateTime"';
+    $expectedProperty = 'property="dc:created"';
+    $expectedValue = "content=\"$isoDate\"";
+    $mapping = rdf_get_mapping('rdf_complex_test');
+    $attributes = drupal_rdfa_attributes($mapping['date'], $date);
+    
+    $this->assertNotEqual(FALSE, strpos($attributes, $expectedType));
+    $this->assertNotEqual(FALSE, strpos($attributes, $expectedProperty));
+    $this->assertNotEqual(FALSE, strpos($attributes, $expectedValue));
+     
+    $expectedProperty = 'property="dc:title"';
+    $mapping = rdf_get_mapping('rdf_test_container');
+    $attributes = drupal_rdfa_attributes($mapping['title']);
+
+    $this->assertNotEqual(FALSE, strpos($attributes, $expectedProperty));
+  }
+}
+
+

=== added directory 'modules/rdf/tests'
=== added file 'modules/rdf/tests/rdf_test.info'
--- modules/rdf/tests/rdf_test.info	1970-01-01 00:00:00 +0000
+++ modules/rdf/tests/rdf_test.info	2009-05-12 16:33:29 +0000
@@ -0,0 +1,8 @@
+; $Id$
+name = "RDF module tests"
+description = "Support module for RDF module testing."
+package = Testing
+version = VERSION
+core = 7.x
+files[] = rdf_test.module
+hidden = TRUE

=== added file 'modules/rdf/tests/rdf_test.module'
--- modules/rdf/tests/rdf_test.module	1970-01-01 00:00:00 +0000
+++ modules/rdf/tests/rdf_test.module	2009-06-08 20:33:05 +0000
@@ -0,0 +1,83 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Dummy module implementing RDF related hooks to test API interaction with
+ * the RDF module.
+ */
+
+/**
+ * Implementation of hook_rdf_mapping().
+ */
+function rdf_test_rdf_mapping() {
+  return array(
+    'rdf_test_container' => array(
+      'rdftype' => array('sioc:Post'),
+      'title' => array('dc:title'),
+      'created' => array('dc:created'),
+      'uid' => array(
+        'sioc:has-creator',
+        'dc:creator',
+      ),
+      'foobar' => array('foo:bar'),
+    ),
+    'rdf_test_another' => array(
+      'title' => array('dc:title'),
+      'rdftype' => array('sioc:User'),
+      'name' => array('dc:creator'),
+      'uid' => array(
+        'sioc:has-creator',
+        'dc:creator',
+      ),
+      'foobar' => array('foo:bar'),
+    ),
+    'rdf_complex_test' => array(
+      'date' => array(
+        'datatype' => 'xsd:dateTime',
+        'callback' => 'rdf_test_date',
+        'property' => array('dc:created'),
+      ),
+    )
+  );
+}
+
+/**
+ * Implementation of hook_rdf_mapping_alter().
+ */
+function rdf_test_rdf_mapping_alter(&$mapping) {
+  // Add a single mapping without overriding anything.
+  $mapping['rdf_test_another']['name'][] = 'foaf:Person';
+
+  // Add a multi-value mapping without overwriting anything.
+  $mapping_addition = array(
+    'rdf_test_another' => array(
+      'title' => 'sioc:title',
+    ),
+  );
+  $mapping = array_merge_recursive($mapping, $mapping_addition);
+
+  // @TODO - in both above examples, what happens if we declare the same
+  // property more than once-- so that 'title' equals for instance
+  // array('foaf:Person', 'dc:title', 'foaf:Person')
+  // should/could we force values to unique at some point?
+
+  // Override (replace) a single property.
+  if (isset($mapping['rdf_test_another']['uid'])) {
+    $mapping['rdf_test_another']['uid'] = array_diff($mapping['rdf_test_another']['uid'], array('dc:creator'));
+    $mapping['rdf_test_another']['uid'][] = 'foo:bar';
+  }
+
+  // Delete a specific property.
+  $mapping['rdf_test_another']['name'] = array_diff((array)$mapping['rdf_test_another']['name'], array('dc:creator'));
+
+  // Delete all mappings for an attribute.
+  unset($mapping['rdf_test_another']['foobar']);
+
+  // Replace a mapping.
+  $mapping['rdf_test_another']['rdftype'] = array('foaf:Person');
+}
+
+function rdf_test_date($date) {
+  return date(DATE_ISO8601, strtotime($date));
+}

=== modified file 'modules/system/page.tpl.php'
--- modules/system/page.tpl.php	2009-05-28 16:44:05 +0000
+++ modules/system/page.tpl.php	2009-06-09 21:18:12 +0000
@@ -160,9 +160,9 @@
 
     <div id="main-wrapper"><div id="main" class="clearfix">
 
-      <div id="content" class="column"><div class="section">
+      <div id="content" class="column"<?php print $rdfa_page_about_typeof; ?>><div class="section">
         <?php if ($highlight): ?><div id="highlight"><?php print $highlight; ?></div><?php endif; ?>
-        <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
+        <?php print $title_rendered; ?>
         <?php if ($tabs): ?><div class="tabs"><?php print $tabs; ?></div><?php endif; ?>
         <?php print $help; ?>
         <div id="content-area" class="region">

=== modified file 'modules/system/system.module'
--- modules/system/system.module	2009-06-16 08:41:35 +0000
+++ modules/system/system.module	2009-06-16 10:18:14 +0000
@@ -237,7 +237,9 @@
     'rdf'      => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
     'rdfs'     => 'http://www.w3.org/2000/01/rdf-schema#',
     'rss'      => 'http://purl.org/rss/1.0/',
+    'tags'     => 'http://www.holygoat.co.uk/owl/redwood/0.1/tags/',
     'sioc'     => 'http://rdfs.org/sioc/ns#',
+    'skos'     => 'http://www.w3.org/2004/02/skos/core#',
     'xsd'      => 'http://www.w3.org/2001/XMLSchema',
   );
 }

=== modified file 'includes/theme.inc'
--- includes/theme.inc	2009-06-13 19:34:57 +0000
+++ includes/theme.inc	2009-06-16 09:31:56 +0000
@@ -1744,11 +1744,21 @@
       $name = $object->name;
     }
 
+    if (!empty($object->rdf_mapping['name'])) {
+      $name = '<span property="' . implode(' ', (array)$object->rdf_mapping['name']) . '">' . check_plain($name) . '</span>';
+    }
+
     if (user_access('access user profiles')) {
-      $output = l($name, 'user/' . $object->uid, array('attributes' => array('title' => t('View user profile.'))));
+      if (!empty($object->rdf_mapping['uid'])) {
+      $user_uri = url('user/' . $object->uid, array('fragment' => 'this'));
+        $output = '<span rel="' . implode(' ', (array)$object->rdf_mapping['uid']) . '">' . l($name, 'user/' . $object->uid, array('attributes' => array('title' => t('View user profile.'), 'about' => $user_uri), 'html' => TRUE)) . '</span>';
+      }
+      else {
+        $output = l($name, 'user/' . $object->uid, array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE));      
+      }
     }
     else {
-      $output = check_plain($name);
+      $output = $name;
     }
   }
   elseif ($object->name) {
@@ -1965,6 +1975,36 @@
   $variables['scripts']           = drupal_get_js();
   $variables['tabs']              = theme('menu_local_tasks');
   $variables['title']             = drupal_get_title();
+
+  $variables['rdfa_page_about_typeof'] = '';
+  $variables['rdfa_page_title'] = '';
+
+  // @TODO move conditional logic to an rdf.inc file-- if it has to be in core required, it should be encapsulated as well as possible
+  if (module_exists('rdf')) {
+    // Contruct the RDFa markup.
+    $rdf_page_mapping = drupal_get_rdf_page_mapping();
+    //var_dump($rdf_page_mapping);
+    if (!empty($rdf_page_mapping['rdftype'])) {
+      $variables['rdfa_page_about_typeof'] = ' about="#this" typeof="' . implode(' ', (array)$rdf_page_mapping['rdftype']) . '"';
+    }
+    else {
+      // Even if we don't have an RDF type for the resource described on the page
+      // we create a URI for it.
+      $variables['rdfa_page_about_typeof'] = ' about="#this"';
+    }
+    if (!empty($rdf_page_mapping['title'])) {
+      $variables['rdfa_page_title'] = ' property="' . implode(' ', (array)$rdf_page_mapping['title']) . '"';
+    }
+  }
+  else {
+    // we still need to create blank variables
+    // @TODO move conditional logic to an rdf.inc file-- if it has to be in core required, it should be encapsulated as well as possible
+    $variables['rdfa_page_about_typeof'] = '';
+    $variables['rdfa_page_title'] = '';
+  }
+
+  // TODO create a separate non-RDFa related patch. 
+  $variables['title_rendered']    = $variables['title'] ? '<h1 class="title" id="page-title"' . $variables['rdfa_page_title'] . '>' . $variables['title'] . '</h1>' : '';
   // RDFa allows annotation of XHTML pages with RDF data, while GRDDL provides
   // mechanisms for extraction of this RDF content via XSLT transformation
   // using an associated GRDDL profile.

