=== modified file 'modules/node/node.install'
--- modules/node/node.install	2009-07-27 19:26:31 +0000
+++ modules/node/node.install	2009-08-15 05:53:39 +0000
@@ -327,6 +327,13 @@ function node_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
+      'rdf_mapping' => array(
+        'description' => 'The serialized mapping from basic node attributes to RDF terms.',
+        'type' => 'text',
+        'not null' => FALSE,
+        'size' => 'big',
+        'serialize' => TRUE,
+      ),
     ),
     'primary key' => array('type'),
   );
@@ -525,6 +532,21 @@ function node_update_7006() {
   return $ret;
 }
 
+/**
+ * Add a column to the node_type table to store RDF mappings.
+ */
+function node_Update_7099() {
+  $ret = array();
+  $attributes = array(
+    'not null' => FALSE,
+    'size' => 'big',
+    'serialize' => TRUE,
+    'description' => 'The serialized mapping from basic node attributes to RDF terms.',
+  );
+  db_add_column($ret, 'node_type', 'rdf_mapping', 'text', $attributes);
+  
+  return $ret;
+}
 
 
 /**

=== modified file 'modules/node/node.module'
--- modules/node/node.module	2009-08-14 13:53:01 +0000
+++ modules/node/node.module	2009-08-17 10:29:42 +0000
@@ -419,6 +419,7 @@ function node_type_save($info) {
     'custom' => (int) $type->custom,
     'modified' => (int) $type->modified,
     'locked' => (int) $type->locked,
+    'rdf_mapping' => serialize($type->rdf_mapping),
   );
 
   if ($is_existing) {
@@ -564,6 +565,9 @@ function _node_types_build() {
     ->addTag('node_type_access')
     ->execute();
   foreach ($type_result as $type_object) {
+    if (isset($type_object->rdf_mapping)) {
+      $type_object->rdf_mapping = unserialize($type_object->rdf_mapping);
+    }
     // Check for node types from disabled modules and mark their types for removal.
     // Types defined by the node module in the database (rather than by a separate
     // module using hook_node_info) have a base value of 'node_content'. The isset()
@@ -618,6 +622,15 @@ function node_type_set_defaults($info = 
     $type->modified = 0;
     $type->locked = 1;
     $type->is_new = 1;
+    $type->rdf_mapping = array(
+      'rdftype' => array('sioc:Item', 'foaf:Document'),
+      'title'   => array('dc:title'),
+      'created' => 'dc:created',
+      'changed' => 'dc:modified',
+      'body'    => 'content:encoded',
+      'uid'     => 'sioc:has_creator',
+      'name'    => 'foaf:name',
+    );
   }
 
   $new_type = clone $type;
@@ -826,6 +839,12 @@ function node_load_multiple($nids = arra
     }
     $nodes = $passed_nids;
   }
+  
+  if (module_exists('rdf')) {
+    foreach ($nodes as $node) {
+      $node->rdf_mapping = rdf_get_mapping($node->type);
+    }
+  }
 
   return $nodes;
 }
@@ -1181,6 +1200,11 @@ function node_show($node, $message = FAL
     drupal_set_title(t('Revision of %title from %date', array('%title' => $node->title, '%date' => format_date($node->revision_timestamp))), PASS_THROUGH);
   }
 
+  // When viewing a single node, push the node RDF mapping to the page RDF mapping.
+  if (module_exists('rdf')) {
+    drupal_set_rdf_page_mapping($node->rdf_mapping);
+  }
+
   // Update the history table, stating that this user viewed this node.
   node_tag_new($node->nid);
 
@@ -1212,6 +1236,8 @@ function template_preprocess_node(&$vari
   $variables['date']      = format_date($node->created);
   $variables['name']      = theme('username', $node);
   $variables['node_url']  = url('node/' . $node->nid);
+  // TODO added here for now, but ideally this would come from the instance (node, term, etc.) which should have its own URI generated upstream.
+  $variables['node_uri']  = url('node/' . $node->nid) . '#this';
   $variables['title']     = check_plain($node->title);
   $variables['page']      = (bool)menu_get_object();
 
@@ -1253,6 +1279,23 @@ function template_preprocess_node(&$vari
   // Clean up name so there are no underscores.
   $variables['template_files'][] = 'node-' . str_replace('_', '-', $node->type);
   $variables['template_files'][] = 'node-' . $node->nid;
+
+  if (!empty($node->rdf_mapping)) {
+    // The about and typeof attributes are required when a node is displayed in teaser mode.
+    if (!$variables['page']) {
+      $variables['rdftype'] = drupal_attributes(array('about' => $variables['node_uri'], 'typeof' => implode(' ', $node->rdf_mapping['rdftype'])));
+    }
+    else {
+      $variables['rdftype'] = '';
+    }
+    // The title is only displayed on teaser mode.
+    $variables['title_rendered'] = !$variables['page'] ? '<h2 ' . drupal_attributes(array('property' => implode($node->rdf_mapping['title']))) . '>' . l($node->title, 'node/'. $node->nid) . '</h2>' : '';
+  }
+  else {
+    $variables['rdftype'] = '';
+    // The title is only displayed on teaser mode.
+    $variables['title_rendered'] = !$variables['page'] ? '<h2>' . l($node->title, 'node/'. $node->nid) . '</h2>' : '';
+  }
 }
 
 /**
@@ -3150,3 +3193,16 @@ function node_requirements($phase) {
   );
   return $requirements;
 }
+
+/**
+ * Implementation of hook_rdf_mapping().
+ */
+function node_rdf_mapping() {
+  $types = node_type_get_types();
+  
+  foreach ($types as $type) {
+    $default_node_mapping[$type->type] = isset($type->rdf_mapping) ? $type->rdf_mapping : NULL;
+  }
+  
+  return $default_node_mapping;
+}

=== modified file 'modules/node/node.test'
--- modules/node/node.test	2009-07-28 19:18:05 +0000
+++ modules/node/node.test	2009-08-15 05:42:50 +0000
@@ -586,6 +586,54 @@ class NodeRSSContentTestCase extends Dru
   }
 }
 
+class NodeRDFaTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Node RDFa output'),
+      'description' => t('Ensure that RDFa is output on node pages.'),
+      'group' => t('Node'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rdf');
+    variable_set('theme_default', 'stark');
+  }
+
+  function testNodeRdfa() {
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $node_resource = check_url(url('node/' . $node->nid, array('fragment' => 'this')));
+    $user_resource = check_url(url('user/' . $node->uid, array('fragment' => 'this')));
+
+    $this->drupalGet('node/' . $node->nid);
+
+    $result = $this->xpath('//div[contains(@class, "node") and contains(@typeof, "sioc:Item")]');
+    $this->assertFalse(empty($result), t('Found a typeof attribute including sioc:Item'));
+    // $this->assertEqual($result[0]['about'], $node_resource, t('Found correct about attribute'));
+
+    $result = $this->xpath('//div[contains(@class, "node") and contains(@typeof, "foaf:Document")]');
+    $this->assertFalse(empty($result), t('Found a typeof attribute including foaf:Document'));
+
+    $result = $this->xpath('//h1[contains(@property, "dc:title")]');
+    $this->assertFalse(empty($result), t('Found a h1 tag with property=dc:title'));
+
+    // $result = $this->xpath('//*[contains(@class, "submitted")]//*[contains(@property, "dc:created")]');
+    // $this->assertFalse(empty($result), t('Found a dc:created property'));
+    // $this->assertEqual($result[0]['datatype'], 'xsd:dateTime', t('Found datatype of xsd:dateTime'));
+    // $this->assertTrue(preg_match('/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}/', $result[0]['content']), t('Found a content attribute in the correct format'));
+
+    // $result = $this->xpath('//div[contains(@typeof, "foaf:Document")]//*[contains(@class, "content") and contains(@property, "content:encoded") and contains(@property, "dc:description")]');
+    // $this->assertFalse(empty($result), t('Found content:encoded and dc:description properties'));
+
+    // $result = $this->xpath('//*[contains(@class, "submitted")]//*[contains(@rel, "sioc:has_creator") and contains(@rel, "dc:creator")]');
+    // $this->assertFalse(empty($result), t('Found sioc:has_creator and dc:creator'));
+    // $result = $this->xpath('//*[contains(@class, "submitted")]//*[contains(@rel, "dc:creator")]//*[contains(@property, "foaf:name") and contains(@typeof, "sioc:User")]');
+    // $this->assertFalse(empty($result), t('Found foaf:name and sioc:User'));
+    // $this->assertEqual($result[0]['about'], $user_resource, t('Found correct about attribute'));
+  }
+
+}
+
 /**
  * Test case to verify basic node_access functionality.
  * @todo Cover hook_access in a separate test class.

=== modified file 'modules/node/node.tpl.php'
--- modules/node/node.tpl.php	2009-08-06 05:05:59 +0000
+++ modules/node/node.tpl.php	2009-08-17 10:29:42 +0000
@@ -64,13 +64,11 @@
  * @see template_process()
  */
 ?>
-<div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?> clearfix">
+<div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?> clearfix" <?php print $rdftype ?>>
 
   <?php print $user_picture; ?>
 
-  <?php if (!$page): ?>
-    <h2><a href="<?php print $node_url; ?>"><?php print $title; ?></a></h2>
-  <?php endif; ?>
+  <?php print $title_rendered; ?>
 
   <?php if ($submitted || !empty($content['links']['terms'])): ?>
     <div class="meta">

