First pass: RDFa Lite expression of schema.org microdata
authorDan Scott <dscott@laurentian.ca>
Wed, 5 Dec 2012 06:34:07 +0000 (01:34 -0500)
committerDan Scott <dscott@laurentian.ca>
Sun, 7 Apr 2013 23:56:02 +0000 (19:56 -0400)
A strictly naive mapping of the existing schema.org microdata into RDFa
Lite.

Signed-off-by: Dan Scott <dscott@laurentian.ca>
Open-ILS/src/templates_rdfa/opac/parts/record/authors.tt2 [new file with mode: 0644]
Open-ILS/src/templates_rdfa/opac/parts/record/body.tt2 [new file with mode: 0644]
Open-ILS/src/templates_rdfa/opac/parts/record/contents.tt2 [new file with mode: 0644]
Open-ILS/src/templates_rdfa/opac/parts/record/subjects.tt2 [new file with mode: 0644]
Open-ILS/src/templates_rdfa/opac/parts/record/summary.tt2 [new file with mode: 0644]

diff --git a/Open-ILS/src/templates_rdfa/opac/parts/record/authors.tt2 b/Open-ILS/src/templates_rdfa/opac/parts/record/authors.tt2
new file mode 100644 (file)
index 0000000..5969588
--- /dev/null
@@ -0,0 +1,72 @@
+[%-  
+
+PROCESS "opac/parts/relators.tt2";
+
+authors = [
+    {
+        type => 'author', 
+        label => l('Author'),
+        xpath => '//*[@tag="100"]|//*[@tag="110"]|//*[@tag="111"]'
+    }, {
+        type => 'added', 
+        label => l('Added Author'),
+        xpath => '//*[@tag="700"]|//*[@tag="710"]|//*[@tag="711"]'
+    }, {
+        type => 'cast', 
+        label => l('Cast'),
+        xpath => '//*[@tag="508"]'
+    }, {
+        type => 'notes', 
+        label => l('Author Notes: '),
+        xpath => '' # Comes from added content...
+    }
+];
+
+BLOCK build_author_links;
+    FOR node IN ctx.marc_xml.findnodes(xpath);
+        term = '';
+        qterm = '';
+        iprop = '';
+        tlabel = '';
+        FOR subfield IN node.childNodes;
+            NEXT UNLESS subfield.nodeName == "subfield";
+            code = subfield.getAttribute('code');
+            IF code == '4';
+                relcode = subfield.textContent.substr(0,3);
+                tlabel = relators.$relcode || label;
+            END;
+            NEXT UNLESS code.match('[a-z]');
+            sf = subfield.textContent | html;
+            term = term _ ' ' _ sf;
+            IF code.match('[acdq]');
+                sf_raw = subfield.textContent.replace('[#"^$\+\-,\.:;&|\[\]()]', ' ');
+                qterm = qterm _ ' ' _ sf_raw;
+            END;
+        END;
+        url = mkurl(ctx.opac_root _ '/results', {query => qterm, qtype => 'author'}, ['page', 'expand']);
+        author_type = (tlabel || label) | html;
+        
+        # schema.org changes
+        IF type == 'author';
+            iprop = ' property="accountablePerson"';
+        ELSIF type == 'added';
+            iprop = ' property="contributor"';
+        END;
+        '<a href="' _ url _ '"' _ iprop _ '>' _ term.replace('^\s+', '') _ '</a> (' _ author_type _ '). ';
+    END;
+END;
+%]
+
+<div class='rdetail_authors_div'>
+[%- FOREACH author IN authors;
+    NEXT UNLESS author.xpath; 
+    links = PROCESS build_author_links(
+        xpath=author.xpath, label=author.label, type=author.type
+    );
+    IF links.match('\S') %]
+    <span class='rdetail-author-div'>[% links %]</span>
+    [%- END %]
+[%- END %]
+</div>
+
+
diff --git a/Open-ILS/src/templates_rdfa/opac/parts/record/body.tt2 b/Open-ILS/src/templates_rdfa/opac/parts/record/body.tt2
new file mode 100644 (file)
index 0000000..5bf95a4
--- /dev/null
@@ -0,0 +1,16 @@
+[%-  attrs = {marc_xml => ctx.marc_xml};
+    PROCESS "opac/parts/misc_util.tt2";
+    PROCESS get_marc_attrs args=attrs;
+    stop_parms = ['expand','cnoffset'];
+    ctx.record_attrs = attrs; # capture for JS
+%]
+<div id='canvas_main' class='canvas' vocab='http://schema.org/' typeof='[% args.schema.itemtype %]'>
+    [%- INCLUDE "opac/parts/record/navigation.tt2" %]
+    [%- IF ctx.bib_is_dead %]
+    <div id='rdetail_deleted_exp'>
+        [% l("This record has been deleted from the database.  We recommend that you remove this title from any bookbags it may have been added to.") %]
+    </div>
+    [%- END %]
+    [% INCLUDE "opac/parts/record/summary.tt2" %]
+    [%- INCLUDE "opac/parts/record/navigation.tt2" %]
+</div>
diff --git a/Open-ILS/src/templates_rdfa/opac/parts/record/contents.tt2 b/Open-ILS/src/templates_rdfa/opac/parts/record/contents.tt2
new file mode 100644 (file)
index 0000000..ff96d73
--- /dev/null
@@ -0,0 +1,194 @@
+[%-
+contents =  [
+    {
+        label => l('General Note: '),
+        xpath => '//*[@tag="500"]'
+    }, {
+        label => l('With Note: '),
+        xpath => '//*[@tag="501"]'
+    }, {
+        label => l('Dissertation Note: '),
+        xpath => '//*[@tag="502"]'
+    }, {
+        label => l('Bibliography, etc. Note: '),
+        xpath => '//*[@tag="504"]'
+    }, {
+        label => l('Formatted Contents Note: '),
+        xpath => '//*[@tag="505"]'
+    }, {
+        label => l('Restrictions on Access Note: '),
+        xpath => '//*[@tag="506"]'
+    }, {
+        label => l('Scale Note for Graphic Material: '),
+        xpath => '//*[@tag="507"]'
+    }, {
+        label => l('Creation/Production Credits Note: '),
+        xpath => '//*[@tag="508"]'
+    }, {
+        label => l('Citation/References Note: '),
+        xpath => '//*[@tag="510"]'
+    }, {
+        label => l('Participant or Performer Note: '),
+        xpath => '//*[@tag="511"]'
+    }, {
+        label => l('Type of Report and Period Covered Note: '),
+        xpath => '//*[@tag="513"]'
+    }, {
+        label => l('Data Quality Note: '),
+        xpath => '//*[@tag="514"]'
+    }, {
+        label => l('Numbering Peculiarities Note: '),
+        xpath => '//*[@tag="515"]'
+    }, {
+        label => l('Type of Computer File or Data Note: '),
+        xpath => '//*[@tag="516"]'
+    }, {
+        label => l('Date/Time and Place of an Event Note: '),
+        xpath => '//*[@tag="518"]'
+    }, {
+        label => l('Summary, etc.: '),
+        xpath => '//*[@tag="520"]'
+    }, {
+        label => l('Target Audience Note: '),
+        xpath => '//*[@tag="521"]'
+    }, {
+        label => l('Geographic Coverage Note: '),
+        xpath => '//*[@tag="522"]'
+    }, {
+        label => l('Preferred Citation of Described Materials Note: '),
+        xpath => '//*[@tag="524"]'
+    }, {
+        label => l('Supplement Note: '),
+        xpath => '//*[@tag="525"]'
+    }, {
+        label => l('Study Program Information Note: '),
+        xpath => '//*[@tag="526"]'
+    }, {
+        label => l('Additional Physical Form available Note: '),
+        xpath => '//*[@tag="530"]'
+    }, {
+        label => l('Reproduction Note: '),
+        xpath => '//*[@tag="533"]'
+    }, {
+        label => l('Original Version Note: '),
+        xpath => '//*[@tag="534"]'
+    }, {
+        label => l('Location of Originals/Duplicates Note: '),
+        xpath => '//*[@tag="535"]'
+    }, {
+        label => l('Funding Information Note: '),
+        xpath => '//*[@tag="536"]'
+    }, {
+        label => l('System Details Note: '),
+        xpath => '//*[@tag="538"]'
+    }, {
+        label => l('Terms Governing Use and Reproduction Note: '),
+        xpath => '//*[@tag="540"]'
+    }, {
+        label => l('Immediate Source of Acquisition Note: '),
+        xpath => '//*[@tag="541"]'
+    }, {
+        label => l('Information Relating to Copyright Status: '),
+        xpath => '//*[@tag="542"]'
+    }, {
+        label => l('Location of Other Archival Materials Note: '),
+        xpath => '//*[@tag="544"]'
+    }, {
+        label => l('Biographical or Historical Data: '),
+        xpath => '//*[@tag="545"]'
+    }, {
+        label => l('Language Note: '),
+        xpath => '//*[@tag="546"]'
+    }, {
+        label => l('Former Title Complexity Note: '),
+        xpath => '//*[@tag="547"]'
+    }, {
+        label => l('Issuing Body Note: '),
+        xpath => '//*[@tag="550"]'
+    }, {
+        label => l('Entity and Attribute Information Note: '),
+        xpath => '//*[@tag="552"]'
+    }, {
+        label => l('Cumulative Index/Finding Aids Note: '),
+        xpath => '//*[@tag="555"]'
+    }, {
+        label => l('Information About Documentation Note: '),
+        xpath => '//*[@tag="556"]'
+    }, {
+        label => l('Ownership and Custodial History: '),
+        xpath => '//*[@tag="561"]'
+    }, {
+        label => l('Copy and Version Identification Note: '),
+        xpath => '//*[@tag="562"]'
+    }, {
+        label => l('Binding Information: '),
+        xpath => '//*[@tag="563"]'
+    }, {
+        label => l('Case File Characteristics Note: '),
+        xpath => '//*[@tag="565"]'
+    }, {
+        label => l('Methodology Note: '),
+        xpath => '//*[@tag="567"]'
+    }, {
+        label => l('Linking Entry Complexity Note: '),
+        xpath => '//*[@tag="580"]'
+    }, {
+        label => l('Publications About Described Materials Note: '),
+        xpath => '//*[@tag="581"]'
+    }, {
+        label => l('Action Note: '),
+        xpath => '//*[@tag="583"]'
+    }, {
+        label => l('Accumulation and Frequency of Use Note: '),
+        xpath => '//*[@tag="584"]'
+    }, {
+        label => l('Exhibitions Note: '),
+        xpath => '//*[@tag="585"]'
+    }, {
+        label => l('Awards Note: '),
+        xpath => '//*[@tag="586"]'
+    }, {
+        label => l('Source of Description Note: '),
+        xpath => '//*[@tag="588"]'
+    } 
+];
+
+BLOCK render_contents;
+    xpath = xpath || '//*[starts-with(@tag,"5")]';
+    FOR node IN ctx.marc_xml.findnodes(xpath);
+        all_content = [];
+        FOR subfield IN node.childNodes;
+            NEXT UNLESS subfield.nodeName == "subfield";
+            code = subfield.getAttribute('code');
+            NEXT UNLESS code.match('[a-z]');
+            all_content.push(subfield.textContent);
+        END;
+        total_contents = all_content.join(" ").replace('\s+$', '');
+        %] [% total_contents;
+        IF total_contents.size; "<br/>"; END;
+    END;
+END 
+%]
+[%  BLOCK render_all_contents;
+    FOREACH cont IN contents;
+        content = PROCESS render_contents(xpath=cont.xpath);
+        IF content.match('\S');
+-%]
+<tr>
+    <td class='rdetail_content_type'>[% cont.label %]</td>
+    <td class='rdetail_content_value' property='keywords'>[% content %]</td>
+</tr>
+        [%- END; %]
+    [%- END; %]
+[%- END %]
+
+[%-  content_html = PROCESS render_all_contents;
+    IF content_html.length > 0;
+%]
+<h2 class='rdetail_contents'>[% l('Content descriptions') %]</h2>
+<table class='rdetail_content'>
+    <tbody>
+[%- content_html %]
+    </tbody>
+</table>
+[%- END %]
diff --git a/Open-ILS/src/templates_rdfa/opac/parts/record/subjects.tt2 b/Open-ILS/src/templates_rdfa/opac/parts/record/subjects.tt2
new file mode 100644 (file)
index 0000000..f070c64
--- /dev/null
@@ -0,0 +1,73 @@
+[% 
+    subjects = [
+        {
+            label => l('Subject: '),
+            xpath => '//*[@tag="600" or @tag="610" or @tag="611" or @tag="630" or @tag="650" or @tag="651"]'
+        }, {
+            label => l('Genre: '),
+            xpath => '//*[@tag="655"]|//*[@tag="659"]'
+        }, {
+            label => l('Topic Heading: '),
+            xpath => '//*[@tag="690"]'
+        }, {
+            label => l('Geographic Setting: '),
+            xpath => '//*[@tag="691"]'
+        }, {
+            label => l('Biographical Subject: '),
+            xpath => '//*[@tag="692"]'
+        }, {
+            label => l('Character Attributes: '),
+            xpath => '//*[@tag="693"]'
+        }, {
+            label => l('Setting: '),
+            xpath => '//*[@tag="698"]'
+        }, {
+            label => l('Time Period: '),
+            xpath => '//*[@tag="699"]'
+        }
+    ];
+
+    BLOCK render_subject;
+        xpath = xpath || '//*[starts-with(@tag,"6")]';
+        FOR node IN ctx.marc_xml.findnodes(xpath);
+            all_terms = [];
+            FOR subfield IN node.childNodes;
+                NEXT UNLESS subfield.nodeName == "subfield";
+                code = subfield.getAttribute('code');
+                NEXT UNLESS code.match('[a-z]');
+                IF code.match('[vxyz]'); " &gt; "; END;
+                # at this point, we actually have a partial term to use.
+                single_term = subfield.textContent | html;
+                all_terms.push(subfield.textContent.replace('[#"^$\+\-,\.:;&|\[\]()]', ''));
+                total_term = all_terms.join(" ").replace('\s+$', '');
+            %]
+<a href="[% mkurl(ctx.opac_root _ '/results', {qtype=>'subject', query=>total_term}, stop_parms); %]">[% single_term %]</a>
+            [%- END;
+            IF all_terms.size; "<br/>"; END;
+        END;
+    END 
+%]
+
+[%  BLOCK render_all_subjects;
+    FOREACH subj IN subjects;
+        content = PROCESS render_subject(xpath=subj.xpath);
+        IF content.match('\S');
+%]
+        <table class='rdetail_subject'>
+            <tbody>
+                <tr>
+                    <td class='rdetail_subject_type'>[% subj.label %]</td>
+                    <td class='rdetail_subject_value' property='keywords'>[% content %]</td>
+                </tr>
+            </tbody>
+        </table>
+        [%- END; %]
+    [%- END; %]
+[%- END %]
+
+[%-  subject_html = PROCESS render_all_subjects;
+    IF subject_html.length > 0;
+%]
+<h2 class='rdetail_related_subjects'>[% l('Search for related items by subject') %]</h2>
+[%- subject_html %]
+[%- END %]
diff --git a/Open-ILS/src/templates_rdfa/opac/parts/record/summary.tt2 b/Open-ILS/src/templates_rdfa/opac/parts/record/summary.tt2
new file mode 100644 (file)
index 0000000..0a0901d
--- /dev/null
@@ -0,0 +1,170 @@
+[%  PROCESS "opac/parts/misc_util.tt2";
+    USE ResolverResolver;
+    ctx.page_title = attrs.title | html
+%]
+<!-- ****************** rdetail_summary.xml ***************************** -->
+<abbr class="unapi-id" title='tag:[% ctx.hostname %],[% date.format(date.now, '%Y') %]:biblio-record_entry/[% ctx.bre_id %]'></abbr>
+
+<hr />
+
+[%-# This holds the record summary information %]
+<div id="rdetail_summary_header">
+    <div id="rdetail_image_div">
+        [% ident = attrs.isbn_clean || attrs.upc; IF ident; %]
+        <a href='[% ctx.media_prefix %]/opac/extras/ac/jacket/large/[% ident | uri %]'><img
+            alt="[% l('Image of item') %]" id='rdetail_image'
+            src='[% ctx.media_prefix %]/opac/extras/ac/jacket/[% record.summary.jacket_size %]/[% ident | uri %]' /></a>
+        [% END %]
+        <br />
+    </div>
+
+    <div id="rdetail_actions_div">
+        [%- search_ou = ctx.search_ou;
+            IF ctx.place_unfillable ||
+                ( attrs.marc_xml.findnodes('//*[local-name()="holdings" and @has_holdable="true"]').size > 0
+                    && (ctx.holds_block.enabled != 'true' || attrs.org_copy_counts.$search_ou.available == 0)
+                )
+         %]
+        <div class="rdetail_aux_utils place_hold">
+            <a href="[% mkurl(ctx.opac_root _ '/place_hold', 
+                {hold_target => ctx.bre_id, hold_type => 'T', hold_source_page => mkurl()}, stop_parms) %]" 
+            class="no-dec"><img src="[% ctx.media_prefix %]/images/green_check.png" alt="[% l('place hold') %]" /><span 
+            class="place_hold">[% l('Place Hold') %]</span></a>
+        </div>
+        [%- END -%]
+        <div class="rdetail_aux_utils toggle_list">
+        [%  IF ctx.user;
+            INCLUDE "opac/parts/bookbag_actions.tt2";
+        %]
+        [%  ELSE;
+            operation = ctx.mylist.grep(ctx.bre_id).size ? "delete" : "add";
+            label = (operation == "add") ? l("Add to my list") : l("Remove from my list"); 
+        %]
+            <a href="[% mkurl(ctx.opac_root _ '/mylist/' _ operation, {record => ctx.bre_id}, stop_parms) %]" class="no-dec">
+                <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
+                [% label %]
+            </a>
+        [% END %]
+        </div>
+        <div class="rdetail_aux_utils">
+            <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
+            <a href="[% mkurl(ctx.opac_root _ '/record/print/' _ ctx.bre_id) %]" class="no-dec">[% l('Print') %]</a> /
+            <a href="[% mkurl(ctx.opac_root _ '/record/email/' _ ctx.bre_id) %]" class="no-dec">[% l('Email') %]</a>
+        </div>
+        [%- IF ctx.refworks.enabled == 'true' %]
+            [%- INCLUDE 'opac/parts/record/refworks.tt2' %]
+        [%- END %]
+    </div>
+    <div id='rdetail_title_div'>
+        [%- IF attrs.format_icon %]
+        <div class="format_icon">
+            <img alt="[% attrs.format_label %]" title="[% attrs.format_label | html %]" src="[% attrs.format_icon %]" />
+        </div>
+        [%- END %]
+        <h1 id='rdetail_title' property="name">[% attrs.title_extended | html %]</h1>
+        [%- INCLUDE "opac/parts/record/authors.tt2" %]
+    </div>
+</div>
+
+[%- IF openurl.enabled == 'true';
+    openurls = [];
+    FOREACH issn IN args.issns;
+        NEXT IF issn == '';
+        openurls = openurls.import(ResolverResolver.resolve_issn(issn, openurl.baseurl));
+    END;
+    IF openurls.size && openurls.0 != '';
+%]
+    <div id='rdetail_openurl'>
+        <strong class='rdetail_openurl_title'>[% l("Electronic resources") %]</strong>
+        <table><tbody>
+[%-
+        FOREACH res IN openurls;
+%]
+        <tr>
+            <td class='rdetail_openurl_entry'><a href="[% res.target_url %]">[% res.public_name %]</a></td>
+            <td>[% res.target_coverage %]</td>
+        </tr>
+    [%- END %]
+    </tbody></table>
+[%- END %]
+    </div>    
+[%- END %]
+[%- merged_uris = args.uris.merge(args.online_res);
+num_uris = merged_uris.size;
+IF num_uris > 0;
+-%]
+<h2 class="rdetail_uris">[% l("Electronic resources") %]</h2>
+<div class="rdetail_uris">
+    [%- IF num_uris > 1 %]<ul>[% END %]
+    [%- FOR uri IN merged_uris %]
+        [%- IF num_uris == 1 %]<p class="rdetail_uri">[% ELSE %]<li class="rdetail_uri">[% END %]
+        <a href="[% uri.href %]">[% uri.link %]</a>[% ' - ' _ uri.note IF uri.note %]
+        [%- IF num_uris == 1 %]</p>[% ELSE %]</li>[% END %]
+    [%- END %]
+    [%- IF num_uris > 1 %]</ul>[% END %]
+</div>
+[%- END %]
+[%- # Hold/copy summary
+    IF ctx.copy_summary.0.count
+%]
+<div id="copy_hold_counts">
+[%- INCLUDE "opac/parts/record/copy_counts.tt2" %]
+    <span id="rdetail_hold_counts">
+        <h2>[% l('Current holds') %]</h2>
+        <p>
+            [%- l("[quant,_1,current hold,current holds] with [quant,_2,total copy,total copies].", 
+                ctx.record_hold_count, ctx.copy_summary.0.count) %]
+        </p>
+    </span>
+[%- INCLUDE "opac/parts/record/copy_table.tt2" copies=ctx.copies %]
+</div>
+[%- END %]
+
+<h2 id='rdetail_record_details'>[% l("Record details") %]</h2>
+<ul>
+    [%- IF attrs.isbns.0; FOR isbn IN attrs.isbns %]
+    <li class='rdetail_isbns'>
+        <strong class='rdetail_label'>[% l('ISBN:'); %]</strong>
+        <span class='rdetail_value' property='isbn'>[% isbn | html  %]</span>
+    </li>
+        [%- END %]
+    [%- END %]
+    [%- IF attrs.issns.0; FOR issn IN attrs.issns %]
+    <li class='rdetail_issns'>
+        <strong class='rdetail_label'>[% l('ISSN:'); %]</strong>
+        <span class='rdetail_value'>[% issn | html  %]</span>
+    </li>
+        [%- END %]
+    [%- END %]
+    [%- IF attrs.phys_desc %]
+    <li id='rdetail_phys_desc'>
+        <strong class='rdetail_label'>[% l("Physical Description:") %]</strong>
+        <span class='rdetail_value'>[% attrs.phys_desc | html %]</span>
+    </li>
+    [%- END %]
+    [%- IF attrs.edition %]
+    <li id='rdetail_edition'>
+        <strong class='rdetail_label'>[% l("Edition:") %]</strong>
+        <span class='rdetail_value'>[% attrs.edition | html %]</span>
+    </li>
+    [%- END %]
+    [%- IF attrs.publisher %]
+    <li id='rdetail_publisher'>
+        <strong class='rdetail_label'>[% l("Publisher:") %]</strong>
+        <span class='rdetail_value' property="publisher" vocab='http://schema.org/' typeof="Organization">
+        [%- IF attrs.pubplace; %]
+            <span property="location">[% attrs.pubplace | html; %]</span>
+        [%- END; %]
+            <span property="name">[% attrs.publisher | html; %]</span>
+        </span>
+        [%- IF attrs.pubdate; %]
+            <span property="datePublished">[% attrs.pubdate | html; %]</span>
+        [%- END; %]
+    </li>
+    [%- END %]
+</ul>
+
+[%- INCLUDE "opac/parts/record/contents.tt2" %]
+[%- INCLUDE "opac/parts/record/subjects.tt2" %]
+[%- INCLUDE "opac/parts/record/series.tt2" %]
+[%- INCLUDE "opac/parts/record/extras.tt2" %]