diff --git a/includes/SMW_GlobalFunctions.php b/includes/SMW_GlobalFunctions.php
index 84ae4ce..2fbfd8f 100644
--- a/includes/SMW_GlobalFunctions.php
+++ b/includes/SMW_GlobalFunctions.php
@@ -221,6 +221,9 @@ function smwfSetupExtension() {
 	require_once($smwgIP . '/includes/SMW_Hooks.php');
 	require_once($smwgIP . '/includes/SMW_RefreshTab.php');
 
+	require_once($smwgIP . '/includes/SMW_RDFa.php');
+	rdfaSetup();
+
 	$wgHooks['InternalParseBeforeLinks'][] = 'smwfParserHook'; // parse annotations
 	$wgHooks['ParserBeforeStrip'][] = 'smwfRegisterInlineQueries'; // register the <ask> parser hook
 	$wgHooks['ArticleSave'][] = 'smwfPreSaveHook'; // check some settings here
diff --git a/includes/SMW_Hooks.php b/includes/SMW_Hooks.php
index 5f2f16d..ced2233 100644
--- a/includes/SMW_Hooks.php
+++ b/includes/SMW_Hooks.php
@@ -94,6 +94,32 @@ function smwfParsePropertiesCallback($semanticLink) {
 		$dv = SMWFactbox::addProperty($singleprop,$value,$valueCaption, $smwgStoreAnnotations && $smwgTempStoreAnnotations);
 	}
 	$result = $dv->getShortWikitext(true);
+	
+	// This is rather non-OO; maybe we should add one or more methods
+	// to the DataValue interface that lets us know what to do.
+	global $rdfaLinks, $rdfaFragmentUUID;
+	if( $dv->getTypeID() == '_wpg' ) {
+		// Add link UUID to fragment.
+		preg_match( '/\[\[([^|\]]+)\|([^\]]*)\]\]/', $result, $matches );
+		list( $foo, $url, $label ) = $matches;
+		if( strpos($url, '#') === false ) $url .= '#';
+		$result = "[[{$url}{$rdfaFragmentUUID}|{$label}]]";
+		$rdfaLinks[] = array($properties, $value);
+	}
+	else if ( $dv->getTypeID() == '_uri' ) {
+		// Doesn't always return a link, but all links will have a caption.
+		$is_link = preg_match( '/\[([^ ]+) ([^\]]+)\]/', $result, $matches );
+		if( $is_link ) {
+			list( $foo, $url, $label ) = $matches;
+			if( strpos($url, '#') === false ) $url .= '#';
+			$result = "[{$url}{$rdfaFragmentUUID} {$label}]";
+			$rdfaLinks[] = array($properties, $value);
+		}
+	}
+	else { 
+		$result = '<span property="'. rdfaAttributeStringForProperties($properties) .'">'.$result.'</span>';
+	}
+	
 	if ( ($smwgInlineErrors && $smwgStoreAnnotations && $smwgTempStoreAnnotations) && (!$dv->isValid()) ) {
 		$result .= $dv->getErrorText();
 	}
diff --git a/includes/SMW_RDFa.php b/includes/SMW_RDFa.php
new file mode 100644
index 0000000..30f6405
--- /dev/null
+++ b/includes/SMW_RDFa.php
@@ -0,0 +1,59 @@
+<?php
+if (!defined('MEDIAWIKI')) die();
+
+//$wgExtensionFunctions[] = 'rdfaSetup';
+
+function rdfaSetup() {
+	global $wgExtensionCredits, $wgHooks, $wgParser;
+	global $smwgNamespace, $wgXhtmlNamespaces, $wgServer, $wgArticlePath;
+	global $rdfaLinks, $rdfaFragmentUUID;
+	
+	$wgExtensionCredits['parserhook'][] = array(
+		'name'=>'RDFa for Semantic MediaWiki',
+		'version'=>'0.1',
+		'author'=>"David McCabe &lt;davemccabe@gmail.com&gt;",
+		'url'=>'http://semantic-mediawiki.org',
+		'description' => 'Causes Semantic MediaWiki to publish its metadata in RDFa format.');
+		
+	# We apparently can't put the namespace part in the xmlns declaration, because
+	# RDFa translates the values into fragments if the NS doesn't end in a '/'.
+	$wgXhtmlNamespaces[$smwgNamespace] = htmlspecialchars($wgServer . str_replace('$1', '', $wgArticlePath));
+	
+	$wgHooks['LinkerLinkAttributes'][] = 'rdfaLinkAttributesHook';
+	
+	// Is this really random?
+	$rdfaFragmentUUID = md5(uniqid(rand(), true) . uniqid(rand(), true));
+	$rdfaLinks = array();
+}
+
+
+function rdfaLinkAttributesHook( &$linker, $pagetitle, $title_attr, $class, &$result ) {
+	global $rdfaFragmentUUID;
+	if( $pagetitle ) {
+		# 32 is the length of the UUID.
+		if( substr($pagetitle->getFragment(), -32) == $rdfaFragmentUUID ) {
+			$pagetitle->setFragment( substr($pagetitle->getFragment(), 0, -32) );
+			$result .= ' ' . rdfaAttributesForNextLink();			
+		}
+	}
+	return true;
+}
+
+function rdfaAttributeStringForProperties($a) {
+	global $wgLang, $smwgNamespace;
+	$ns = $wgLang->getNsText(SMW_NS_PROPERTY);
+	$result = array();
+	foreach($a as $p) {
+		$result[] = $smwgNamespace . ':' . $ns . ':' . urlencode($p);
+	}
+	return implode(" ", $result);
+}
+
+function rdfaAttributesForNextLink() {
+	global $rdfaLinks;
+	list($p, $v) = array_shift($rdfaLinks);
+	$ps = rdfaAttributeStringForProperties($p);
+	return "rel=\"$ps\" content=\"$v\" about=\"\"";
+}
+
+?>
