=== modified file 'modules/node/node.install'
--- modules/node/node.install	2009-08-31 16:24:15 +0000
+++ modules/node/node.install	2009-09-11 11:23:02 +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-09-15 20:54:27 +0000
+++ modules/node/node.module	2009-09-16 06:00:09 +0000
@@ -495,6 +495,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) {
@@ -640,6 +641,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()
@@ -694,10 +698,40 @@ 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(
+        'property' => array('dc:title'),
+      ),
+      'created' => array(
+        'property' => array('dc:date', 'dc:created'),
+        'datatype' => 'xsd:dateTime',
+        'callback' => 'date_iso8601',
+      ),
+      'changed' => array(
+        'property' => array('dc:modified'),
+      ),
+      'body'    => array(
+        'property' => array('content:encoded'),
+      ),
+      'uid'     => array(
+        'property' => array('sioc:has_creator', 'foaf:maker'),
+      ),
+      'name'    => array(
+        'property' => array('foaf:name'),
+      ),
+    );
   }
 
-  $new_type = clone $type;
   $info = (array) $info;
+
+  // Use a specific RDF mapping for this node type if a module defines it.
+  $rdf_mapping = module_invoke_all('rdf_mapping');
+  if (!empty($info['type']) && !empty($rdf_mapping[$info['type']])) {
+    $info['rdf_mapping'] = $rdf_mapping[$info['type']];
+  }
+
+  $new_type = clone $type;
   foreach ($info as $key => $data) {
     $new_type->$key = $data;
   }

=== modified file 'modules/node/node.test'
--- modules/node/node.test	2009-08-29 04:16:14 +0000
+++ modules/node/node.test	2009-09-15 17:28:19 +0000
@@ -615,6 +615,68 @@ 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');
+  }
+
+  function testNodeRdfa() {
+    $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+    $node_resource = check_url(url('node/' . $node->nid, array('fragment' => 'this')));
+    $user_resource = check_url(url('user/' . $node->uid, array('fragment' => 'this')));
+
+    // Test node in full node mode.
+    $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('//meta[contains(@property, "dc:title")]');
+    $this->assertFalse(empty($result), t('Found a meta 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 node in teaser mode.
+    $this->drupalGet('');
+
+    $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('//h2[contains(@property, "dc:title")]');
+    $this->assertFalse(empty($result), t('Found a h2 tag with property=dc:title'));
+
+  }
+
+}
+
 /**
  * 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-09-11 06:48:02 +0000
+++ modules/node/node.tpl.php	2009-09-12 09:07:46 +0000
@@ -83,8 +83,8 @@
       <?php if ($display_submitted): ?>
         <span class="submitted">
           <?php
-            print t('Submitted by !username on @datetime',
-              array('!username' => $name, '@datetime' => $date));
+            print t('Submitted by !username on !datetime',
+              array('!username' => $name, '!datetime' => $date));
           ?>
         </span>
       <?php endif; ?>

