diff --git a/public/instance/proxy/opac-de-23/index.php b/public/instance/proxy/opac-de-23/index.php
index 5a3b93b2ba1d3277f485c5c37a602d5a0f3467c5..7258161a2aaa0dc3102c66e5d5561919c72c10a9 100644
--- a/public/instance/proxy/opac-de-23/index.php
+++ b/public/instance/proxy/opac-de-23/index.php
@@ -10,6 +10,7 @@ use HAB\Pica\Reader\PicaNormReader;
 use HAB\Pica\Writer\PicaXmlWriter;
 
 define('PSI_TEMPLATE', 'http://opac.lbs-braunschweig.gbv.de/DB=2/PLAIN=Y/CHARSET=UTF8/PLAINTTLCHARSET=UTF8/PPN?PPN=%s');
+define('PICA_TEMPLATE', 'http://uri.hab.de/instance/proxy/opac-de-23/%s.xml');
 
 function terminate (Request $request, Response $response) {
     $response->prepare($request);
@@ -26,10 +27,27 @@ function load ($ident) {
     }
 }
 
+function transform ($sourceUri, $templateUri) {
+    $source = new DOMDocument();
+    if (@$source->load($sourceUri) === false) {
+        return false;
+    }
+    $xslt = new DOMDocument();
+    if (@$xslt->load($templateUri, LIBXML_NOENT) === false ) {
+        return false;
+    }
+    $proc = new XSLTProcessor();
+    if (@$proc->importStylesheet($xslt) === false) {
+        return false;
+    }
+    $result = $proc->transformToDoc($source);
+    return $result->saveXml($result->documentElement);
+}
+
 $request = Request::createFromGlobals();
 
 $route = basename($request->server->get('REQUEST_URI'));
-if (!preg_match('@^[0-9]{8}[0-9X]\.xml@', $route)) {
+if (!preg_match('@^[0-9]{8}[0-9X]\.[a-z]+@', $route)) {
     $response = new Response('<h1>400 Bad Request</h1>', 400, array('Content-Type' => 'text/html'));
     terminate($request, $response);
 }
@@ -49,6 +67,18 @@ switch ($format) {
         $content = $writer->write($record);
         $response = new Response($content, 200, array('Content-Type' => 'application/xml'));
         break;
+    case 'rdf':
+        $type = (string)$record->getFirstMatchingField('002@/00')->getNthSubfield(0, '0');
+        if ($type[0] === 'T') {
+            $sourceUri = sprintf(PICA_TEMPLATE, $ident);
+            $templateUri = __DIR__ . '/../../../../src/xslt/pica2skos.xsl';
+            $content = transform($sourceUri, $templateUri);
+            if ($content) {
+                $response = new Response($content, 200, array('Content-Type' => 'application/rdf+xml'));
+                break;
+            }
+        }
+        // Fall through
     default:
         $response = new Response('<h1>406 Not Acceptable</h1>', 406, array('Content-Type' => 'text/html'));
 }
diff --git a/src/xslt/pica2skos.xsl b/src/xslt/pica2skos.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..ffbe009720ff82079ae9b3268f17b4c528ac5a2d
--- /dev/null
+++ b/src/xslt/pica2skos.xsl
@@ -0,0 +1,27 @@
+<xsl:transform version="1.0"
+               exclude-result-prefixes="rdf pica skos"
+               xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+               xmlns:pica="info:srw/schema/5/picaXML-v1.0"
+               xmlns:skos="http://www.w3.org/2004/02/skos/core#"
+               xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="xml" indent="yes"/>
+
+  <xsl:template match="pica:record">
+    <xsl:variable name="recordType" select="substring(pica:datafield[@tag = '002@']/pica:subfield[@code = '0'], 2, 1)"/>
+    <rdf:RDF>
+      <skos:Concept rdf:about="http://uri.hab.de/instance/proxy/opac-de-23/{pica:datafield[@tag = '003@']/pica:subfield[@code = '0']}">
+        <xsl:choose>
+          <xsl:when test="$recordType = 's'">
+            <skos:prefLabel>
+              <xsl:value-of select="translate(pica:datafield[@tag = '041A']/pica:subfield[@code = 'a'], '@', '')"/>
+            </skos:prefLabel>
+          </xsl:when>
+        </xsl:choose>
+      </skos:Concept>
+    </rdf:RDF>
+  </xsl:template>
+
+  <xsl:template match="text()"/>
+
+</xsl:transform>