=== modified file 'modules/node/node.install'
--- modules/node/node.install	2009-08-31 16:24:15 +0000
+++ modules/node/node.install	2009-08-31 18:48:20 +0000
@@ -344,6 +344,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'),
   );
@@ -562,6 +569,22 @@ function node_update_7007() {
 }
 
 /**
+ * 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;
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */

=== modified file 'modules/node/node.module'
--- modules/node/node.module	2009-08-31 17:05:33 +0000
+++ modules/node/node.module	2009-08-31 19:34:02 +0000
@@ -467,6 +467,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) {
@@ -612,6 +613,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()
@@ -666,6 +670,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;
@@ -1093,6 +1106,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);
 
@@ -1124,6 +1142,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();
 
@@ -3120,3 +3140,16 @@ class NodeController extends DrupalDefau
     parent::attachLoad($nodes);
   }
 }
+
+/**
+ * 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-08-29 04:16:14 +0000
+++ modules/node/node.test	2009-08-31 16:07:47 +0000
@@ -615,6 +615,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-29 04:16:14 +0000
+++ modules/node/node.tpl.php	2009-08-31 19:55:17 +0000
@@ -70,7 +70,7 @@
  * @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; ?>
 

