=== modified file 'includes/common.inc' --- includes/common.inc 2009-09-05 15:05:01 +0000 +++ includes/common.inc 2009-09-05 16:11:18 +0000 @@ -243,7 +243,11 @@ function drupal_get_rdf_namespaces() { foreach (module_invoke_all('rdf_namespaces') as $prefix => $uri) { $xml_rdf_namespaces[] = 'xmlns:' . $prefix . '="' . $uri . '"'; } - return implode("\n ", $xml_rdf_namespaces); + //allow altering of this namespaces + drupal_alter('rdf_namespaces', $xml_rdf_namespaces); + + //we are returning an array of namespaces to allow themers to alter how it shows up + return $xml_rdf_namespaces; } /** @@ -3183,7 +3187,7 @@ function drupal_get_js($scope = 'header' case 'external': // Preprocessing for external JavaScript files is ignored. - $output .= '\n"; + $output .= '\n"; break; } } @@ -4287,7 +4291,7 @@ function show(&$element) { * * @see drupal_render() * @see drupal_render_cache_set() - * + * * @param $elements * A renderable array. * @return @@ -4324,7 +4328,7 @@ function drupal_render_cache_get($elemen * A renderable array. */ function drupal_render_cache_set($markup, $elements) { - // Create the cache ID for the element + // Create the cache ID for the element if (!in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) || !$cid = drupal_render_cid_create($elements)) { return FALSE; } @@ -4604,7 +4608,7 @@ function drupal_common_theme() { 'arguments' => array('region' => NULL), ), 'username' => array( - 'arguments' => array('object' => NULL), + 'arguments' => array('object' => NULL, 'link_attributes' => array()), ), 'progress_bar' => array( 'arguments' => array('percent' => NULL, 'message' => NULL), === modified file 'includes/theme.inc' --- includes/theme.inc 2009-08-31 19:50:17 +0000 +++ includes/theme.inc 2009-09-05 14:19:11 +0000 @@ -1863,11 +1863,13 @@ function theme_more_link($url, $title) { * A string containing an HTML link to the user's page if the passed object * suggests that this is a site user. Otherwise, only the username is returned. */ -function theme_username($object) { +function theme_username($object, $link_attributes = array()) { + // Insist that HTML is false when it's not passed in. + $link_attributes += array('html' => FALSE); if ($object->uid && $object->name) { - // Shorten the name when it is too long or it will break many tables. - if (drupal_strlen($object->name) > 20) { + if (!$link_attributes['html'] && drupal_strlen($object->name) > 20) { + // Shorten the name when it is too long or it will break many tables. $name = drupal_substr($object->name, 0, 15) . '...'; } else { @@ -1875,10 +1877,11 @@ function theme_username($object) { } if (user_access('access user profiles')) { - $output = l($name, 'user/' . $object->uid, array('attributes' => array('title' => t('View user profile.')))); + $link_attributes += array('attributes' => array('title' => t('View user profile.'))); + $output = l($name, 'user/' . $object->uid, $link_attributes); } else { - $output = check_plain($name); + $output = $link_attributes['html'] ? $name : check_plain($name); } } elseif ($object->name) { @@ -1887,10 +1890,11 @@ function theme_username($object) { // aggregator modules). This clause enables modules to display // the true author of the content. if (!empty($object->homepage)) { - $output = l($object->name, $object->homepage, array('attributes' => array('rel' => 'nofollow'))); + $link_attributes += array('attributes' => array('rel' => t('View nofollow profile.'))); + $output = l($object->name, $object->homepage, $link_attributes); } else { - $output = check_plain($object->name); + $output = $link_attributes['html'] ? $object->name : check_plain($object->name); } if (theme_get_setting('toggle_comment_user_verification')) { @@ -2079,10 +2083,11 @@ function template_preprocess_page(&$vari $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : ''); $variables['tabs'] = theme('menu_local_tasks'); $variables['title'] = drupal_get_title(); + // 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. - $variables['rdf_namespaces'] = drupal_get_rdf_namespaces(); + $variables['rdf_namespaces'] = implode("\n ", drupal_get_rdf_namespaces()); $variables['grddl_profile'] = 'http://ns.inria.fr/grddl/rdfa/'; if ($node = menu_get_object()) { === 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-08-17 14:25:35 +0000 @@ -0,0 +1,69 @@ + array( + 'rdftype' => array('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 + */ +function hook_rdf_mapping_alter(&$mapping) { + return array( + 'blog' => array( + 'rdftype' => array('sioc:Post','myvoc:BlogPost'), + 'title' => array('dc:title', 'myvoc: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'), + ) + ); +} + +/** + * @} 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-19 20:48:47 +0000 @@ -0,0 +1,7 @@ +; $Id$ +name = RDF +description = Supports RDF mappings. +package = Core +core = 7.x +files[] = rdf.module +files[] = rdf.test === added file 'modules/rdf/rdf.module' --- modules/rdf/rdf.module 1970-01-01 00:00:00 +0000 +++ modules/rdf/rdf.module 2009-09-05 15:46:45 +0000 @@ -0,0 +1,267 @@ + 'foaf:Document', + 'title' => array( + 'property' => array('dc:title'), + ) + ); + $stored_mapping = &drupal_static(__FUNCTION__, $default_mapping); + + if (isset($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 to render. + * + * @param $mapping + * An array containing a mandatory property and optional datatype and + * callback. + * Example: + * array( + * 'property' => array('dc:created'), + * 'datatype' => 'xsd:dateTime', + * 'callback' => 'date_iso8601', + * ) + * @param $data + * A value that needs to be converted by the provided callback function. + * @return array + * An array containing RDFa attributes ready for rendering. + */ +function drupal_rdfa_attributes($mapping, $data = NULL) { + $attributes['property'] = $mapping['property']; + + if (isset($mapping['callback']) && isset($data)) { + $callback = $mapping['callback']; + + if (function_exists($callback)) { + $attributes['content'] = call_user_func($callback, $data); + } + if (isset($mapping['datatype'])) { + $attributes['datatype'] = $mapping['datatype']; + } + } + + return $attributes; +} + +/** + * Implementation of hook_node_load(). + */ +function rdf_node_load($nodes, $types) { + foreach ($nodes as $node) { + $node->rdf_mapping = rdf_get_mapping($node->type); + + // The node_load function does not reuse user_load(), so we need to regenerate + // the URI of the author of the node. + $node->rdf['user'] = array('uri' => _rdf_generate_user_uri($node->uid)); + } +} + +/** + * Implement hook_user_load(). + */ +function rdf_user_load($users) { + // Generate an RDF resource URI for each user account. + foreach ($users as $user) { + $user->rdf = array('uri' => _rdf_generate_user_uri($user->uid)); + } +} + +/** + * Implements hook_comment_view(). + * + * @param $comment + * A comment object. + */ +function rdf_comment_view($comment){ + $comment->rdf_mapping = rdf_get_mapping('comment'); +} + +/** + * Helper function to create a URI for the user object. + * + * @param $uid + * The user id the URI should be generated from. + * @return + * A URI including the base path of the site, e.g. '/subdomain/user/1#user'. + */ +function _rdf_generate_user_uri($uid) { + return base_path() . 'user/' . $uid . '#user'; +} + +/** + * Returns an ISO8601 formatted date based on the given date. + * + * Can be used as a callback for mappings. + * + * @param $date + * A date in a format parseable by strtotime. + * @return string + * An ISO8601 formatted date. + */ +function date_iso8601($date) { + return date(DATE_ISO8601, strtotime($date)); +} + +/** + * Implement MODULE_preprocess_HOOK(). + */ +function rdf_preprocess_node(&$variables) { + // The about and typeof attributes are required when a node is displayed in teaser mode. + if (!$variables['page']) { + $variables['attributes_array']['about'] = $variables['node_uri']; + $variables['attributes_array']['typeof'] = implode(' ', $variables['node']->rdf_mapping['rdftype']); + } + + // The title is only displayed on teaser mode. + $variables['title_raw'] = $variables['title']; + $variables['title'] = !$variables['page'] ? ' implode($variables['node']->rdf_mapping['title']))) . '>' . $variables['title_raw'] . '' : ''; +} + +/** + * Implements MODULE_preprocess_HOOK(). + */ +function rdf_preprocess_page(&$variables) { + // The variable rdfa_page_about contains the HTML attributes which define + // what resource a page is about and optionally its RDF type. + $variables['rdfa_page_about'] = ''; + // The variable rdfa_page_title contains the HTML attributes which define + // which property should be used for the title of a page. + $variables['rdfa_page_title'] = ''; + + // Contruct the RDFa markup. + $rdf_page_mapping = drupal_get_rdf_page_mapping(); + if (!empty($rdf_page_mapping['rdftype'])) { + $variables['rdfa_page_about'] = ' 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'] = ' about="#this"'; + } + if (!empty($rdf_page_mapping['title'])) { + $variables['rdfa_page_title_attributes'] = ' property="' . implode(' ', $rdf_page_mapping['title']['property']) . '"'; + } +} + +/** + * Adds RDFa attributes to the template variables. + * + * @param $variables + */ +function rdf_preprocess_field(&$variables) { + $instance = $variables['instance']; + $value = $variables['items'][0]['#item']['value']; + + if (isset($instance['rdf_mapping'])) { + $variables['#attributes'] = drupal_rdfa_attributes($instance['rdf_mapping'], $value); + } +} + +/** + * Implements MODULE_preprocess_HOOK(). + */ +function rdf_preprocess_username(&$variables) { + $object = $variables['object'] = clone($variables['object']); + + if (!empty($object->rdf_mapping['name'])) { + $object->name = '' . check_plain($object->name) . ''; + $variables['link_attributes']['html'] = TRUE; + } + + if (user_access('access user profiles') && !empty($object->rdf_mapping['uid']) && !empty($object->rdf['user']['uri'])) { + $variables['link_attributes']['attributes']['about'] = $object->rdf['user']['uri']; + } +} + +/** + * Implements MODULE_postprocess_HOOK(). + */ +function rdf_postprocess_username(&$output, $hook, $variables) { + $object = $variables['object']; + if (user_access('access user profiles') && !empty($object->rdf_mapping['uid']) && !empty($object->rdf['user']['uri'])) { + $output = ''. $output .''; + } +} + +/** + * @todo + * all this can and should be cut if issue #553038 patch lands. + */ +function rdf_theme_registry_alter(&$theme_registry) { + if ($theme_registry['username']['function'] == 'theme_username') { + $theme_registry['username']['function'] = 'rdf_theme_username'; + unset($theme_registry['username']['postprocess functions']); + } +} + +function rdf_theme_username($object, $link_attributes) { + $output = theme_username($object, $link_attributes); + if (user_access('access user profiles') && !empty($object->rdf_mapping['uid']) && !empty($object->rdf['user']['uri'])) { + $output = ''. $output .''; + } + return $output; +} === added file 'modules/rdf/rdf.test' --- modules/rdf/rdf.test 1970-01-01 00:00:00 +0000 +++ modules/rdf/rdf.test 2009-09-05 16:29:30 +0000 @@ -0,0 +1,218 @@ + t('RDF mappings'), + 'description' => t('Test RDF mapping hooks.'), + 'group' => t('RDF'), + ); + } + + function setUp() { + // Enable RDF and RDF test in the test environment. + 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('property' => array('dc:title')), t('Mapping for title is dc:title.')); + $this->assertIdentical($mapping['created'], array('property' => array('dc:created')), t('Mapping for created is dc:created.')); + $this->assertTrue(in_array('sioc:has-creator', $mapping['uid']['property']), t('Mapping for uid contains sioc:has-creator')); + $this->assertTrue(in_array('dc:creator', $mapping['uid']['property']), 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']['property']), t('Mapping for title contains dc:title')); + $this->assertTrue(in_array('sioc:title', $mapping['title']['property']), t('Mapping for title contains sioc:title')); + $this->assertTrue(in_array('sioc:has-creator', $mapping['uid']['property']), t('Mapping for uid contains sioc:has-creator')); + $this->assertTrue(in_array('foo:bar', $mapping['uid']['property']), t('Mapping for uid contains foo:bar')); + $this->assertFalse(in_array('dc:creator', $mapping['uid']['property']), t('Mapping for uid does not contain dc:creator')); + $this->assertTrue(in_array('foaf:name', $mapping['name']['property']), t('Mapping for name contains foaf:name')); + $this->assertFalse(in_array('dc:creator', $mapping['name']['property']), 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' => array('property' => array('dc:title')), 'rdftype' => 'foaf:Document'), t('Default mapping is set correctly.')); + + // If we manually set a mapping, that should replace the default. + drupal_set_rdf_page_mapping(array('foobar' => array('property' => array('foo:bar')))); + $this->assertEqual(drupal_get_rdf_page_mapping(), array('foobar' => array('property' => array('foo:bar'))), t('Custom mapping overrides default mapping.')); + } +} + +/** + * RDFa markup generation tests. + */ +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() { + // Enable RDF and RDF test in the test environment. + parent::setUp('rdf', 'rdf_test'); + } + + /** + * Test drupal_rdfa_attributes(). + */ + function testDrupalRdfaAtributes() { + $date = '2009-05-14'; + $isoDate = date(DATE_ISO8601, strtotime($date)); + + $expected_type = 'xsd:dateTime'; + $expected_property = array('dc:created'); + $expected_value = $isoDate; + $mapping = rdf_get_mapping('rdf_complex_test'); + $attributes = drupal_rdfa_attributes($mapping['date'], $date); + + $this->assertEqual($expected_type, $attributes['datatype']); + $this->assertEqual($expected_property, $attributes['property']); + $this->assertEqual($expected_value, $attributes['content']); + + $expected_property = array('dc:title'); + $mapping = rdf_get_mapping('rdf_test_container'); + $attributes = drupal_rdfa_attributes($mapping['title']); + + $this->assertEqual($expected_property, $attributes['property']); + } + +} + +class RdfaFieldTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => t('RDFa field markup'), + 'description' => t('Test RDFa markup in fields.'), + 'group' => t('RDF'), + ); + } + + function setUp() { + parent::setUp('field_test', 'rdf'); + + $this->field_name = drupal_strtolower($this->randomName() . '_field_name'); + $this->field = array('field_name' => $this->field_name, 'type' => 'test_field', 'cardinality' => 4); + $this->field = field_create_field($this->field); + $this->field_id = $this->field['id']; + $this->instance = array( + 'field_name' => $this->field_name, + 'bundle' => 'test_bundle', + 'label' => $this->randomName() . '_label', + 'description' => $this->randomName() . '_description', + 'weight' => mt_rand(0, 127), + 'settings' => array( + 'test_instance_setting' => $this->randomName(), + ), + 'widget' => array( + 'type' => 'test_field_widget', + 'label' => 'Test Field', + 'settings' => array( + 'test_widget_setting' => $this->randomName(), + ) + ), + 'rdf_mapping' => array( + 'property' => array('dc:created'), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ) + ); + field_create_instance($this->instance); + } + + function testAttributesInMarkup() { + $entity_type = 'test_entity'; + $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']); + $langcode = FIELD_LANGUAGE_NONE; + + // Populate values to be displayed. + $date = '2009-09-05'; + $values = array(0 => array('value' => $date)); + $entity->{$this->field_name}[$langcode] = $values; + + // Simple formatter, label displayed. + $formatter_setting = $this->randomName(); + $this->field['display'] = array( + 'full' => array( + 'label' => 'above', + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $formatter_setting, + ) + ), + ); + + field_update_instance($this->instance); + $this->content = drupal_render(field_attach_view($entity_type, $entity)); + $this->assertPattern('/property="dc:created"/'); + $this->assertPattern('/datatype="xsd:dateTime"/'); + $date_iso8601 = preg_quote(date(DATE_ISO8601, strtotime($date))); + $this->assertPattern("/content=\"$date_iso8601\"/"); + } + +} + +/** + * Test the generation of the user RDF URI. + */ +class RdfUserLoadUnitTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'User RDF URI generation', + 'description' => 'Test the loading of a user and a node and make sure the user RDF URI is added to the respective object.', + 'group' => 'RDF', + ); + } + + function setUp() { + // Enable RDF in the test environment. + parent::setUp('rdf'); + $web_user = $this->drupalCreateUser(array('create article content')); + $this->drupalLogin($web_user); + } + + /** + * Create a user and ensure it has an RDF URI. + */ + function testUserLoad() { + // Create a user. + $account = $this->drupalCreateUser(array()); + // Load real user object. + $account = user_load($account->uid, TRUE); + $this->assertIdentical($account->rdf, array('uri' => base_path() . 'user/' . $account->uid . '#user'), t('The user RDF URI is present in the user object.')); + } + + /** + * Create a node and ensure it has an RDF URI for the author of the node. + */ + function testNodeLoad() { + $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1)); + $node = node_load($node->nid); + $this->assertIdentical($node->rdf['user'], array('uri' => base_path() . 'user/' . $node->uid . '#user'), t('The user RDF URI is present in the node object.')); + } +} === 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 13:42:35 +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-09-01 14:21:06 +0000 @@ -0,0 +1,99 @@ + array( + 'rdftype' => array('sioc:Post'), + 'title' => array( + 'property' => array( + 'dc:title' + ), + ), + 'created' => array('property' => array('dc:created')), + 'uid' => array( + 'property' => array( + 'sioc:has-creator', + 'dc:creator', + ), + ), + 'foobar' => array( + 'property' => array( + 'foo:bar' + ), + ), + ), + 'rdf_test_another' => array( + 'rdftype' => array('sioc:User'), + 'title' => array( + 'property' => array('dc:title'), + ), + 'name' => array( + 'property' => array('dc:creator'), + ), + 'uid' => array( + 'property' => array( + 'sioc:has-creator', + 'dc:creator', + ), + ), + 'foobar' => array( + 'property' => array('foo:bar'), + ), + ), + 'rdf_complex_test' => array( + 'date' => array( + 'property' => array('dc:created'), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + ) + ); +} + +/** + * 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']['property'][] = 'foaf:name'; + + // Add a multi-value mapping without overwriting anything. + $mapping_addition = array( + 'rdf_test_another' => array( + 'title' => array( + 'property' => array('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']['property'] = array_diff($mapping['rdf_test_another']['uid']['property'], array('dc:creator')); + $mapping['rdf_test_another']['uid']['property'][] = 'foo:bar'; + } + + // Delete a specific property. + $mapping['rdf_test_another']['name']['property'] = array_diff($mapping['rdf_test_another']['name']['property'], 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'); +} === modified file 'modules/system/page.tpl.php' --- modules/system/page.tpl.php 2009-08-31 19:50:17 +0000 +++ modules/system/page.tpl.php 2009-09-01 11:53:14 +0000 @@ -168,9 +168,9 @@
-
+
>
-

+

>

=== modified file 'modules/system/system.module' --- modules/system/system.module 2009-09-05 15:05:01 +0000 +++ modules/system/system.module 2009-09-05 16:11:19 +0000 @@ -257,7 +257,9 @@ function system_rdf_namespaces() { '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', ); }