LP#1744385: Search and Result Display improvements
authorMike Rylander <mrylander@gmail.com>
Mon, 11 Sep 2017 19:24:55 +0000 (15:24 -0400)
committerDan Wells <dbw2@calvin.edu>
Wed, 28 Feb 2018 21:17:53 +0000 (16:17 -0500)
== Virtual Index Definitions

The practical purpose of Virtual Index Definitions is to supply an Evergreen administrator with
the ability to control the weighting and field inclusion of values in the general keyword index,
commonly referred to as "the blob," without requiring tricky configuration that has subtle semantics, an
over-abundance of index definitions which can slow search generally, or the need to reingest all
records on a regular basis as experiments are performed and the configuration refined. Significant
results of recasting keyword indexes as a set of one or more Virtual Index Definitions will be simpler
search configuration management, faster search speed overall, and more practical reconfiguration and
adjustment as needed.

Previous to this commit, in order to provide field-specific weighting to keyword matches against titles or authors, an
administrator must duplicate many other index definitions and supply overriding weights to those
duplicates. This not only complicates configuration, but slows down record ingest as well as search. It
is also fairly ineffective at achieving the goal of weighted keyword fields. Virtual Index Definitions will
substantially alleviate the need for these workarounds and their consequences.

  * A Virtual Index Definition is not required supply any configuration for extracting bibliographic
    data from records, but instead can become a sink for data collected by other index definitions
    which is then colocated together to supply a search target made up of the separately extracted
    data. Virtual Index Definitions are effectively treated as aggregate definitions, matching across
    all values extracted from constituent non-virtual index definitions.  They can further make use
    of the Combined class functionality to colocate all values in a class together for matching even
    across virtual fields.

  * Configuration allows for weighting of constituent index definitions that participate in a
    Virtual Index Definition. This weighting is separate from the weighting supplied when the index
    definition itself is a search target.

  * The Evergreen QueryParser driver returns the list of fields actually searched using every
    user-supplied term set, including constituent expansion when a Virtual Index Definition is
    searched. In particular, this will facilitate Search Term Highlighting described below.

  * Stock configuration changes make use of pre-existing, non-virtual index definitions mapped
    to new a Virtual Index Definition that implements the functionality provided by the
    keyword|keyword index definition. The keyword|keyword definition is left in place for the time
    being, until more data can be gathered about the real-world effect of removing it entirely and
    replacing it with Virtual Index Definition mappings.

  * New system administration functions will be created to facilitate modification of Virtual Index
    Definition mapping, avoiding the need for a full reingest when existing index definitions are
    added or removed from a virtual field.

== Increased use of Metabib Display Fields

In extention of changes proposed in other available branches, we here use Metabib Display Fields
to render catalog search results, intermediate metarecord results, and record detail pages.
This will requires the addition of several new Metabib Display Field definitions, as well as Perl
services to gather and render the data.

== Search Term Highlighting

This commit enables Search Term Highlighting in the OPAC on the main search results page, the record
detail page, and intermediate pages such as metarecord grouped results page. Highlighting
search terms will help the user determine why a particular record (or set of records) was retrieved.

Highlighting of matched terms uses the same stemming used to accomplish the search, as configured
per field and class.

This feature will help the user more quickly determine the relevance of a particular record by calling their
attention to search terms in context. Lastly, it will help familiarize the user with how records are
searched, including which fields are searched as well as exposing concepts like stemming.

== Interfaces

A new AngularJS "MARC Search/Facet Fields" interface has been created to replace the Dojo version, and
both have been extended to support Virtual Index Definition data supplier mapping and weighting.

== Settings & Permissions

The new Virtual Index Definition data supplier mapping table, config.metabib_field_virtual_map, requires
the same permissions as the MARC Search/Facet Fields interface: CREATE_METABIB_FIELD, UPDATE_METABIB_FIELD,
DELETE_METABIB_FIELD, or ADMIN_METABIB_FIELD for all actions

There is a new template-level global configuration variable in config.tt2 called search.no_highlight
which disables highlighting for users of that config.tt2 instance.

== Public Catalog

The public and staff catalog will make use of new APIs to identify and display highlight-augmented
values for those Display Fields used to render the search result pages, intermediate metarecord
constituent pages, and record detail pages.  Highlighting of terms will be performed using the
application of Template::Toolkit-driven CSS. A generic CSS class identifying a highlighted term,
along with CSS classes identifying the search class and each search field will be available for
use for customization of the highlighting. A stock CSS
template is provided as a baseline upon which sites may expand.

When highlighting is generally enabled, it may be turned on or off on a per-page basis through the use of
a UI component which will request the page again without highlighting.

== Backend

There now exist several new database tables and functions primarily in support of search highlighting.
Additionally, the QueryParser driver for Evergreen has been augmented to be able to return a data structure
describing how the search was performed, in a way that allows a separate support API to gather a highlighted
version of the Display Field data for a given record.

== Re-ingest or Indexing Dependencies

With the addition and modification of many Index Definitions, a full reingest is recommended.  However, search
will continue to work as it did before the changes in this commit for those records that have not yet been
reingested during that process.  Therefore a slow, rolling reingest is recommended.

== Performance Implications or Concerns

Because the Metabib Display Fields infrastructure will eventually replace functionality that is significantly more
CPU-intensive in the various forms of XML parsing, XSLT transformation, XPath calculation, and
Metabib Virtual Record construction, it is expected that the overall CPU load will be reduced by this
development, and ideally the overall time required to perform and render a search will likewise drop. It
is unlikely that the speed increase will be visible to users on a per-search basis, but that search in
aggregate will become a smaller consumer of resources.

Signed-off-by: Mike Rylander <mrylander@gmail.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Dan Wells <dbw2@calvin.edu>
31 files changed:
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
Open-ILS/src/sql/Pg/002.schema.config.sql
Open-ILS/src/sql/Pg/030.schema.metabib.sql
Open-ILS/src/sql/Pg/300.schema.staged_search.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql [new file with mode: 0644]
Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql [new file with mode: 0644]
Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql [new file with mode: 0644]
Open-ILS/src/support-scripts/test-scripts/query_parser.pl
Open-ILS/src/templates/conify/global/config/metabib_field.tt2
Open-ILS/src/templates/conify/global/config/metabib_field_virtual_map.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/css/style.css.tt2
Open-ILS/src/templates/opac/parts/misc_util.tt2
Open-ILS/src/templates/opac/parts/record/authors.tt2
Open-ILS/src/templates/opac/parts/record/contents.tt2
Open-ILS/src/templates/opac/parts/record/subjects.tt2
Open-ILS/src/templates/opac/parts/record/summary.tt2
Open-ILS/src/templates/opac/parts/result/table.tt2
Open-ILS/src/templates/staff/admin/server/config/metabib_field.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/admin/server/config/metabib_field_virtual_map.tt2 [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field_virtual_map.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js
Open-ILS/web/js/ui/default/staff/services/grid.js

index a84b556..ae53496 100644 (file)
@@ -2761,7 +2761,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        </actions>
                </permacrud>
        </class>
-       <class id="cxt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::xml_transform" oils_persist:tablename="config.xml_transform" reporter:label="XML/XSLT Transform Definition">
+       <class id="cxt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::xml_transform" oils_persist:tablename="config.xml_transform" reporter:label="XML/XSLT Transform Definition" oils_persist:field_safe="true">
                <fields oils_persist:primary="name">
                        <field reporter:label="Name" name="name" reporter:datatype="text" />
                        <field reporter:label="Namespace URI" name="namespace_uri" reporter:datatype="text"/>
@@ -2801,7 +2801,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
        <class id="cmc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_class" oils_persist:tablename="config.metabib_class" reporter:label="Metabib Class" oils_persist:field_safe="true">
                <fields oils_persist:primary="name">
-                       <field reporter:label="Name" name="name" reporter:datatype="text"/>
+                       <field reporter:label="Name" name="name" reporter:datatype="text" reporter:selector="label"/>
                        <field reporter:label="Label" name="label" reporter:datatype="text" oils_persist:i18n="true"/>
                        <field reporter:label="Buoyant?" name="buoyant" reporter:datatype="bool" />
                        <field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
@@ -2827,26 +2827,32 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
        <class id="cmf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field" oils_persist:tablename="config.metabib_field" reporter:label="Metabib Field" oils_persist:field_safe="true">
                <fields oils_persist:primary="id" oils_persist:sequence="config.metabib_field_id_seq">
-                       <field reporter:label="Class" name="field_class" reporter:datatype="link"/>
                        <field reporter:label="ID" name="id" reporter:datatype="id" reporter:selector="label"/>
-                       <field reporter:label="Name" name="name" reporter:datatype="text"/>
+                       <field reporter:label="Class" name="field_class" reporter:datatype="link"/>
                        <field reporter:label="Label" name="label" reporter:datatype="text" oils_persist:i18n="true"/>
-                       <field reporter:label="XPath" name="xpath" reporter:datatype="text"/>
+                       <field reporter:label="Name" name="name" reporter:datatype="text"/>
                        <field reporter:label="Weight" name="weight" reporter:datatype="int" />
+                       <field reporter:label="XPath" name="xpath" reporter:datatype="text"/>
+                       <field reporter:label="Joiner" name="joiner" reporter:datatype="text"/>
                        <field reporter:label="Format" name="format" reporter:datatype="link"/>
                        <field reporter:label="Search Field" name="search_field" reporter:datatype="bool" />
                        <field reporter:label="Facet Field" name="facet_field" reporter:datatype="bool" />
                        <field reporter:label="Facet XPath" name="facet_xpath" reporter:datatype="text" />
+                       <field reporter:label="Display Field?" name="display_field" reporter:datatype="bool" />
                        <field reporter:label="Display XPath" name="display_xpath" reporter:datatype="text" />
                        <field reporter:label="Browse Field" name="browse_field" reporter:datatype="bool" />
                        <field reporter:label="Browse XPath" name="browse_xpath" reporter:datatype="text" />
+                       <field reporter:label="Browse Sort XPath" name="browse_sort_xpath" reporter:datatype="text" />
+                       <field reporter:label="Authority XPath" name="authority_xpath" reporter:datatype="text" />
                        <field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
-                       <field reporter:label="Display Field?" name="display_field" reporter:datatype="bool" />
                        <field reporter:label="Display Field Map" name="display_field_map" oils_persist:virtual="true" reporter:datatype="link"/>
+                       <field reporter:label="Virtual Field Data Suppliers" name="data_sources" oils_persist:virtual="true" reporter:datatype="link"/>
                </fields>
                <links>
+                       <link field="format" reltype="has_a" key="name" map="" class="cxt"/>
                        <link field="field_class" reltype="has_a" key="name" map="" class="cmc"/>
                        <link field="display_field_map" reltype="might_have" key="field" map="" class="cdfm"/>
+                       <link field="data_sources" reltype="has_many" key="virtual" map="" class="cmfvm"/>
                </links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
@@ -2857,6 +2863,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
+
+       <class id="cmfvm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field_virtual_map" oils_persist:tablename="config.metabib_field_virtual_map" reporter:label="Metabib Field Virtual Map" oils_persist:field_safe="true">
+               <fields oils_persist:primary="id" oils_persist:sequence="config.metabib_field_virtual_map_id_seq">
+                       <field reporter:label="ID" name="id" reporter:datatype="id"/>
+                       <field reporter:label="Real" name="real" reporter:datatype="link"/>
+                       <field reporter:label="Virtual" name="virtual" reporter:datatype="link"/>
+                       <field reporter:label="Weight" name="weight" reporter:datatype="int"/>
+               </fields>
+               <links>
+                       <link field="real" reltype="has_a" key="id" map="" class="cmf"/>
+                       <link field="virtual" reltype="has_a" key="id" map="" class="cmf"/>
+               </links>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <create permission="CREATE_METABIB_FIELD ADMIN_METABIB_FIELD" global_required="true"/>
+                <retrieve/>
+                <update permission="UPDATE_METABIB_FIELD ADMIN_METABIB_FIELD" global_required="true"/>
+                <delete permission="DELETE_METABIB_FIELD ADMIN_METABIB_FIELD" global_required="true"/>
+            </actions>
+        </permacrud>
+       </class>
+
        <class id="cbho" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::best_hold_order" oils_persist:tablename="config.best_hold_order" reporter:label="Best-Hold Sort Order">
                <fields oils_persist:primary="id" oils_persist:sequence="config.best_hold_order_id_seq">
                        <field reporter:label="ID" name="id" reporter:datatype="id" reporter:selector="name" />
@@ -3736,6 +3764,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field name="field" reporter:datatype="link"/>
                        <field name="source" reporter:datatype="link"/>
                        <field name="value"  reporter:datatype="text"/>
+                       <field name="highlight" oils_persist:virtual="true"  reporter:datatype="text"/>
                </fields>
                <links>
                        <link field="source" reltype="has_a" key="id" map="" class="bre"/>
@@ -3839,8 +3868,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                oils_persist:tablename="config.display_field_map"
                oils_obj:fieldmapper="config::display_field_map"
                oils_persist:field_safe="true"
-               reporter:label="Display Field Map" 
-               oils_persist:readonly="true">
+               reporter:label="Display Field Map">
                <fields oils_persist:primary="name">
                        <field name="name" reporter:datatype="text"/>
                        <field name="field" reporter:datatype="link"/>
index 06ec97d..96ce5da 100644 (file)
@@ -1306,6 +1306,30 @@ sub staged_search {
     return cache_facets($facet_key, $new_ids, $IAmMetabib, $ignore_facet_classes) if $docache;
 }
 
+sub passthrough_fetch_display_fields {
+    my $self = shift;
+    my $conn = shift;
+    my $highlight_map = shift;
+    my @records = @_;
+
+    return $U->storagereq(
+        'open-ils.storage.fetch.metabib.display_field.highlight',
+        $highlight_map,
+        @records
+    ) if (@records == 1);
+
+    return $U->storagereq(
+        'open-ils.storage.fetch.metabib.display_field.highlight.atomic',
+        $highlight_map,
+        \@records
+    );
+}
+__PACKAGE__->register_method(
+    method    => 'passthrough_fetch_display_fields',
+    api_name  => 'open-ils.search.fetch.metabib.display_field.highlight'
+);
+
+
 sub tag_circulated_records {
     my ($auth, $results, $metabib) = @_;
     my $e = new_editor(authtoken => $auth);
index 12f4f45..e91ff20 100644 (file)
@@ -34,6 +34,13 @@ __PACKAGE__->columns(Primary => 'id');
 __PACKAGE__->columns(Essential => qw/field_class name xpath weight format search_field facet_field display_xpath display_field/);
 #-------------------------------------------------------------------------------
 
+package config::metabib_field_virtual_map;
+use base qw/config/;
+__PACKAGE__->table('config_metabib_field_virtual_map');
+__PACKAGE__->columns(Primary => 'id');
+__PACKAGE__->columns(Essential => qw/real virtual/);
+#-------------------------------------------------------------------------------
+
 package config::identification_type;
 use base qw/config/;
 __PACKAGE__->table('config_identification_type');
index 4b45483..a763f4d 100644 (file)
@@ -8,6 +8,8 @@ use OpenSRF::Utils qw/:datetime/;
 use OpenSRF::Utils::JSON;
 use OpenILS::Application::AppUtils;
 use OpenILS::Utils::CStoreEditor;
+use OpenSRF::Utils::Logger qw($logger);
+use Data::Dumper;
 my $U = 'OpenILS::Application::AppUtils';
 
 my ${spc} = ' ' x 2;
@@ -228,6 +230,15 @@ sub search_field_id_map {
     return $self->custom_data->{search_field_id_map};
 }
 
+sub search_field_virtual_map {
+    my $self = shift;
+    my $map = shift;
+
+    $self->custom_data->{search_field_virtual_map} ||= {};
+    $self->custom_data->{search_field_virtual_map} = $map if ($map);
+    return $self->custom_data->{search_field_virtual_map};
+}
+
 sub add_search_field_id_map {
     my $self = shift;
     my $class = shift;
@@ -246,6 +257,18 @@ sub add_search_field_id_map {
     };
 }
 
+sub add_search_field_virtual_map {
+    my $self = shift;
+    my $realid = shift;
+    my $virtid = shift;
+
+    $self->search_field_virtual_map->{by_virt}{$virtid} ||= [];
+    push @{$self->search_field_virtual_map->{by_virt}{$virtid}}, $realid;
+
+    $self->search_field_virtual_map->{by_real}{$realid} ||= [];
+    push @{$self->search_field_virtual_map->{by_real}{$realid}}, $virtid;
+}
+
 sub search_field_class_by_id {
     my $self = shift;
     my $id = shift;
@@ -400,6 +423,17 @@ sub initialize_search_field_id_map {
     return $self->search_field_id_map;
 }
 
+sub initialize_search_field_virtual_map {
+    my $self = shift;
+    my $cmfvm_list = shift;
+
+    __PACKAGE__->add_search_field_virtual_map( $_->real, $_->virtual )
+        for (@$cmfvm_list);
+
+    $logger->debug('Virtual field map: ' . Dumper($self->search_field_virtual_map));
+    return $self->search_field_virtual_map;
+}
+
 sub initialize_aliases {
     my $self = shift;
     my $cmsa_list = shift;
@@ -513,6 +547,9 @@ sub initialize {
     $self->initialize_search_field_id_map( $args{config_metabib_field} )
         if ($args{config_metabib_field});
 
+    $self->initialize_search_field_virtual_map( $args{config_metabib_field_virtual_map} )
+        if ($args{config_metabib_field_virtual_map});
+
     $self->initialize_aliases( $args{config_metabib_search_alias} )
         if ($args{config_metabib_search_alias});
 
@@ -598,6 +635,8 @@ sub TEST_SETUP {
     __PACKAGE__->add_relevance_bump( keyword => keyword => first_word => 1 );
     __PACKAGE__->add_relevance_bump( keyword => keyword => full_match => 1 );
     
+    __PACKAGE__->add_search_field_virtual_map( 6 => 15 );
+
     __PACKAGE__->class_ts_config( 'series', undef, 1, 'english_nostop' );
     __PACKAGE__->class_ts_config( 'title', undef, 1, 'english_nostop' );
     __PACKAGE__->class_ts_config( 'author', undef, 1, 'english_nostop' );
@@ -635,6 +674,8 @@ sub TEST_SETUP {
     
     __PACKAGE__->add_search_field_alias( subject => name => 'bib.subjectName' );
     
+    #__PACKAGE__->search_class_combined( keyword => 1 );
+    __PACKAGE__->search_class_combined( author => 1 );
 }
 
 __PACKAGE__->default_search_class( 'keyword' );
@@ -1169,17 +1210,6 @@ sub flatten {
                     next;
                 }
 
-                my $table = $node->table;
-                my $ctable = $node->combined_table;
-                my $talias = $node->table_alias;
-
-                my $node_rank = 'COALESCE(' . $node->rank . " * ${talias}.weight, 0.0)";
-
-                $from .= "\n" . ${spc} x 4 ."LEFT JOIN (\n"
-                      . ${spc} x 5 . "SELECT fe.*, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* search */\n"
-                      . ${spc} x 6 . "FROM  $table AS fe";
-                $from .= "\n" . ${spc} x 7 . "JOIN config.metabib_field AS fe_weight ON (fe_weight.id = fe.field)";
-
                 my @bump_fields;
                 my @field_ids;
                 if (@{$node->fields} > 0) {
@@ -1196,22 +1226,37 @@ sub flatten {
                     @bump_fields = @{$self->QueryParser->search_fields->{$node->classname}};
                 }
 
+                # use search_field_list to handle virtual index defs
+                my $search_field_list = $self->QueryParser->search_field_ids_by_class($node->classname);
+                $search_field_list = [@field_ids] if (@field_ids);
+
+                my $table = $node->table;
+                my $ctable = $node->combined_table;
+                my $talias = $node->table_alias;
+
+                my $node_rank = 'COALESCE(' . $node->rank . " * ${talias}.weight * 1000, 0.0)";
+
+                $from .= "\n" . ${spc} x 4 ."LEFT JOIN (\n"
+                      . ${spc} x 5 . "SELECT fe.*, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* search */\n"
+                      . ${spc} x 6 . "FROM  $table AS fe\n"
+                      . ${spc} x 7 . "JOIN config.metabib_field AS fe_weight ON (fe_weight.id = fe.field)";
+
                 if ($node->dummy_count < @{$node->only_atoms} ) {
                     $with .= ",\n     " if $with;
                     $with .= "${talias}_xq AS (SELECT ". $node->tsquery ." AS tsq,". $node->tsquery_rank ." AS tsq_rank )";
                     if ($node->combined_search) {
-                        $from .= "\n" . ${spc} x 6 . "JOIN $ctable AS com ON (com.record = fe.source";
+                        $from .= "\n" . ${spc} x 7 . "JOIN $ctable AS com ON (com.record = fe.source";
                         if (@field_ids) {
                             $from .= " AND com.metabib_field IN (" . join(',',@field_ids) . "))";
                         } else {
                             $from .= " AND com.metabib_field IS NULL)";
                         }
-                        $from .= "\n" . ${spc} x 6 . "JOIN ${talias}_xq ON (com.index_vector @@ ${talias}_xq.tsq)";
+                        $from .= "\n" . ${spc} x 7 . "JOIN ${talias}_xq ON (com.index_vector @@ ${talias}_xq.tsq)";
                     } else {
-                        $from .= "\n" . ${spc} x 6 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
+                        $from .= "\n" . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
                     }
                 } else {
-                    $from .= "\n" . ${spc} x 6 . ", (SELECT NULL::tsquery AS tsq, NULL:tsquery AS tsq_rank ) AS ${talias}_xq";
+                    $from .= "\n" . ${spc} x 7 . ", (SELECT NULL::tsquery AS tsq, NULL::tsquery AS tsq_rank ) AS ${talias}_xq";
                 }
 
                 if (@field_ids) {
@@ -1219,6 +1264,47 @@ sub flatten {
                         join(',', @field_ids) . ")";
                 }
 
+                # Even though virtual fields have all the real field data in
+                # their combined version, and thus a search against the real
+                # fields is not necessary to match records, we still want to
+                # UNION them in so we can get their virtual weight if they
+                # would match a search directly against them.
+                if ($node->dummy_count < @{$node->only_atoms} ) { # no point in searching real fields with no search terms
+                    for my $possible_vfield (@$search_field_list) {
+                        my $real_fields = $self->QueryParser->search_field_virtual_map->{by_virt}->{$possible_vfield};
+                        if ($real_fields and @$real_fields) { # this is a virt field
+                            # UNION in the others ... group by class?
+                            for my $real_field (@$real_fields) {
+                                $node->add_vfield($real_field);
+                                $logger->debug("Looking up virtual field for real field $real_field");
+                                my $vclass = $self->QueryParser->search_field_class_by_id($real_field)->{classname};
+                                my $vtable = $node->table($vclass);
+                                my $vfield = 'field';
+                                my $vrecord = 'source';
+                                $from .= "\n" . ${spc} x 8 . "UNION ALL\n";
+
+                                if ($node->combined_search) { # real fields inherit combine'dness from the virtual field
+                                    $vtable = $node->combined_table($vclass);
+                                    $vfield = 'metabib_field';
+                                    $vrecord = 'record';
+                                    $from .= ${spc} x 5 . "SELECT 0::BIGINT AS id, fe.record AS source, fe.metabib_field AS field, "
+                                          . "'' AS value, fe.index_vector, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n";
+                                } else {
+                                    $from .= ${spc} x 5 . "SELECT fe.id, fe.source, fe.field, fe.value, fe.index_vector, "
+                                          . "fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n";
+                                }
+                                
+                                $from .= ${spc} x 6 . "FROM  $vtable AS fe\n"
+                                      . ${spc} x 7 . "JOIN config.metabib_field_virtual_map AS fe_weight ON ("
+                                            ."fe_weight.virtual = $possible_vfield AND "
+                                            ."fe_weight.real = $real_field AND "
+                                            ."fe_weight.real = fe.$vfield)\n"
+                                      . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
+                            }
+                        }
+                    }
+                }
+
                 $from .= "\n" . ${spc} x 4 . ") AS $talias ON (m.source = ${talias}.source)";
 
                 my %used_bumps;
@@ -1239,9 +1325,9 @@ sub flatten {
 
                 if(scalar @bumps > 0 && scalar @{$node->only_positive_atoms} > 0) {
                     # Note: Previous rank function used search_normalize outright. Duplicating that here.
-                    $node_rank .= "\n" . ${spc} x 5 . "* evergreen.rel_bump(('{' || quote_literal(search_normalize(";
+                    $node_rank .= "\n" . ${spc} x 5 . "* COALESCE(evergreen.rel_bump(('{' || quote_literal(search_normalize(";
                     $node_rank .= join(")) || ',' || quote_literal(search_normalize(",map { $self->QueryParser->quote_phrase_value($_->content) } @{$node->only_positive_atoms});
-                    $node_rank .= ")) || '}')::TEXT[], " . $node->table_alias . ".value, '{" . join(",",@bumps) . "}'::TEXT[], '{" . join(",",@bumpmults) . "}'::NUMERIC[])";
+                    $node_rank .= ")) || '}')::TEXT[], " . $node->table_alias . ".value, '{" . join(",",@bumps) . "}'::TEXT[], '{" . join(",",@bumpmults) . "}'::NUMERIC[]),1.0)";
                 }
 
                 my $NOT = '';
@@ -1665,11 +1751,13 @@ sub fields {
 
 sub table_alias {
     my $self = shift;
+    my $suffix = shift;
 
     my $table_alias = "$self";
     $table_alias =~ s/^.*\(0(x[0-9a-fA-F]+)\)$/$1/go;
     $table_alias .= '_' . $self->name;
     $table_alias =~ s/\|/_/go;
+    $table_alias .= "_$suffix" if ($suffix);
 
     return $table_alias;
 }
@@ -1777,6 +1865,86 @@ sub buildSQL {
 #-------------------------------
 package OpenILS::Application::Storage::Driver::Pg::QueryParser::query_plan::node;
 use base 'QueryParser::query_plan::node';
+use List::MoreUtils qw/uniq/;
+use Data::Dumper;
+
+sub abstract_node_additions {
+    my $self = shift;
+    my $aq = shift;
+
+    my $hm = $self->plan
+                ->QueryParser
+                ->parse_tree
+                ->get_abstract_data('highlight_map') || {};
+
+    my $field_set = $self->fields;
+    $field_set = $self->plan->QueryParser->search_fields->{$self->classname}
+        if (!@$field_set);
+
+    my @field_ids = grep defined, (
+        map {
+            $self->plan->QueryParser->search_field_ids_by_class(
+                $self->classname, $_
+            )->[0]
+        } @$field_set
+    );
+
+    push @field_ids, @{$self->{vfields}} if $self->{vfields};
+
+    my $ts_query = $self->tsquery_rank;
+
+    # We need to rework the hash so fields are only ever pointed at once.
+    # That means if a field is already being looked at elsewhere then we'll
+    # need to separate it out and combine its preexisting tsqueries.  This
+    # will be fairly brute-force, and could be improved later, likely, with
+    # a clever algorithm.
+
+    my %inverted_hm;
+    for my $t (keys %$hm) {
+        for my $f (@{$$hm{$t}}) {
+            $inverted_hm{$f} = $t;
+        }
+    }
+
+    # Then, loop over new fields and put them in the inverted hash.
+    my @existing_fields = keys %inverted_hm;
+
+    for my $f (@field_ids) {
+        if (grep { $f == $_ } @existing_fields) { # We've seen the field, should we combine?
+            my $t = $inverted_hm{$f};
+            if ($t ne $ts_query) { # Different tsquery, do it!
+                $t .= ' || '. $ts_query;
+                $inverted_hm{$f} = $t;
+            }
+        } else { # New field
+            $inverted_hm{$f} = $ts_query;
+        }
+    }
+
+    # Now, flip it back over.
+    $hm = {};
+    for my $f (keys %inverted_hm) {
+        my $t = $inverted_hm{$f};
+        if ($$hm{$t}) {
+            push @{$$hm{$t}}, $f;
+        } else {
+            $$hm{$t} = [$f];
+        }
+    }
+
+    $self->plan
+        ->QueryParser
+        ->parse_tree
+        ->set_abstract_data('highlight_map', $hm);
+}
+
+sub add_vfield {
+    my $self = shift;
+    my $vfield = shift;
+
+    $self->{vfields} ||= [];
+    push @{$self->{vfields}}, $vfield;
+}
 
 sub only_atoms {
     my $self = shift;
@@ -1824,18 +1992,14 @@ sub dummy_count {
 
 sub table {
     my $self = shift;
-    my $table = shift;
-    $self->{table} = $table if ($table);
-    return $self->{table} if $self->{table};
-    return $self->table( 'metabib.' . $self->classname . '_field_entry' );
+    my $classname = shift || $self->classname;
+    return 'metabib.' . $classname . '_field_entry';
 }
 
 sub combined_table {
     my $self = shift;
-    my $ctable = shift;
-    $self->{ctable} = $ctable if ($ctable);
-    return $self->{ctable} if $self->{ctable};
-    return $self->combined_table( 'metabib.combined_' . $self->classname . '_field_entry' );
+    my $classname = shift || $self->classname;
+    return 'metabib.combined_' . $classname . '_field_entry';
 }
 
 sub combined_search {
@@ -1845,16 +2009,15 @@ sub combined_search {
 
 sub table_alias {
     my $self = shift;
-    my $table_alias = shift;
-    $self->{table_alias} = $table_alias if ($table_alias);
-    return $self->{table_alias} if ($self->{table_alias});
+    my $suffix = shift;
 
-    $table_alias = "$self";
+    my $table_alias = "$self";
     $table_alias =~ s/^.*\(0(x[0-9a-fA-F]+)\)$/$1/go;
     $table_alias .= '_' . $self->requested_class;
     $table_alias =~ s/\|/_/go;
+    $table_alias .= "_$suffix" if ($suffix);
 
-    return $self->table_alias( $table_alias );
+    return $table_alias;
 }
 
 sub tsquery {
@@ -1881,7 +2044,7 @@ sub tsquery_rank {
         push @atomlines, "\n" . ${spc} x 3 . $atom->sql;
     }
     $self->{tsquery_rank} = join(' ||', @atomlines);
-    $self->{tsquery_rank} = 'NULL::tsquery' unless $self->{tsquery_rank};
+    $self->{tsquery_rank} = "''::tsquery" unless $self->{tsquery_rank};
     return $self->{tsquery_rank};
 }
 
index c8c3ea7..eb3f423 100644 (file)
@@ -40,6 +40,11 @@ sub _initialize_parser {
                 'open-ils.cstore.direct.config.metabib_field.search.atomic',
                 { id => { "!=" => undef } }
             )->gather(1),
+        config_metabib_field_virtual_map    =>
+            $cstore->request(
+                'open-ils.cstore.direct.config.metabib_field_virtual_map.search.atomic',
+                { id => { "!=" => undef } }
+            )->gather(1),
         config_metabib_search_alias         =>
             $cstore->request(
                 'open-ils.cstore.direct.config.metabib_search_alias.search.atomic',
@@ -87,6 +92,49 @@ sub _initialize_parser {
     die("Cannot initialize $parser!") unless ($parser->initialization_complete);
 }
 
+sub fetch_highlighted_display_fields {
+    my $self = shift;
+    my $client = shift;
+    my $records = shift;
+    my $highlight_map = shift;
+
+    unless ($records) {
+        $client->respond_complete;
+        return;
+    }
+
+    my $hl_map_string = "''::HSTORE";
+    if (ref($highlight_map)) {
+        $hl_map_string = "";
+        for my $tsq (keys %$highlight_map) {
+            my $field_list = join(',', @{$$highlight_map{$tsq}});
+            $hl_map_string .= ' || ' if $hl_map_string;
+            $hl_map_string .= "hstore(($tsq)\:\:TEXT,'$field_list')";
+        }
+    }
+
+    my $sth = metabib::metarecord_source_map->db_Main->prepare(
+        "SELECT * FROM search.highlight_display_fields(?, $hl_map_string)"
+    );
+
+    $records = [$records] unless ref($records);
+    for my $record ( @$records ) {
+        next unless $record;
+        $sth->execute($record);
+        my $rows = $sth->fetchall_arrayref({});
+        $client->respond($rows);
+    }
+
+    return undef;
+}
+__PACKAGE__->register_method(
+    api_name    => 'open-ils.storage.fetch.metabib.display_field.highlight',
+    method      => 'fetch_highlighted_display_fields',
+    api_level   => 1,
+    stream      => 1
+);
+
+
 sub ordered_records_from_metarecord { # XXX Replace with QP-based search-within-MR
     my $self = shift;
     my $client = shift;
index 090b944..199a415 100644 (file)
@@ -1520,6 +1520,19 @@ package QueryParser::query_plan;
 use Data::Dumper;
 $Data::Dumper::Indent = 0;
 
+sub get_abstract_data {
+    my $self = shift;
+    my $key = shift;
+    return $self->{abstract_data}{$key};
+}
+
+sub set_abstract_data {
+    my $self = shift;
+    my $key = shift;
+    my $value = shift;
+    $self->{abstract_data}{$key} = $value;
+}
+
 sub atoms_only {
     my $self = shift;
     return @{$self->filters} == 0 &&
@@ -1741,7 +1754,7 @@ sub QueryParser {
 sub new {
     my $pkg = shift;
     $pkg = ref($pkg) || $pkg;
-    my %args = (query => [], joiner => '&', @_);
+    my %args = (abstract_data => {}, query => [], joiner => '&', @_);
 
     return bless \%args => $pkg;
 }
@@ -2076,6 +2089,9 @@ sub to_abstract_query {
     }
 
     $abstract_query->{children} ||= { QueryParser::_util::default_joiner() => $kids };
+    $$abstract_query{additional_data} = $self->{abstract_data}
+        if (keys(%{$self->{abstract_data}}));
+
     return $abstract_query;
 }
 
@@ -2301,6 +2317,9 @@ sub to_abstract_query {
         "fields" => $self->fields
     };
 
+    $self->abstract_node_additions($abstract_query)
+        if ($self->can('abstract_node_additions'));
+
     my $kids = [];
 
     for my $qatom (@{$self->query_atoms}) {
index 6aa1f58..e386d43 100644 (file)
@@ -341,6 +341,16 @@ sub load_common {
     $self->load_org_util_funcs;
     $self->load_perm_funcs;
 
+    $ctx->{fetch_display_fields} = sub {
+        my $id = shift;
+        return $U->simplereq(
+            'open-ils.search', 
+            'open-ils.search.fetch.metabib.display_field.highlight',
+            $id,
+            $ctx->{query_struct}{additional_data}{highlight_map}
+        );
+    };
+
     return Apache2::Const::OK;
 }
 
index 491f3bb..09b59cf 100644 (file)
@@ -202,7 +202,7 @@ CREATE TABLE config.metabib_field (
        field_class     TEXT    NOT NULL REFERENCES config.metabib_class (name),
        name            TEXT    NOT NULL,
        label           TEXT    NOT NULL,
-       xpath           TEXT    NOT NULL,
+       xpath           TEXT,
        weight          INT     NOT NULL DEFAULT 1,
        format          TEXT    NOT NULL REFERENCES config.xml_transform (name) DEFAULT 'mods33',
        search_field    BOOL    NOT NULL DEFAULT TRUE,
@@ -215,7 +215,7 @@ CREATE TABLE config.metabib_field (
        authority_xpath TEXT,
        joiner      TEXT,
        restrict        BOOL    DEFAULT FALSE NOT NULL,
-    display_field BOOL NOT NULL DEFAULT FALSE
+    display_field BOOL NOT NULL DEFAULT TRUE
 );
 COMMENT ON TABLE config.metabib_field IS $$
 XPath used for record indexing ingest
@@ -226,6 +226,27 @@ a "class" of either title, subject, author, keyword, series
 or identifier.
 $$;
 
+CREATE TABLE config.metabib_field_virtual_map (
+    id      SERIAL  PRIMARY KEY,
+    real    INT NOT NULL REFERENCES config.metabib_field (id),
+    virtual INT NOT NULL REFERENCES config.metabib_field (id),
+    weight  INT NOT NULL DEFAULT 1
+);
+COMMENT ON TABLE config.metabib_field_virtual_map IS $$
+Maps between real (physically extracted) index definitions
+and virtual (target sync, no required extraction of its own)
+index definitions.
+
+The virtual side may not extract any data of its own, but
+will collect data from all of the real fields.  This reduces
+extraction (ingest) overhead by eliminating duplcated extraction,
+and allows for searching across novel combinations of fields, such
+as names used as either subjects or authors.  By preserving this
+mapping rather than defining duplicate extractions, information
+about the originating, "real" index definitions can be used
+in interesting ways, such as highlighting in search results.
+$$;
+
 CREATE UNIQUE INDEX config_metabib_field_class_name_idx ON config.metabib_field (field_class, name);
 
 CREATE TABLE config.display_field_map (
index 499073b..2f37b55 100644 (file)
@@ -173,6 +173,19 @@ CREATE UNIQUE INDEX metabib_combined_series_field_entry_fakepk_idx ON metabib.co
 CREATE INDEX metabib_combined_series_field_entry_index_vector_idx ON metabib.combined_series_field_entry USING GIST (index_vector);
 CREATE INDEX metabib_combined_series_field_source_idx ON metabib.combined_series_field_entry (metabib_field);
 
+CREATE VIEW metabib.combined_all_field_entry AS
+    SELECT * FROM metabib.combined_title_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_author_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_subject_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_keyword_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_identifier_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_series_field_entry;
+
 CREATE TABLE metabib.facet_entry (
        id              BIGSERIAL       PRIMARY KEY,
        source          BIGINT          NOT NULL,
@@ -230,28 +243,76 @@ CREATE VIEW metabib.compressed_display_entry AS
 CREATE VIEW metabib.wide_display_entry AS
 /* Table-like view of well-known display fields.   
    This VIEW expands as well-known display fields are added. */
-    SELECT 
+    SELECT
         bre.id AS source,
         COALESCE(mcde_title.value, 'null') AS title,
         COALESCE(mcde_author.value, 'null') AS author,
-        COALESCE(mcde_subject.value, 'null') AS subject,
+        COALESCE(mcde_subject_geographic.value, 'null') AS subject_geographic,
+        COALESCE(mcde_subject_name.value, 'null') AS subject_name,
+        COALESCE(mcde_subject_temporal.value, 'null') AS subject_temporal,
+        COALESCE(mcde_subject_topic.value, 'null') AS subject_topic,
         COALESCE(mcde_creators.value, 'null') AS creators,
-        COALESCE(mcde_isbn.value, 'null') AS isbn
-    -- ensure one row per bre regardless of the presence of display entries
-    FROM biblio.record_entry bre 
-    LEFT JOIN metabib.compressed_display_entry mcde_title 
+        COALESCE(mcde_isbn.value, 'null') AS isbn,
+        COALESCE(mcde_issn.value, 'null') AS issn,
+        COALESCE(mcde_upc.value, 'null') AS upc,
+        COALESCE(mcde_tcn.value, 'null') AS tcn,
+        COALESCE(mcde_edition.value, 'null') AS edition,
+        COALESCE(mcde_physical_description.value, 'null') AS physical_description,
+        COALESCE(mcde_publisher.value, 'null') AS publisher,
+        COALESCE(mcde_series_title.value, 'null') AS series_title,
+        COALESCE(mcde_abstract.value, 'null') AS abstract,
+        COALESCE(mcde_toc.value, 'null') AS toc,
+        COALESCE(mcde_pubdate.value, 'null') AS pubdate,
+        COALESCE(mcde_type_of_resource.value, 'null') AS type_of_resource
+    FROM biblio.record_entry bre
+    LEFT JOIN metabib.compressed_display_entry mcde_title
         ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
-    LEFT JOIN metabib.compressed_display_entry mcde_author 
+    LEFT JOIN metabib.compressed_display_entry mcde_author
         ON (bre.id = mcde_author.source AND mcde_author.name = 'author')
-    LEFT JOIN metabib.compressed_display_entry mcde_subject 
+    LEFT JOIN metabib.compressed_display_entry mcde_subject
         ON (bre.id = mcde_subject.source AND mcde_subject.name = 'subject')
-    LEFT JOIN metabib.compressed_display_entry mcde_creators 
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_geographic
+        ON (bre.id = mcde_subject_geographic.source
+            AND mcde_subject_geographic.name = 'subject_geographic')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_name
+        ON (bre.id = mcde_subject_name.source
+            AND mcde_subject_name.name = 'subject_name')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_temporal
+        ON (bre.id = mcde_subject_temporal.source
+            AND mcde_subject_temporal.name = 'subject_temporal')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_topic
+        ON (bre.id = mcde_subject_topic.source
+            AND mcde_subject_topic.name = 'subject_topic')
+    LEFT JOIN metabib.compressed_display_entry mcde_creators
         ON (bre.id = mcde_creators.source AND mcde_creators.name = 'creators')
-    LEFT JOIN metabib.compressed_display_entry mcde_isbn 
+    LEFT JOIN metabib.compressed_display_entry mcde_isbn
         ON (bre.id = mcde_isbn.source AND mcde_isbn.name = 'isbn')
+    LEFT JOIN metabib.compressed_display_entry mcde_issn
+        ON (bre.id = mcde_issn.source AND mcde_issn.name = 'issn')
+    LEFT JOIN metabib.compressed_display_entry mcde_upc
+        ON (bre.id = mcde_upc.source AND mcde_upc.name = 'upc')
+    LEFT JOIN metabib.compressed_display_entry mcde_tcn
+        ON (bre.id = mcde_tcn.source AND mcde_tcn.name = 'tcn')
+    LEFT JOIN metabib.compressed_display_entry mcde_edition
+        ON (bre.id = mcde_edition.source AND mcde_edition.name = 'edition')
+    LEFT JOIN metabib.compressed_display_entry mcde_physical_description
+        ON (bre.id = mcde_physical_description.source
+            AND mcde_physical_description.name = 'physical_description')
+    LEFT JOIN metabib.compressed_display_entry mcde_publisher
+        ON (bre.id = mcde_publisher.source AND mcde_publisher.name = 'publisher')
+    LEFT JOIN metabib.compressed_display_entry mcde_series_title
+        ON (bre.id = mcde_series_title.source AND mcde_series_title.name = 'series_title')
+    LEFT JOIN metabib.compressed_display_entry mcde_abstract
+        ON (bre.id = mcde_abstract.source AND mcde_abstract.name = 'abstract')
+    LEFT JOIN metabib.compressed_display_entry mcde_toc
+        ON (bre.id = mcde_toc.source AND mcde_toc.name = 'toc')
+    LEFT JOIN metabib.compressed_display_entry mcde_pubdate
+        ON (bre.id = mcde_pubdate.source AND mcde_pubdate.name = 'pubdate')
+    LEFT JOIN metabib.compressed_display_entry mcde_type_of_resource
+        ON (bre.id = mcde_type_of_resource.source
+            AND mcde_type_of_resource.name = 'type_of_resource')
 ;
 
-
 CREATE TABLE metabib.browse_entry (
     id BIGSERIAL PRIMARY KEY,
     value TEXT,
@@ -719,13 +780,14 @@ BEGIN
 
     -- Loop over the indexing entries
     FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+        CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field
 
         process_idx := FALSE;
         IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
         IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
         IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
         IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
-        CONTINUE WHEN process_idx = FALSE;
+        CONTINUE WHEN process_idx = FALSE; -- disabled for all types
 
         joiner := COALESCE(idx.joiner, default_joiner);
 
@@ -884,10 +946,14 @@ BEGIN
     END LOOP;
 
 END;
-
 $func$ LANGUAGE PLPGSQL;
 
 CREATE OR REPLACE FUNCTION metabib.update_combined_index_vectors(bib_id BIGINT) RETURNS VOID AS $func$
+DECLARE
+    rdata       TSVECTOR;
+    vclass      TEXT;
+    vfield      INT;
+    rfields     INT[];
 BEGIN
     DELETE FROM metabib.combined_keyword_field_entry WHERE record = bib_id;
     INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector)
@@ -937,6 +1003,32 @@ BEGIN
         SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
         FROM metabib.identifier_field_entry WHERE source = bib_id;
 
+    -- For each virtual def, gather the data from the combined real field
+    -- entries and append it to the virtual combined entry.
+    FOR vfield, rfields IN SELECT virtual, ARRAY_AGG(real)  FROM config.metabib_field_virtual_map GROUP BY virtual LOOP
+        SELECT  field_class INTO vclass
+          FROM  config.metabib_field
+          WHERE id = vfield;
+
+        SELECT  string_agg(index_vector::TEXT,' ')::tsvector INTO rdata
+          FROM  metabib.combined_all_field_entry
+          WHERE record = bib_id
+                AND metabib_field = ANY (rfields);
+
+        BEGIN -- I cannot wait for INSERT ON CONFLICT ... 9.5, though
+            EXECUTE $$
+                INSERT INTO metabib.combined_$$ || vclass || $$_field_entry
+                    (record, metabib_field, index_vector) VALUES ($1, $2, $3)
+            $$ USING bib_id, vfield, rdata;
+        EXCEPTION WHEN unique_violation THEN
+            EXECUTE $$
+                UPDATE  metabib.combined_$$ || vclass || $$_field_entry
+                  SET   index_vector = index_vector || $3
+                  WHERE record = $1
+                        AND metabib_field = $2
+            $$ USING bib_id, vfield, rdata;
+        END;
+    END LOOP;
 END;
 $func$ LANGUAGE PLPGSQL;
 
@@ -1404,7 +1496,12 @@ BEGIN
 END;
 $func$ LANGUAGE PLPGSQL;
 
-CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT, bib_is_deleted BOOL DEFAULT FALSE, retain_deleted BOOL DEFAULT FALSE ) RETURNS BIGINT AS $func$
+CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib(
+    bib_id bigint,
+    fp text,
+    bib_is_deleted boolean DEFAULT false,
+    retain_deleted boolean DEFAULT false
+) RETURNS bigint AS $function$
 DECLARE
     new_mapping     BOOL := TRUE;
     source_count    INT;
@@ -1415,11 +1512,11 @@ BEGIN
 
     -- We need to make sure we're not a deleted master record of an MR
     IF bib_is_deleted THEN
-        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
+        IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
+            DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
+        END IF;
 
-            IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
-                DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
-            END IF;
+        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
 
             -- Now, are there any more sources on this MR?
             SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr;
@@ -1491,8 +1588,7 @@ BEGIN
     RETURN old_mr;
 
 END;
-$func$ LANGUAGE PLPGSQL;
-
+$function$ LANGUAGE plpgsql;
 
 CREATE OR REPLACE FUNCTION biblio.map_authority_linking (bibid BIGINT, marc TEXT) RETURNS BIGINT AS $func$
     DELETE FROM authority.bib_linking WHERE bib = $1;
index 820313f..71a2e7d 100644 (file)
@@ -1315,6 +1315,139 @@ BEGIN
 END;
 $p$ LANGUAGE PLPGSQL ROWS 10;
 
+CREATE OR REPLACE VIEW search.best_tsconfig AS
+    SELECT  m.id AS id,
+            COALESCE(f.ts_config, c.ts_config, 'simple') AS ts_config
+      FROM  config.metabib_field m
+            LEFT JOIN config.metabib_class_ts_map c ON (c.field_class = m.field_class AND c.index_weight = 'C')
+            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND c.index_weight = 'C');
+
+CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq         TEXT,
+    field_list  INT[] DEFAULT '{}'::INT[],
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    opts            TEXT := '';
+    v_css_class     TEXT := css_class;
+    v_delimiter     TEXT := delimiter;
+    v_field_list    INT[] := field_list;
+    hl_query        TEXT;
+BEGIN
+    IF v_delimiter LIKE $$%'%$$ OR v_delimiter LIKE '%"%' THEN --"
+        v_delimiter := ' ... ';
+    END IF;
+
+    IF NOT hl_all THEN
+        opts := opts || 'MinWords=' || minwords;
+        opts := opts || ', MaxWords=' || maxwords;
+        opts := opts || ', ShortWords=' || shortwords;
+        opts := opts || ', MaxFragments=' || maxfrags;
+        opts := opts || ', FragmentDelimiter="' || delimiter || '"';
+    ELSE
+        opts := opts || 'HighlightAll=TRUE';
+    END IF;
+
+    IF v_css_class LIKE $$%'%$$ OR v_css_class LIKE '%"%' THEN -- "
+        v_css_class := 'oils_SH';
+    END IF;
+
+    opts := opts || $$, StopSel=</b>, StartSel="<b class='$$ || v_css_class; -- "
+
+    IF v_field_list = '{}'::INT[] THEN
+        SELECT ARRAY_AGG(id) INTO v_field_list FROM config.metabib_field WHERE display_field;
+    END IF;
+
+    hl_query := $$
+        SELECT  de.id,
+                de.source,
+                de.field,
+                de.value AS value,
+                ts_headline(
+                    ts_config::REGCONFIG,
+                    evergreen.escape_for_html(de.value),
+                    $$ || quote_literal(tsq) || $$,
+                    $1 || ' ' || mf.field_class || ' ' || mf.name || $xx$'>"$xx$ -- "'
+                ) AS highlight
+          FROM  metabib.display_entry de
+                JOIN config.metabib_field mf ON (mf.id = de.field)
+                JOIN search.best_tsconfig t ON (t.id = de.field)
+          WHERE de.source = $2
+                AND field = ANY ($3)
+          ORDER BY de.id;$$;
+
+    RETURN QUERY EXECUTE hl_query USING opts, rid, v_field_list;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION evergreen.escape_for_html (TEXT) RETURNS TEXT AS $$
+    SELECT  regexp_replace(
+                regexp_replace(
+                    regexp_replace(
+                        $1,
+                        '&',
+                        '&amp;',
+                        'g'
+                    ),
+                    '<',
+                    '&lt;',
+                    'g'
+                ),
+                '>',
+                '&gt;',
+                'g'
+            );
+$$ LANGUAGE SQL IMMUTABLE LEAKPROOF STRICT COST 10;
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq_map     HSTORE, -- { '(a | b) & c' => '1,2,3,4', ...}
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    tsq     TEXT;
+    fields  TEXT;
+    afields INT[];
+    seen    INT[];
+BEGIN
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_map) LOOP
+        SELECT  ARRAY_AGG(unnest::INT) INTO afields
+          FROM  unnest(regexp_split_to_array(fields,','));
+        seen := seen || afields;
+
+        RETURN QUERY
+            SELECT * FROM search.highlight_display_fields(
+                rid, tsq, afields, css_class, hl_all,minwords,
+                maxwords, shortwords, maxfrags, delimiter
+            );
+    END LOOP;
+
+    RETURN QUERY
+        SELECT  id,
+                source,
+                field,
+                value,
+                value AS highlight
+          FROM  metabib.display_entry
+          WHERE source = rid
+                AND NOT (field = ANY (seen));
+END;
+$f$ LANGUAGE PLPGSQL ROWS 10;
 
 COMMIT;
 
index 5a2b0ff..94ea030 100644 (file)
@@ -150,7 +150,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES 
     (15, 'keyword', 'keyword', oils_i18n_gettext(15, 'General Keywords', 'cmf', 'label'), 'mods32', $$//mods32:mods/*[not(local-name()='originInfo')]$$, FALSE, FALSE ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES
-    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject$$, FALSE, TRUE );
+    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$, FALSE, TRUE );
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field ) VALUES
     (17, 'identifier', 'accession', oils_i18n_gettext(17, 'Accession Number', 'cmf', 'label'), 'marcxml', $$//marc:controlfield[@tag='001']$$, FALSE );
@@ -187,6 +187,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, facet_field, facet_xpath, joiner ) VALUES
     (33, 'identifier', 'genre', oils_i18n_gettext(33, 'Genre', 'cmf', 'label'), 'marcxml', $$//marc:datafield[@tag='655']$$, FALSE, TRUE, $$//*[local-name()='subfield' and contains('abvxyz',@code)]$$, ' -- ' ); -- /* to fool vim */;
+UPDATE config.metabib_field SET display_xpath = facet_xpath, display_field = TRUE WHERE id = 33;
 
 UPDATE config.metabib_field SET joiner = ' -- ' WHERE field_class = 'subject' AND name NOT IN ('name');
 
@@ -210,6 +211,122 @@ INSERT INTO config.metabib_field ( id, field_class, name, label,
     (37, 'author', 'creator', oils_i18n_gettext(37, 'All Creators', 'cmf', 'label'),
      'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    38, 'keyword', 'edition',
+    oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    39, 'keyword', 'physical_description',
+    oils_i18n_gettext(39, 'Physical Descrption', 'cmf', 'label'),
+    $$(//mods33:mods/mods33:physicalDescription/mods33:form|//mods33:mods/mods33:physicalDescription/mods33:extent|//mods33:mods/mods33:physicalDescription/mods33:reformattingQuality|//mods33:mods/mods33:physicalDescription/mods33:internetMediaType|//mods33:mods/mods33:physicalDescription/mods33:digitalOrigin)$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    40, 'keyword', 'publisher',
+    oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    41, 'keyword', 'abstract',
+    oils_i18n_gettext(41, 'Abstract', 'cmf', 'label'),
+    $$//mods33:mods/mods33:abstract$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    42, 'keyword', 'toc',
+    oils_i18n_gettext(42, 'Table of Contents', 'cmf', 'label'),
+    $$//mods33:tableOfContents$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    43, 'identifier', 'type_of_resource',
+    oils_i18n_gettext(43, 'Type of Resource', 'cmf', 'label'),
+    $$//mods33:mods/mods33:typeOfResource$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    44, 'identifier', 'pubdate',
+    oils_i18n_gettext(44, 'Publication Date', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:dateIssued[@encoding="marc"]|//mods33:mods/mods33:originInfo//mods33:dateIssued[1]$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, label, browse_field)
+    VALUES (45, 'keyword', 'blob', oils_i18n_gettext(45, 'All searchable fields', 'cmf', 'label'), FALSE);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    46, 'keyword', 'bibliography',
+    oils_i18n_gettext(46, 'Bibliography', 'cmf', 'label'),
+    $$//mods33:note[@type='bibliography']$$,
+    TRUE, TRUE, FALSE
+),(
+    47, 'keyword', 'thesis',
+    oils_i18n_gettext(47, 'Thesis', 'cmf', 'label'),
+    $$//mods33:note[@type='thesis']$$,
+    TRUE, TRUE, FALSE
+),(
+    48, 'keyword', 'production_credits',
+    oils_i18n_gettext(48, 'Creation/Production Credits', 'cmf', 'label'),
+    $$//mods33:note[@type='creation/production credits']$$,
+    TRUE, TRUE, FALSE
+),(
+    49, 'keyword', 'performers',
+    oils_i18n_gettext(49, 'Performers', 'cmf', 'label'),
+    $$//mods33:note[@type='performers']$$,
+    TRUE, TRUE, FALSE
+),(
+    50, 'keyword', 'general_note',
+    oils_i18n_gettext(50, 'General Note', 'cmf', 'label'),
+    $$//mods33:note[not(@type)]$$,
+    TRUE, TRUE, FALSE
+)
+;
+
+INSERT INTO config.metabib_field_virtual_map (real, virtual)
+    SELECT  id,
+            45
+      FROM  config.metabib_field
+      WHERE search_field
+            AND id NOT IN (15, 45)
+            AND id NOT IN (SELECT real FROM config.metabib_field_virtual_map);
+
+-- Modify existing config.metabib_field entries
+
+UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (
+    1,  -- seriestitle
+    11, -- subject_geographic
+    12, -- subject_name
+    13, -- subject_temporal
+    14, -- subject_topic
+    19, -- ISSN
+    20, -- UPC
+    26  -- TCN
+);
 
 INSERT INTO config.metabib_field_index_norm_map (field,norm)
     SELECT  m.id,
@@ -226,7 +343,22 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('author', 8, FALSE),
     ('creators', 37, TRUE),
     ('subject', 16, TRUE),
-    ('isbn', 18, TRUE)
+    ('isbn', 18, TRUE),
+    ('series_title',         1, FALSE),
+    ('subject_geographic',  11, TRUE),
+    ('subject_name',        12, TRUE),
+    ('subject_temporal',    13, TRUE),
+    ('subject_topic',       14, TRUE),
+    ('issn',                19, TRUE),
+    ('upc',                 20, TRUE),
+    ('tcn',                 26, FALSE),
+    ('edition',             38, FALSE),
+    ('physical_description',39, TRUE),
+    ('publisher',           40, FALSE),
+    ('abstract',            41, FALSE),
+    ('toc',                 42, FALSE),
+    ('type_of_resource',    43, FALSE),
+    ('pubdate',             44, FALSE)
 ;
 
 INSERT INTO config.metabib_search_alias (alias,field_class) VALUES ('kw','keyword');
index ea55482..6b1788b 100644 (file)
@@ -7,46 +7,46 @@ BEGIN;
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    38, 'identifier', 'edition', 
+    38, 'keyword', 'edition', 
     oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    39, 'identifier', 'physical_description', 
+    39, 'keyword', 'physical_description', 
     oils_i18n_gettext(39, 'Physical Descrption', 'cmf', 'label'),
     $$(//mods33:mods/mods33:physicalDescription/mods33:form|//mods33:mods/mods33:physicalDescription/mods33:extent|//mods33:mods/mods33:physicalDescription/mods33:reformattingQuality|//mods33:mods/mods33:physicalDescription/mods33:internetMediaType|//mods33:mods/mods33:physicalDescription/mods33:digitalOrigin)$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    40, 'identifier', 'publisher', 
+    40, 'keyword', 'publisher', 
     oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    41, 'identifier', 'abstract', 
+    41, 'keyword', 'abstract', 
     oils_i18n_gettext(41, 'Abstract', 'cmf', 'label'),
     $$//mods33:mods/mods33:abstract$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    42, 'identifier', 'toc', 
+    42, 'keyword', 'toc', 
     oils_i18n_gettext(42, 'Table of Contents', 'cmf', 'label'),
     $$//mods33:tableOfContents$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
@@ -177,34 +177,3 @@ CREATE VIEW metabib.wide_display_entry AS
 
 COMMIT;
 
-/** ROLLBACK 
-
-BEGIN;
-DELETE FROM metabib.display_entry WHERE field IN (1,11,12,13,14,19,20,26,38,39,40,41,42,43,44);
-DELETE FROM config.display_field_map WHERE field IN (1,11,12,13,14,19,20,26,38,39,40,41,42,43,44);
-DELETE FROM config.metabib_field WHERE id IN (38,39,40,41,42,43,44);
-COMMIT;
-
-*/
-
--- Perform a full display field reingest, since we didn't do one during
--- the 3.0 upgrade when display fields were introduced.
-
-\qecho
-\qecho Reingesting display field entries.  This may take a while.
-\qecho This command can be stopped (control-c) and rerun later if needed:
-\qecho
-\qecho SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE,     
-\qecho     (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field)) 
-\qecho     FROM biblio.record_entry WHERE id > 0; 
-\qecho
-
--- avoid displaying a row per entry by selecting the total count.
--- NOTE: extracting display data for deleted bibs because we occasionally
--- display deleted bib records.
-SELECT COUNT(*) AS bib_count FROM (
-  SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE,     
-    (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field)) 
-  FROM biblio.record_entry WHERE id > 0
-) x;
-
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
new file mode 100644 (file)
index 0000000..2fc357b
--- /dev/null
@@ -0,0 +1,559 @@
+BEGIN;
+
+ALTER TABLE config.metabib_field ALTER COLUMN xpath DROP NOT NULL;
+
+CREATE TABLE config.metabib_field_virtual_map (
+    id      SERIAL  PRIMARY KEY,
+    real    INT NOT NULL REFERENCES config.metabib_field (id),
+    virtual INT NOT NULL REFERENCES config.metabib_field (id),
+    weight  INT NOT NULL DEFAULT 1
+);
+COMMENT ON TABLE config.metabib_field_virtual_map IS $$
+Maps between real (physically extracted) index definitions
+and virtual (target sync, no required extraction of its own)
+index definitions.
+
+The virtual side may not extract any data of its own, but
+will collect data from all of the real fields.  This reduces
+extraction (ingest) overhead by eliminating duplcated extraction,
+and allows for searching across novel combinations of fields, such
+as names used as either subjects or authors.  By preserving this
+mapping rather than defining duplicate extractions, information
+about the originating, "real" index definitions can be used
+in interesting ways, such as highlighting in search results.
+$$;
+
+CREATE OR REPLACE VIEW metabib.combined_all_field_entry AS
+    SELECT * FROM metabib.combined_title_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_author_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_subject_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_keyword_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_identifier_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_series_field_entry;
+
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
+    rid BIGINT,
+    default_joiner TEXT,
+    field_types TEXT[],
+    only_fields INT[]
+) RETURNS SETOF metabib.field_entry_template AS $func$
+DECLARE
+    bib     biblio.record_entry%ROWTYPE;
+    idx     config.metabib_field%ROWTYPE;
+    xfrm        config.xml_transform%ROWTYPE;
+    prev_xfrm   TEXT;
+    transformed_xml TEXT;
+    xml_node    TEXT;
+    xml_node_list   TEXT[];
+    facet_text  TEXT;
+    display_text TEXT;
+    browse_text TEXT;
+    sort_value  TEXT;
+    raw_text    TEXT;
+    curr_text   TEXT;
+    joiner      TEXT := default_joiner; -- XXX will index defs supply a joiner?
+    authority_text TEXT;
+    authority_link BIGINT;
+    output_row  metabib.field_entry_template%ROWTYPE;
+    process_idx BOOL;
+BEGIN
+
+    -- Start out with no field-use bools set
+    output_row.browse_field = FALSE;
+    output_row.facet_field = FALSE;
+    output_row.display_field = FALSE;
+    output_row.search_field = FALSE;
+
+    -- Get the record
+    SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
+
+    -- Loop over the indexing entries
+    FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+        CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field
+
+        process_idx := FALSE;
+        IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        CONTINUE WHEN process_idx = FALSE; -- disabled for all types
+
+        joiner := COALESCE(idx.joiner, default_joiner);
+
+        SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
+
+        -- See if we can skip the XSLT ... it's expensive
+        IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
+            -- Can't skip the transform
+            IF xfrm.xslt <> '---' THEN
+                transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
+            ELSE
+                transformed_xml := bib.marc;
+            END IF;
+
+            prev_xfrm := xfrm.name;
+        END IF;
+
+        xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+
+        raw_text := NULL;
+        FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
+            CONTINUE WHEN xml_node !~ E'^\\s*<';
+
+            -- XXX much of this should be moved into oils_xpath_string...
+            curr_text := ARRAY_TO_STRING(evergreen.array_remove_item_by_value(evergreen.array_remove_item_by_value(
+                oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
+                    REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
+                ), ' '), ''),  -- throw away morally empty (bankrupt?) strings
+                joiner
+            );
+
+            CONTINUE WHEN curr_text IS NULL OR curr_text = '';
+
+            IF raw_text IS NOT NULL THEN
+                raw_text := raw_text || joiner;
+            END IF;
+
+            raw_text := COALESCE(raw_text,'') || curr_text;
+
+            -- autosuggest/metabib.browse_entry
+            IF idx.browse_field THEN
+
+                IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN
+                    browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    browse_text := curr_text;
+                END IF;
+
+                IF idx.browse_sort_xpath IS NOT NULL AND
+                    idx.browse_sort_xpath <> '' THEN
+
+                    sort_value := oils_xpath_string(
+                        idx.browse_sort_xpath, xml_node, joiner,
+                        ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
+                    );
+                ELSE
+                    sort_value := browse_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g'));
+                output_row.sort_value :=
+                    public.naco_normalize(sort_value);
+
+                output_row.authority := NULL;
+
+                IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN
+                    authority_text := oils_xpath_string(
+                        idx.authority_xpath, xml_node, joiner,
+                        ARRAY[
+                            ARRAY[xfrm.prefix, xfrm.namespace_uri],
+                            ARRAY['xlink','http://www.w3.org/1999/xlink']
+                        ]
+                    );
+
+                    IF authority_text ~ '^\d+$' THEN
+                        authority_link := authority_text::BIGINT;
+                        PERFORM * FROM authority.record_entry WHERE id = authority_link;
+                        IF FOUND THEN
+                            output_row.authority := authority_link;
+                        END IF;
+                    END IF;
+
+                END IF;
+
+                output_row.browse_field = TRUE;
+                -- Returning browse rows with search_field = true for search+browse
+                -- configs allows us to retain granularity of being able to search
+                -- browse fields with "starts with" type operators (for example, for
+                -- titles of songs in music albums)
+                IF idx.search_field THEN
+                    output_row.search_field = TRUE;
+                END IF;
+                RETURN NEXT output_row;
+                output_row.browse_field = FALSE;
+                output_row.search_field = FALSE;
+                output_row.sort_value := NULL;
+            END IF;
+
+            -- insert raw node text for faceting
+            IF idx.facet_field THEN
+
+                IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
+                    facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    facet_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
+
+                output_row.facet_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.facet_field = FALSE;
+            END IF;
+
+            -- insert raw node text for display
+            IF idx.display_field THEN
+
+                IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
+                    display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    display_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
+
+                output_row.display_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.display_field = FALSE;
+            END IF;
+
+        END LOOP;
+
+        CONTINUE WHEN raw_text IS NULL OR raw_text = '';
+
+        -- insert combined node text for searching
+        IF idx.search_field THEN
+            output_row.field_class = idx.field_class;
+            output_row.field = idx.id;
+            output_row.source = rid;
+            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
+
+            output_row.search_field = TRUE;
+            RETURN NEXT output_row;
+            output_row.search_field = FALSE;
+        END IF;
+
+    END LOOP;
+
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION metabib.update_combined_index_vectors(bib_id BIGINT) RETURNS VOID AS $func$
+DECLARE
+    rdata       TSVECTOR;
+    vclass      TEXT;
+    vfield      INT;
+    rfields     INT[];
+BEGIN
+    DELETE FROM metabib.combined_keyword_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.keyword_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.keyword_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_title_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_title_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.title_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_title_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.title_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_author_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_author_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.author_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_author_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.author_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_subject_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_subject_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.subject_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_subject_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.subject_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_series_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_series_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.series_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_series_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.series_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_identifier_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_identifier_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.identifier_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_identifier_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.identifier_field_entry WHERE source = bib_id;
+
+    -- For each virtual def, gather the data from the combined real field
+    -- entries and append it to the virtual combined entry.
+    FOR vfield, rfields IN SELECT virtual, ARRAY_AGG(real)  FROM config.metabib_field_virtual_map GROUP BY virtual LOOP
+        SELECT  field_class INTO vclass
+          FROM  config.metabib_field
+          WHERE id = vfield;
+
+        SELECT  string_agg(index_vector::TEXT,' ')::tsvector INTO rdata
+          FROM  metabib.combined_all_field_entry
+          WHERE record = bib_id
+                AND metabib_field = ANY (rfields);
+
+        BEGIN -- I cannot wait for INSERT ON CONFLICT ... 9.5, though
+            EXECUTE $$
+                INSERT INTO metabib.combined_$$ || vclass || $$_field_entry
+                    (record, metabib_field, index_vector) VALUES ($1, $2, $3)
+            $$ USING bib_id, vfield, rdata;
+        EXCEPTION WHEN unique_violation THEN
+            EXECUTE $$
+                UPDATE  metabib.combined_$$ || vclass || $$_field_entry
+                  SET   index_vector = index_vector || $3
+                  WHERE record = $1
+                        AND metabib_field = $2
+            $$ USING bib_id, vfield, rdata;
+        END;
+    END LOOP;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE VIEW search.best_tsconfig AS
+    SELECT  m.id AS id,
+            COALESCE(f.ts_config, c.ts_config, 'simple') AS ts_config
+      FROM  config.metabib_field m
+            LEFT JOIN config.metabib_class_ts_map c ON (c.field_class = m.field_class AND c.index_weight = 'C')
+            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND c.index_weight = 'C');
+
+CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq         TEXT,
+    field_list  INT[] DEFAULT '{}'::INT[],
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    opts            TEXT := '';
+    v_css_class     TEXT := css_class;
+    v_delimiter     TEXT := delimiter;
+    v_field_list    INT[] := field_list;
+    hl_query        TEXT;
+BEGIN
+    IF v_delimiter LIKE $$%'%$$ OR v_delimiter LIKE '%"%' THEN --"
+        v_delimiter := ' ... ';
+    END IF;
+
+    IF NOT hl_all THEN
+        opts := opts || 'MinWords=' || minwords;
+        opts := opts || ', MaxWords=' || maxwords;
+        opts := opts || ', ShortWords=' || shortwords;
+        opts := opts || ', MaxFragments=' || maxfrags;
+        opts := opts || ', FragmentDelimiter="' || delimiter || '"';
+    ELSE
+        opts := opts || 'HighlightAll=TRUE';
+    END IF;
+
+    IF v_css_class LIKE $$%'%$$ OR v_css_class LIKE '%"%' THEN -- "
+        v_css_class := 'oils_SH';
+    END IF;
+
+    opts := opts || $$, StopSel=</b>, StartSel="<b class='$$ || v_css_class; -- "
+
+    IF v_field_list = '{}'::INT[] THEN
+        SELECT ARRAY_AGG(id) INTO v_field_list FROM config.metabib_field WHERE display_field;
+    END IF;
+
+    hl_query := $$
+        SELECT  de.id,
+                de.source,
+                de.field,
+                de.value AS value,
+                ts_headline(
+                    ts_config::REGCONFIG,
+                    evergreen.escape_for_html(de.value),
+                    $$ || quote_literal(tsq) || $$,
+                    $1 || ' ' || mf.field_class || ' ' || mf.name || $xx$'>"$xx$ -- "'
+                ) AS highlight
+          FROM  metabib.display_entry de
+                JOIN config.metabib_field mf ON (mf.id = de.field)
+                JOIN search.best_tsconfig t ON (t.id = de.field)
+          WHERE de.source = $2
+                AND field = ANY ($3)
+          ORDER BY de.id;$$;
+
+    RETURN QUERY EXECUTE hl_query USING opts, rid, v_field_list;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION evergreen.escape_for_html (TEXT) RETURNS TEXT AS $$
+    SELECT  regexp_replace(
+                regexp_replace(
+                    regexp_replace(
+                        $1,
+                        '&',
+                        '&amp;',
+                        'g'
+                    ),
+                    '<',
+                    '&lt;',
+                    'g'
+                ),
+                '>',
+                '&gt;',
+                'g'
+            );
+$$ LANGUAGE SQL IMMUTABLE LEAKPROOF STRICT COST 10;
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq_map     HSTORE, -- { '(a | b) & c' => '1,2,3,4', ...}
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    tsq     TEXT;
+    fields  TEXT;
+    afields INT[];
+    seen    INT[];
+BEGIN
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_map) LOOP
+        SELECT  ARRAY_AGG(unnest::INT) INTO afields
+          FROM  unnest(regexp_split_to_array(fields,','));
+        seen := seen || afields;
+
+        RETURN QUERY
+            SELECT * FROM search.highlight_display_fields(
+                rid, tsq, afields, css_class, hl_all,minwords,
+                maxwords, shortwords, maxfrags, delimiter
+            );
+    END LOOP;
+
+    RETURN QUERY
+        SELECT  id,
+                source,
+                field,
+                value,
+                value AS highlight
+          FROM  metabib.display_entry
+          WHERE source = rid
+                AND NOT (field = ANY (seen));
+END;
+$f$ LANGUAGE PLPGSQL ROWS 10;
+CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib(
+    bib_id bigint,
+    fp text,
+    bib_is_deleted boolean DEFAULT false,
+    retain_deleted boolean DEFAULT false
+) RETURNS bigint AS $function$
+DECLARE
+    new_mapping     BOOL := TRUE;
+    source_count    INT;
+    old_mr          BIGINT;
+    tmp_mr          metabib.metarecord%ROWTYPE;
+    deleted_mrs     BIGINT[];
+BEGIN
+
+    -- We need to make sure we're not a deleted master record of an MR
+    IF bib_is_deleted THEN
+        IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
+            DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
+        END IF;
+
+        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
+
+            -- Now, are there any more sources on this MR?
+            SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr;
+
+            IF source_count = 0 AND NOT retain_deleted THEN -- No other records
+                deleted_mrs := ARRAY_APPEND(deleted_mrs, old_mr); -- Just in case...
+                DELETE FROM metabib.metarecord WHERE id = old_mr;
+
+            ELSE -- indeed there are. Update it with a null cache and recalcualated master record
+                UPDATE  metabib.metarecord
+                  SET   mods = NULL,
+                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+                  WHERE id = old_mr;
+            END IF;
+        END LOOP;
+
+    ELSE -- insert or update
+
+        FOR tmp_mr IN SELECT m.* FROM metabib.metarecord m JOIN metabib.metarecord_source_map s ON (s.metarecord = m.id) WHERE s.source = bib_id LOOP
+
+            -- Find the first fingerprint-matching
+            IF old_mr IS NULL AND fp = tmp_mr.fingerprint THEN
+                old_mr := tmp_mr.id;
+                new_mapping := FALSE;
+
+            ELSE -- Our fingerprint changed ... maybe remove the old MR
+                DELETE FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id AND source = bib_id; -- remove the old source mapping
+                SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id;
+                IF source_count = 0 THEN -- No other records
+                    deleted_mrs := ARRAY_APPEND(deleted_mrs, tmp_mr.id);
+                    DELETE FROM metabib.metarecord WHERE id = tmp_mr.id;
+                END IF;
+            END IF;
+
+        END LOOP;
+
+        -- we found no suitable, preexisting MR based on old source maps
+        IF old_mr IS NULL THEN
+            SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp; -- is there one for our current fingerprint?
+
+            IF old_mr IS NULL THEN -- nope, create one and grab its id
+                INSERT INTO metabib.metarecord ( fingerprint, master_record ) VALUES ( fp, bib_id );
+                SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp;
+
+            ELSE -- indeed there is. update it with a null cache and recalcualated master record
+                UPDATE  metabib.metarecord
+                  SET   mods = NULL,
+                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+                  WHERE id = old_mr;
+            END IF;
+
+        ELSE -- there was one we already attached to, update its mods cache and master_record
+            UPDATE  metabib.metarecord
+              SET   mods = NULL,
+                    master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+              WHERE id = old_mr;
+        END IF;
+
+        IF new_mapping THEN
+            INSERT INTO metabib.metarecord_source_map (metarecord, source) VALUES (old_mr, bib_id); -- new source mapping
+        END IF;
+
+    END IF;
+
+    IF ARRAY_UPPER(deleted_mrs,1) > 0 THEN
+        UPDATE action.hold_request SET target = old_mr WHERE target IN ( SELECT unnest(deleted_mrs) ) AND hold_type = 'M'; -- if we had to delete any MRs above, make sure their holds are moved
+    END IF;
+
+    RETURN old_mr;
+
+END;
+$function$ LANGUAGE plpgsql;
+
+COMMIT;
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
new file mode 100644 (file)
index 0000000..5efb1ff
--- /dev/null
@@ -0,0 +1,6817 @@
+BEGIN;
+
+update config.xml_transform set xslt = $XXXX$<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns="http://www.loc.gov/mods/v3" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xlink marc" version="1.0">
+        <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
+<!--
+Revision 1.14 - Fixed template isValid and fields 010, 020, 022, 024, 028, and 037 to output additional identifier elements
+  with corresponding @type and @invalid eq 'yes' when subfields z or y (in the case of 022) exist in the MARCXML ::: 2007/01/04 17:35:20 cred
+
+Revision 1.13 - Changed order of output under cartographics to reflect schema  2006/11/28 tmee
+
+Revision 1.12 - Updated to reflect MODS 3.2 Mapping  2006/10/11 tmee
+
+Revision 1.11 - The attribute objectPart moved from <languageTerm> to <language>
+      2006/04/08  jrad
+
+Revision 1.10 MODS 3.1 revisions to language and classification elements
+                                (plus ability to find marc:collection embedded in wrapper elements such as SRU zs: wrappers)
+                                2006/02/06  ggar
+
+Revision 1.9 subfield $y was added to field 242 2004/09/02 10:57 jrad
+
+Revision 1.8 Subject chopPunctuation expanded and attribute fixes 2004/08/12 jrad
+
+Revision 1.7 2004/03/25 08:29 jrad
+
+Revision 1.6 various validation fixes 2004/02/20 ntra
+
+Revision 1.5  2003/10/02 16:18:58  ntra
+MODS2 to MODS3 updates, language unstacking and
+de-duping, chopPunctuation expanded
+
+Revision 1.3  2003/04/03 00:07:19  ntra
+Revision 1.3 Additional Changes not related to MODS Version 2.0 by ntra
+
+Revision 1.2  2003/03/24 19:37:42  ckeith
+Added Log Comment
+
+-->
+        <xsl:template match="/">
+                <xsl:choose>
+                        <xsl:when test="//marc:collection">
+                                <modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
+                                        <xsl:for-each select="//marc:collection/marc:record">
+                                                <mods version="3.2">
+                                                        <xsl:call-template name="marcRecord"/>
+                                                </mods>
+                                        </xsl:for-each>
+                                </modsCollection>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
+                                        <xsl:for-each select="//marc:record">
+                                                <xsl:call-template name="marcRecord"/>
+                                        </xsl:for-each>
+                                </mods>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="marcRecord">
+                <xsl:variable name="leader" select="marc:leader"/>
+                <xsl:variable name="leader6" select="substring($leader,7,1)"/>
+                <xsl:variable name="leader7" select="substring($leader,8,1)"/>
+                <xsl:variable name="controlField008" select="marc:controlfield[@tag='008']"/>
+                <xsl:variable name="typeOf008">
+                        <xsl:choose>
+                                <xsl:when test="$leader6='a'">
+                                        <xsl:choose>
+                                                <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>
+                                                <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when>
+                                        </xsl:choose>
+                                </xsl:when>
+                                <xsl:when test="$leader6='t'">BK</xsl:when>
+                                <xsl:when test="$leader6='p'">MM</xsl:when>
+                                <xsl:when test="$leader6='m'">CF</xsl:when>
+                                <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when>
+                                <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when>
+                                <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'">MU</xsl:when>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:for-each select="marc:datafield[@tag='245']">
+                        <titleInfo>
+                                <xsl:variable name="title">
+                                        <xsl:choose>
+                                                <xsl:when test="marc:subfield[@code='b']">
+                                                        <xsl:call-template name="specialSubfieldSelect">
+                                                                <xsl:with-param name="axis">b</xsl:with-param>
+                                                                <xsl:with-param name="beforeCodes">afgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                </xsl:variable>
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="$title"/>
+                                                </xsl:with-param>
+                                                <xsl:with-param name="punctuation">
+                                                    <xsl:text>,;/ </xsl:text>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1,@ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop,@ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:if test="marc:subfield[@code='b']">
+                                        <subTitle>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="axis">b</xsl:with-param>
+                                                                        <xsl:with-param name="anyCodes">b</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">afgk</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </subTitle>
+                                </xsl:if>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleInfo>
+                        <!-- A form of title that ignores non-filing characters; useful
+                                 for not converting "L'Oreal" into "L' Oreal" at index time -->
+                        <titleNonfiling>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleNonfiling>
+                        <!-- hybrid of titleInfo and titleNonfiling which will give us a preformatted string (for punctuation)
+                                 but also keep the nonSort stuff in a separate field (for sorting) -->
+                        <titleBrowse>
+                                <xsl:variable name="titleBrowseChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleBrowseChop,1,@ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleBrowseChop,@ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleBrowseChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleBrowse>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='210']">
+                        <titleInfo type="abbreviated">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">a</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="subtitle"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='242']">
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <!-- 1/04 removed $h, b -->
+                                                        <xsl:with-param name="codes">a</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo type="translated">
+                                <!--09/01/04 Added subfield $y-->
+                                <xsl:for-each select="marc:subfield[@code='y']">
+                                        <xsl:attribute name="lang">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <title>
+                                        <xsl:value-of select="$titleChop" />
+                                </title>
+                                <!-- 1/04 fix -->
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <titleInfo type="translated-nfi">
+                                <xsl:for-each select="marc:subfield[@code='y']">
+                                        <xsl:attribute name="lang">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1,@ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop,@ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop" />
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='246']">
+                        <titleInfo type="alternative">
+                                <xsl:for-each select="marc:subfield[@code='i']">
+                                        <xsl:attribute name="displayLabel">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <!-- 1/04 removed $h, $b -->
+                                                                <xsl:with-param name="codes">af</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='130']|marc:datafield[@tag='240']|marc:datafield[@tag='730'][@ind2!='2']">
+                        <xsl:variable name="nfi">
+                                <xsl:choose>
+                                        <xsl:when test="@tag='240'">
+                                                <xsl:value-of select="@ind2"/>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:value-of select="@ind1"/>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </xsl:variable>
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="uri" />
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield">
+                                                <xsl:if test="(contains('adfklmor',@code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">
+                                                        <xsl:value-of select="text()"/>
+                                                        <xsl:text> </xsl:text>
+                                                </xsl:if>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo type="uniform">
+                                <title>
+                                        <xsl:value-of select="$titleChop"/>
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <titleInfo type="uniform-nfi">
+                                <xsl:choose>
+                                        <xsl:when test="$nfi>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1,$nfi)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop,$nfi+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">ah</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo type="alternative">
+                                <title>
+                                        <xsl:value-of select="$titleChop" />
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <titleInfo type="alternative-nfi">
+                                <xsl:choose>
+                                        <xsl:when test="@ind1>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1,@ind1)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop,@ind1+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop" />
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='100']">
+                        <name type="personal">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDQ"/>
+                                <xsl:call-template name="affiliation"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='110']">
+                        <name type="corporate">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDN"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='111']">
+                        <name type="conference">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameACDEQ"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='700'][not(marc:subfield[@code='t'])]">
+                        <name type="personal">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDQ"/>
+                                <xsl:call-template name="affiliation"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='710'][not(marc:subfield[@code='t'])]">
+                        <name type="corporate">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDN"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='711'][not(marc:subfield[@code='t'])]">
+                        <name type="conference">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameACDEQ"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='720'][not(marc:subfield[@code='t'])]">
+                        <name>
+                                <xsl:if test="@ind1=1">
+                                        <xsl:attribute name="type">
+                                                <xsl:text>personal</xsl:text>
+                                        </xsl:attribute>
+                                </xsl:if>
+                                <namePart>
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </namePart>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <typeOfResource>
+                        <xsl:if test="$leader7='c'">
+                                <xsl:attribute name="collection">yes</xsl:attribute>
+                        </xsl:if>
+                        <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
+                                <xsl:attribute name="manuscript">yes</xsl:attribute>
+                        </xsl:if>
+                        <xsl:choose>
+                                <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
+                                <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
+                                <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
+                                <xsl:when test="$leader6='i'">sound recording-nonmusical</xsl:when>
+                                <xsl:when test="$leader6='j'">sound recording-musical</xsl:when>
+                                <xsl:when test="$leader6='k'">still image</xsl:when>
+                                <xsl:when test="$leader6='g'">moving image</xsl:when>
+                                <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
+                                <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
+                                <xsl:when test="$leader6='p'">mixed material</xsl:when>
+                        </xsl:choose>
+                </typeOfResource>
+                <xsl:if test="substring($controlField008,26,1)='d'">
+                        <genre authority="marc">globe</genre>
+                </xsl:if>
+                <xsl:if test="marc:controlfield[@tag='007'][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+                        <genre authority="marc">remote sensing image</genre>
+                </xsl:if>
+                <xsl:if test="$typeOf008='MP'">
+                        <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-25='a' or $controlField008-25='b' or $controlField008-25='c' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+                                        <genre authority="marc">map</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+                                        <genre authority="marc">atlas</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='SE'">
+                        <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-21='d'">
+                                        <genre authority="marc">database</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='l'">
+                                        <genre authority="marc">loose-leaf</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='m'">
+                                        <genre authority="marc">series</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='n'">
+                                        <genre authority="marc">newspaper</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='p'">
+                                        <genre authority="marc">periodical</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='w'">
+                                        <genre authority="marc">web site</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
+                        <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="contains($controlField008-24,'a')">
+                                        <genre authority="marc">abstract or summary</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'b')">
+                                        <genre authority="marc">bibliography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'c')">
+                                        <genre authority="marc">catalog</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'d')">
+                                        <genre authority="marc">dictionary</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'e')">
+                                        <genre authority="marc">encyclopedia</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'f')">
+                                        <genre authority="marc">handbook</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'g')">
+                                        <genre authority="marc">legal article</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'i')">
+                                        <genre authority="marc">index</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'k')">
+                                        <genre authority="marc">discography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'l')">
+                                        <genre authority="marc">legislation</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'m')">
+                                        <genre authority="marc">theses</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'n')">
+                                        <genre authority="marc">survey of literature</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'o')">
+                                        <genre authority="marc">review</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'p')">
+                                        <genre authority="marc">programmed text</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'q')">
+                                        <genre authority="marc">filmography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'r')">
+                                        <genre authority="marc">directory</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'s')">
+                                        <genre authority="marc">statistics</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'t')">
+                                        <genre authority="marc">technical report</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'v')">
+                                        <genre authority="marc">legal case and case notes</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'w')">
+                                        <genre authority="marc">law report or digest</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'z')">
+                                        <genre authority="marc">treaty</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                        <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-29='1'">
+                                        <genre authority="marc">conference publication</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='CF'">
+                        <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-26='a'">
+                                        <genre authority="marc">numeric data</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='e'">
+                                        <genre authority="marc">database</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='f'">
+                                        <genre authority="marc">font</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='g'">
+                                        <genre authority="marc">game</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='BK'">
+                        <xsl:if test="substring($controlField008,25,1)='j'">
+                                <genre authority="marc">patent</genre>
+                        </xsl:if>
+                        <xsl:if test="substring($controlField008,31,1)='1'">
+                                <genre authority="marc">festschrift</genre>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"></xsl:variable>
+                        <xsl:if test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
+                                <genre authority="marc">biography</genre>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-33='e'">
+                                        <genre authority="marc">essay</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='d'">
+                                        <genre authority="marc">drama</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='c'">
+                                        <genre authority="marc">comic strip</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='l'">
+                                        <genre authority="marc">fiction</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='h'">
+                                        <genre authority="marc">humor, satire</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='i'">
+                                        <genre authority="marc">letter</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='f'">
+                                        <genre authority="marc">novel</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='j'">
+                                        <genre authority="marc">short story</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='s'">
+                                        <genre authority="marc">speech</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='MU'">
+                        <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"></xsl:variable>
+                        <xsl:if test="contains($controlField008-30-31,'b')">
+                                <genre authority="marc">biography</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'c')">
+                                <genre authority="marc">conference publication</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'d')">
+                                <genre authority="marc">drama</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'e')">
+                                <genre authority="marc">essay</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'f')">
+                                <genre authority="marc">fiction</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'o')">
+                                <genre authority="marc">folktale</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'h')">
+                                <genre authority="marc">history</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'k')">
+                                <genre authority="marc">humor, satire</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'m')">
+                                <genre authority="marc">memoir</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'p')">
+                                <genre authority="marc">poetry</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'r')">
+                                <genre authority="marc">rehearsal</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'g')">
+                                <genre authority="marc">reporting</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'s')">
+                                <genre authority="marc">sound</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'l')">
+                                <genre authority="marc">speech</genre>
+                        </xsl:if>
+                </xsl:if>
+                <xsl:if test="$typeOf008='VM'">
+                        <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-33='a'">
+                                        <genre authority="marc">art original</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='b'">
+                                        <genre authority="marc">kit</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='c'">
+                                        <genre authority="marc">art reproduction</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='d'">
+                                        <genre authority="marc">diorama</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='f'">
+                                        <genre authority="marc">filmstrip</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='g'">
+                                        <genre authority="marc">legal article</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='i'">
+                                        <genre authority="marc">picture</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='k'">
+                                        <genre authority="marc">graphic</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='l'">
+                                        <genre authority="marc">technical drawing</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='m'">
+                                        <genre authority="marc">motion picture</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='n'">
+                                        <genre authority="marc">chart</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='o'">
+                                        <genre authority="marc">flash card</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='p'">
+                                        <genre authority="marc">microscope slide</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+                                        <genre authority="marc">model</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='r'">
+                                        <genre authority="marc">realia</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='s'">
+                                        <genre authority="marc">slide</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='t'">
+                                        <genre authority="marc">transparency</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='v'">
+                                        <genre authority="marc">videorecording</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='w'">
+                                        <genre authority="marc">toy</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=655]">
+                        <genre authority="marc">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abvxyz</xsl:with-param>
+                                        <xsl:with-param name="delimeter">-</xsl:with-param>
+                                </xsl:call-template>
+                        </genre>
+                </xsl:for-each>
+                <originInfo>
+                        <xsl:variable name="MARCpublicationCode" select="normalize-space(substring($controlField008,16,3))"></xsl:variable>
+                        <xsl:if test="translate($MARCpublicationCode,'|','')">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                <xsl:attribute name="authority">marccountry</xsl:attribute>
+                                                <xsl:value-of select="$MARCpublicationCode"/>
+                                        </placeTerm>
+                                </place>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                <xsl:attribute name="authority">iso3166</xsl:attribute>
+                                                <xsl:value-of select="."/>
+                                        </placeTerm>
+                                </place>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">text</xsl:attribute>
+                                                <xsl:call-template name="chopPunctuationFront">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="chopPunctuation">
+                                                                        <xsl:with-param name="chopString" select="."/>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </placeTerm>
+                                </place>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
+                                <dateValid point="start">
+                                        <xsl:value-of select="."/>
+                                </dateValid>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
+                                <dateValid point="end">
+                                        <xsl:value-of select="."/>
+                                </dateValid>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
+                                <dateModified>
+                                        <xsl:value-of select="."/>
+                                </dateModified>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
+                                <xsl:choose>
+                                        <xsl:when test="@code='b'">
+                                                <publisher>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                                <xsl:with-param name="punctuation">
+                                                                        <xsl:text>:,;/ </xsl:text>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </publisher>
+                                        </xsl:when>
+                                        <xsl:when test="@code='c'">
+                                                <dateIssued>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </dateIssued>
+                                        </xsl:when>
+                                        <xsl:when test="@code='g'">
+                                                <dateCreated>
+                                                        <xsl:value-of select="."/>
+                                                </dateCreated>
+                                        </xsl:when>
+                                </xsl:choose>
+                        </xsl:for-each>
+                        <xsl:variable name="dataField260c">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="marc:datafield[@tag=260]/marc:subfield[@code='c']"></xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <xsl:variable name="controlField008-7-10" select="normalize-space(substring($controlField008, 8, 4))"></xsl:variable>
+                        <xsl:variable name="controlField008-11-14" select="normalize-space(substring($controlField008, 12, 4))"></xsl:variable>
+                        <xsl:variable name="controlField008-6" select="normalize-space(substring($controlField008, 7, 1))"></xsl:variable>
+                        <xsl:if test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">
+                                <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">
+                                        <dateIssued encoding="marc">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+                                <xsl:if test="$controlField008-7-10">
+                                        <dateIssued encoding="marc" point="start">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <dateIssued encoding="marc" point="end">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='q'">
+                                <xsl:if test="$controlField008-7-10">
+                                        <dateIssued encoding="marc" point="start" qualifier="questionable">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='q'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <dateIssued encoding="marc" point="end" qualifier="questionable">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='t'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <copyrightDate encoding="marc">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </copyrightDate>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">
+                                <dateCaptured encoding="iso8601">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">
+                                <dateCaptured encoding="iso8601" point="start">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">
+                                <dateCaptured encoding="iso8601" point="end">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
+                                <edition>
+                                        <xsl:value-of select="."/>
+                                </edition>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:leader">
+                                <issuance>
+                                        <xsl:choose>
+                                                <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">monographic</xsl:when>
+                                                <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">continuing</xsl:when>
+                                        </xsl:choose>
+                                </issuance>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
+                                <frequency>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">ab</xsl:with-param>
+                                        </xsl:call-template>
+                                </frequency>
+                        </xsl:for-each>
+                </originInfo>
+                <xsl:variable name="controlField008-35-37" select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"></xsl:variable>
+                <xsl:if test="$controlField008-35-37">
+                        <language>
+                                <languageTerm authority="iso639-2b" type="code">
+                                        <xsl:value-of select="substring($controlField008,36,3)"/>
+                                </languageTerm>
+                        </language>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=041]">
+                        <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='d' or @code='e' or @code='f' or @code='g' or @code='h']">
+                                <xsl:variable name="langCodes" select="."/>
+                                <xsl:choose>
+                                        <xsl:when test="../marc:subfield[@code='2']='rfc3066'">
+                                                <!-- not stacked but could be repeated -->
+                                                <xsl:call-template name="rfcLanguages">
+                                                        <xsl:with-param name="nodeNum">
+                                                                <xsl:value-of select="1"/>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="usedLanguages">
+                                                                <xsl:text></xsl:text>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="controlField008-35-37">
+                                                                <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <!-- iso -->
+                                                <xsl:variable name="allLanguages">
+                                                        <xsl:copy-of select="$langCodes"></xsl:copy-of>
+                                                </xsl:variable>
+                                                <xsl:variable name="currentLanguage">
+                                                        <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
+                                                </xsl:variable>
+                                                <xsl:call-template name="isoLanguage">
+                                                        <xsl:with-param name="currentLanguage">
+                                                                <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="remainingLanguages">
+                                                                <xsl:value-of select="substring($allLanguages,4,string-length($allLanguages)-3)"></xsl:value-of>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="usedLanguages">
+                                                                <xsl:if test="$controlField008-35-37">
+                                                                        <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
+                                                                </xsl:if>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </xsl:for-each>
+                </xsl:for-each>
+                <xsl:variable name="physicalDescription">
+                        <!--3.2 change tmee 007/11 -->
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a']">
+                                <digitalOrigin>reformatted digital</digitalOrigin>
+                        </xsl:if>
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='b']">
+                                <digitalOrigin>digitized microfilm</digitalOrigin>
+                        </xsl:if>
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='d']">
+                                <digitalOrigin>digitized other analog</digitalOrigin>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"></xsl:variable>
+                        <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
+                        <xsl:variable name="check008-23">
+                                <xsl:if test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">
+                                        <xsl:value-of select="true()"></xsl:value-of>
+                                </xsl:if>
+                        </xsl:variable>
+                        <xsl:variable name="check008-29">
+                                <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
+                                        <xsl:value-of select="true()"></xsl:value-of>
+                                </xsl:if>
+                        </xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
+                                        <form authority="marcform">braille</form>
+                                </xsl:when>
+                                <xsl:when test="($controlField008-23=' ' and ($leader6='c' or $leader6='d')) or (($typeOf008='BK' or $typeOf008='SE') and ($controlField008-23=' ' or $controlField008='r'))">
+                                        <form authority="marcform">print</form>
+                                </xsl:when>
+                                <xsl:when test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">
+                                        <form authority="marcform">electronic</form>
+                                </xsl:when>
+                                <xsl:when test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
+                                        <form authority="marcform">microfiche</form>
+                                </xsl:when>
+                                <xsl:when test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
+                                        <form authority="marcform">microfilm</form>
+                                </xsl:when>
+                        </xsl:choose>
+                        <!-- 1/04 fix -->
+                        <xsl:if test="marc:datafield[@tag=130]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=130]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=240]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=240]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=242]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=242]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=245]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=245]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=246]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=246]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=730]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=730]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
+                                <form>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </form>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
+                                <xsl:choose>
+                                        <xsl:when test="substring(text(),14,1)='a'">
+                                                <reformattingQuality>access</reformattingQuality>
+                                        </xsl:when>
+                                        <xsl:when test="substring(text(),14,1)='p'">
+                                                <reformattingQuality>preservation</reformattingQuality>
+                                        </xsl:when>
+                                        <xsl:when test="substring(text(),14,1)='r'">
+                                                <reformattingQuality>replacement</reformattingQuality>
+                                        </xsl:when>
+                                </xsl:choose>
+                        </xsl:for-each>
+                        <!--3.2 change tmee 007/01 -->
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='b']">
+                                <form authority="smd">chip cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='c']">
+                                <form authority="smd">computer optical disc cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='j']">
+                                <form authority="smd">magnetic disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='m']">
+                                <form authority="smd">magneto-optical disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='o']">
+                                <form authority="smd">optical disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='a']">
+                                <form authority="smd">tape cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='f']">
+                                <form authority="smd">tape cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='h']">
+                                <form authority="smd">tape reel</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='a']">
+                                <form authority="smd">celestial globe</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='e']">
+                                <form authority="smd">earth moon globe</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='b']">
+                                <form authority="smd">planetary or lunar globe</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='c']">
+                                <form authority="smd">terrestrial globe</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='o'][substring(text(),2,1)='o']">
+                                <form authority="smd">kit</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+                                <form authority="smd">atlas</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='g']">
+                                <form authority="smd">diagram</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+                                <form authority="smd">map</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+                                <form authority="smd">model</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='k']">
+                                <form authority="smd">profile</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote-sensing image</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='s']">
+                                <form authority="smd">section</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='y']">
+                                <form authority="smd">view</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='a']">
+                                <form authority="smd">aperture card</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='e']">
+                                <form authority="smd">microfiche</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='f']">
+                                <form authority="smd">microfiche cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='b']">
+                                <form authority="smd">microfilm cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='c']">
+                                <form authority="smd">microfilm cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='d']">
+                                <form authority="smd">microfilm reel</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='g']">
+                                <form authority="smd">microopaque</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='c']">
+                                <form authority="smd">film cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='f']">
+                                <form authority="smd">film cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='r']">
+                                <form authority="smd">film reel</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='n']">
+                                <form authority="smd">chart</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='c']">
+                                <form authority="smd">collage</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='d']">
+                                <form authority="smd">drawing</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='o']">
+                                <form authority="smd">flash card</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='e']">
+                                <form authority="smd">painting</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='f']">
+                                <form authority="smd">photomechanical print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='g']">
+                                <form authority="smd">photonegative</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='h']">
+                                <form authority="smd">photoprint</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='i']">
+                                <form authority="smd">picture</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='j']">
+                                <form authority="smd">print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='l']">
+                                <form authority="smd">technical drawing</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='q'][substring(text(),2,1)='q']">
+                                <form authority="smd">notated music</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='d']">
+                                <form authority="smd">filmslip</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='c']">
+                                <form authority="smd">filmstrip cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='o']">
+                                <form authority="smd">filmstrip roll</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='f']">
+                                <form authority="smd">other filmstrip type</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='s']">
+                                <form authority="smd">slide</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='t']">
+                                <form authority="smd">transparency</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='r'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote-sensing image</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='e']">
+                                <form authority="smd">cylinder</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='q']">
+                                <form authority="smd">roll</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='g']">
+                                <form authority="smd">sound cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='s']">
+                                <form authority="smd">sound cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='d']">
+                                <form authority="smd">sound disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='t']">
+                                <form authority="smd">sound-tape reel</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='i']">
+                                <form authority="smd">sound-track film</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='w']">
+                                <form authority="smd">wire recording</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='c']">
+                                <form authority="smd">braille</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='b']">
+                                <form authority="smd">combination</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='a']">
+                                <form authority="smd">moon</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='d']">
+                                <form authority="smd">tactile, with no writing system</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='c']">
+                                <form authority="smd">braille</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='b']">
+                                <form authority="smd">large print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='a']">
+                                <form authority="smd">regular print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='d']">
+                                <form authority="smd">text in looseleaf binder</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='c']">
+                                <form authority="smd">videocartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='f']">
+                                <form authority="smd">videocassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='d']">
+                                <form authority="smd">videodisc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='r']">
+                                <form authority="smd">videoreel</form>
+                        </xsl:if>
+
+                        <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">
+                                <internetMediaType>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </internetMediaType>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=300]">
+                                <extent>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abce</xsl:with-param>
+                                        </xsl:call-template>
+                                </extent>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($physicalDescription))">
+                        <physicalDescription>
+                                <xsl:copy-of select="$physicalDescription"></xsl:copy-of>
+                        </physicalDescription>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=520]">
+                        <abstract>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </abstract>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=505]">
+                        <tableOfContents>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">agrt</xsl:with-param>
+                                </xsl:call-template>
+                        </tableOfContents>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=521]">
+                        <targetAudience>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </targetAudience>
+                </xsl:for-each>
+                <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">
+                        <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"></xsl:variable>
+                        <xsl:choose>
+                                <!-- 01/04 fix -->
+                                <xsl:when test="$controlField008-22='d'">
+                                        <targetAudience authority="marctarget">adolescent</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='e'">
+                                        <targetAudience authority="marctarget">adult</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='g'">
+                                        <targetAudience authority="marctarget">general</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
+                                        <targetAudience authority="marctarget">juvenile</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='a'">
+                                        <targetAudience authority="marctarget">preschool</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='f'">
+                                        <targetAudience authority="marctarget">specialized</targetAudience>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">
+                        <note type="statement of responsibility">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=500]">
+                        <note>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                        </note>
+                </xsl:for-each>
+
+                <!--3.2 change tmee additional note fields-->
+
+                <xsl:for-each select="marc:datafield[@tag=506]">
+                        <note type="restrictions">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=510]">
+                        <note  type="citation/reference">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+
+                <xsl:for-each select="marc:datafield[@tag=511]">
+                        <note type="performers">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=518]">
+                        <note type="venue">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=530]">
+                        <note  type="additional physical form">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=533]">
+                        <note  type="reproduction">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=534]">
+                        <note  type="original version">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=538]">
+                        <note  type="system details">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=583]">
+                        <note type="action">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+
+
+
+
+                <xsl:for-each select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
+                        <note>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
+                        <subject>
+                                <cartographics>
+                                        <coordinates>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">defg</xsl:with-param>
+                                                </xsl:call-template>
+                                        </coordinates>
+                                </cartographics>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=043]">
+                        <subject>
+                                <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+                                        <geographicCode>
+                                                <xsl:attribute name="authority">
+                                                        <xsl:if test="@code='a'">
+                                                                <xsl:text>marcgac</xsl:text>
+                                                        </xsl:if>
+                                                        <xsl:if test="@code='b'">
+                                                                <xsl:value-of select="following-sibling::marc:subfield[@code=2]"></xsl:value-of>
+                                                        </xsl:if>
+                                                        <xsl:if test="@code='c'">
+                                                                <xsl:text>iso3166</xsl:text>
+                                                        </xsl:if>
+                                                </xsl:attribute>
+                                                <xsl:value-of select="self::marc:subfield"></xsl:value-of>
+                                        </geographicCode>
+                                </xsl:for-each>
+                        </subject>
+                </xsl:for-each>
+                <!-- tmee 2006/11/27 -->
+                <xsl:for-each select="marc:datafield[@tag=255]">
+                        <subject>
+                                <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+                                <cartographics>
+                                        <xsl:if test="@code='a'">
+                                                <scale>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </scale>
+                                        </xsl:if>
+                                        <xsl:if test="@code='b'">
+                                                <projection>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </projection>
+                                        </xsl:if>
+                                        <xsl:if test="@code='c'">
+                                                <coordinates>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </coordinates>
+                                        </xsl:if>
+                                </cartographics>
+                                </xsl:for-each>
+                        </subject>
+                </xsl:for-each>
+
+                <xsl:apply-templates select="marc:datafield[653 >= @tag and @tag >= 600]"></xsl:apply-templates>
+                <xsl:apply-templates select="marc:datafield[@tag=656]"></xsl:apply-templates>
+                <xsl:for-each select="marc:datafield[@tag=752]">
+                        <subject>
+                                <hierarchicalGeographic>
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <country>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </country>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <state>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </state>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='c']">
+                                                <county>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </county>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='d']">
+                                                <city>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </city>
+                                        </xsl:for-each>
+                                </hierarchicalGeographic>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
+                        <subject>
+                                <xsl:choose>
+                                        <xsl:when test="@ind1=2">
+                                                <temporal encoding="iso8601" point="start">
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString">
+                                                                        <xsl:value-of select="marc:subfield[@code='b'][1]"></xsl:value-of>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </temporal>
+                                                <temporal encoding="iso8601" point="end">
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString">
+                                                                        <xsl:value-of select="marc:subfield[@code='b'][2]"></xsl:value-of>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </temporal>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:for-each select="marc:subfield[@code='b']">
+                                                        <temporal encoding="iso8601">
+                                                                <xsl:call-template name="chopPunctuation">
+                                                                        <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </temporal>
+                                                </xsl:for-each>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=050]">
+                        <xsl:for-each select="marc:subfield[@code='b']">
+                                <classification authority="lcc">
+                                        <xsl:if test="../marc:subfield[@code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:value-of select="../marc:subfield[@code='3']"></xsl:value-of>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"></xsl:value-of>
+                                        <xsl:text> </xsl:text>
+                                        <xsl:value-of select="text()"></xsl:value-of>
+                                </classification>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">
+                                <classification authority="lcc">
+                                        <xsl:if test="../marc:subfield[@code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:value-of select="../marc:subfield[@code='3']"></xsl:value-of>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="text()"></xsl:value-of>
+                                </classification>
+                        </xsl:for-each>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=082]">
+                        <classification authority="ddc">
+                                <xsl:if test="marc:subfield[@code='2']">
+                                        <xsl:attribute name="edition">
+                                                <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:if>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=080]">
+                        <classification authority="udc">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abx</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=060]">
+                        <classification authority="nlm">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">
+                        <classification authority="sudocs">
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">
+                        <classification authority="candoc">
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086]">
+                        <classification>
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                </xsl:attribute>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=084]">
+                        <classification>
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=440]">
+                        <relatedItem type="series">
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">av</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:value-of select="$titleChop" />
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <titleInfo type="nfi">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind2>0">
+                                                        <nonSort>
+                                                                <xsl:value-of select="substring($titleChop,1,@ind2)"/>
+                                                        </nonSort>
+                                                        <title>
+                                                                <xsl:value-of select="substring($titleChop,@ind2+1)"/>
+                                                        </title>
+                                                        <xsl:call-template name="part"/>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <title>
+                                                                <xsl:value-of select="$titleChop" />
+                                                        </title>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">av</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=510]">
+                        <relatedItem type="isReferencedBy">
+                                <note>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abcx3</xsl:with-param>
+                                        </xsl:call-template>
+                                </note>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=534]">
+                        <relatedItem type="original">
+                                <xsl:call-template name="relatedTitle"></xsl:call-template>
+                                <xsl:call-template name="relatedName"></xsl:call-template>
+                                <xsl:if test="marc:subfield[@code='b' or @code='c']">
+                                        <originInfo>
+                                                <xsl:for-each select="marc:subfield[@code='c']">
+                                                        <publisher>
+                                                                <xsl:value-of select="."></xsl:value-of>
+                                                        </publisher>
+                                                </xsl:for-each>
+                                                <xsl:for-each select="marc:subfield[@code='b']">
+                                                        <edition>
+                                                                <xsl:value-of select="."></xsl:value-of>
+                                                        </edition>
+                                                </xsl:for-each>
+                                        </originInfo>
+                                </xsl:if>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                                <xsl:for-each select="marc:subfield[@code='z']">
+                                        <identifier type="isbn">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </identifier>
+                                </xsl:for-each>
+                                <xsl:call-template name="relatedNote"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <name type="personal">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aq</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">g</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="termsOfAddress"></xsl:call-template>
+                                        <xsl:call-template name="nameDate"></xsl:call-template>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">dg</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </titleInfo>
+                                <name type="corporate">
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:variable name="tempNamePart">
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">c</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:variable>
+                                        <xsl:if test="normalize-space($tempNamePart)">
+                                                <namePart>
+                                                        <xsl:value-of select="$tempNamePart"></xsl:value-of>
+                                                </namePart>
+                                        </xsl:if>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </titleInfo>
+                                <name type="conference">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:value-of select="$titleChop" />
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <titleInfo type="nfi">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind1>0">
+                                                        <nonSort>
+                                                                <xsl:value-of select="substring($titleChop,1,@ind1)"/>
+                                                        </nonSort>
+                                                        <title>
+                                                                <xsl:value-of select="substring($titleChop,@ind1+1)"/>
+                                                        </title>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <title>
+                                                                <xsl:value-of select="$titleChop" />
+                                                        </title>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">
+                        <relatedItem type="series">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
+                        <relatedItem>
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=775]">
+                        <relatedItem type="otherVersion">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">
+                        <relatedItem type="constituent">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">
+                        <relatedItem type="host">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=776]">
+                        <relatedItem type="otherFormat">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=780]">
+                        <relatedItem type="preceding">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=785]">
+                        <relatedItem type="succeeding">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=786]">
+                        <relatedItem type="original">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=800]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <name type="personal">
+                                        <namePart>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">aq</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="beforeCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="termsOfAddress"></xsl:call-template>
+                                        <xsl:call-template name="nameDate"></xsl:call-template>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=810]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">dg</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </titleInfo>
+                                <name type="corporate">
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">c</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=811]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </titleInfo>
+                                <name type="conference">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='830']">
+                        <relatedItem type="series">
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:value-of select="$titleChop" />
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <titleInfo type="nfi">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind2>0">
+                                                        <nonSort>
+                                                                <xsl:value-of select="substring($titleChop,1,@ind2)"/>
+                                                        </nonSort>
+                                                        <title>
+                                                                <xsl:value-of select="substring($titleChop,@ind2+1)"/>
+                                                        </title>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <title>
+                                                                <xsl:value-of select="$titleChop" />
+                                                        </title>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='856'][@ind2='2']/marc:subfield[@code='q']">
+                        <relatedItem>
+                                <internetMediaType>
+                                        <xsl:value-of select="."/>
+                                </internetMediaType>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='020']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">isbn</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="isbn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='0']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">isrc</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="isrc">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='2']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">ismn</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="ismn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='4']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">sici</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="sici">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='022']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">issn</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="issn">
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='010']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">lccn</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="lccn">
+                                <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='028']">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind1='0'">issue number</xsl:when>
+                                                <xsl:when test="@ind1='1'">matrix number</xsl:when>
+                                                <xsl:when test="@ind1='2'">music plate</xsl:when>
+                                                <xsl:when test="@ind1='3'">music publisher</xsl:when>
+                                                <xsl:when test="@ind1='4'">videorecording identifier</xsl:when>
+                                        </xsl:choose>
+                                </xsl:attribute>
+                                <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 028 -->
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">
+                                                <xsl:choose>
+                                                        <xsl:when test="@ind1='0'">ba</xsl:when>
+                                                        <xsl:otherwise>ab</xsl:otherwise>
+                                                </xsl:choose>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='037']">
+                        <identifier type="stock number">
+                                <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 037 -->
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='856'][marc:subfield[@code='u']]">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:choose>
+                                                <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:doi') or starts-with(marc:subfield[@code='u'],'doi')">doi</xsl:when>
+                                                <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov')">hdl</xsl:when>
+                                                <xsl:otherwise>uri</xsl:otherwise>
+                                        </xsl:choose>
+                                </xsl:attribute>
+                                <xsl:choose>
+                                        <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov') ">
+                                                <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </identifier>
+                        <xsl:if test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl')">
+                                <identifier type="hdl">
+                                        <xsl:if test="marc:subfield[@code='y' or @code='3' or @code='z']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">y3z</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]">
+                        <identifier type="upc">
+                                <xsl:call-template name="isInvalid"/>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </identifier>
+                </xsl:for-each>
+                <!-- 1/04 fix added $y -->
+                <xsl:for-each select="marc:datafield[@tag=856][marc:subfield[@code='u']]">
+                        <location>
+                                <url>
+                                        <xsl:if test="marc:subfield[@code='y' or @code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">y3</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:if test="marc:subfield[@code='z' ]">
+                                                <xsl:attribute name="note">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">z</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
+
+                                </url>
+                        </location>
+                </xsl:for-each>
+
+                        <!-- 3.2 change tmee 856z  -->
+
+
+                <xsl:for-each select="marc:datafield[@tag=852]">
+                        <location>
+                                <physicalLocation>
+                                        <xsl:call-template name="displayLabel"></xsl:call-template>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abje</xsl:with-param>
+                                        </xsl:call-template>
+                                </physicalLocation>
+                        </location>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=506]">
+                        <accessCondition type="restrictionOnAccess">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcd35</xsl:with-param>
+                                </xsl:call-template>
+                        </accessCondition>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=540]">
+                        <accessCondition type="useAndReproduction">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcde35</xsl:with-param>
+                                </xsl:call-template>
+                        </accessCondition>
+                </xsl:for-each>
+                <recordInfo>
+                        <xsl:for-each select="marc:datafield[@tag=040]">
+                                <recordContentSource authority="marcorg">
+                                        <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                </recordContentSource>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=008]">
+                                <recordCreationDate encoding="marc">
+                                        <xsl:value-of select="substring(.,1,6)"></xsl:value-of>
+                                </recordCreationDate>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=005]">
+                                <recordChangeDate encoding="iso8601">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </recordChangeDate>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=001]">
+                                <recordIdentifier>
+                                        <xsl:if test="../marc:controlfield[@tag=003]">
+                                                <xsl:attribute name="source">
+                                                        <xsl:value-of select="../marc:controlfield[@tag=003]"></xsl:value-of>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </recordIdentifier>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=040]/marc:subfield[@code='b']">
+                                <languageOfCataloging>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </languageTerm>
+                                </languageOfCataloging>
+                        </xsl:for-each>
+                </recordInfo>
+        </xsl:template>
+        <xsl:template name="displayForm">
+                <xsl:for-each select="marc:subfield[@code='c']">
+                        <displayForm>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </displayForm>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="affiliation">
+                <xsl:for-each select="marc:subfield[@code='u']">
+                        <affiliation>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </affiliation>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="uri">
+                <xsl:for-each select="marc:subfield[@code='u']">
+                        <xsl:attribute name="xlink:href">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </xsl:attribute>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='0']">
+                        <xsl:choose>
+                                <xsl:when test="contains(text(), ')')">
+                                        <xsl:attribute name="xlink:href">
+                                                <xsl:value-of select="substring-after(text(), ')')"></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:attribute name="xlink:href">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="role">
+                <xsl:for-each select="marc:subfield[@code='e']">
+                        <role>
+                                <roleTerm type="text">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </roleTerm>
+                        </role>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='4']">
+                        <role>
+                                <roleTerm authority="marcrelator" type="code">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </roleTerm>
+                        </role>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="part">
+                <xsl:variable name="partNumber">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">n</xsl:with-param>
+                                <xsl:with-param name="anyCodes">n</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:variable name="partName">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">p</xsl:with-param>
+                                <xsl:with-param name="anyCodes">p</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($partNumber))">
+                        <partNumber>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="$partNumber"></xsl:with-param>
+                                </xsl:call-template>
+                        </partNumber>
+                </xsl:if>
+                <xsl:if test="string-length(normalize-space($partName))">
+                        <partName>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="$partName"></xsl:with-param>
+                                </xsl:call-template>
+                        </partName>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedPart">
+                <xsl:if test="@tag=773">
+                        <xsl:for-each select="marc:subfield[@code='g']">
+                                <part>
+                                        <text>
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </text>
+                                </part>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:subfield[@code='q']">
+                                <part>
+                                        <xsl:call-template name="parsePart"></xsl:call-template>
+                                </part>
+                        </xsl:for-each>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedPartNumName">
+                <xsl:variable name="partNumber">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">g</xsl:with-param>
+                                <xsl:with-param name="anyCodes">g</xsl:with-param>
+                                <xsl:with-param name="afterCodes">pst</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:variable name="partName">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">p</xsl:with-param>
+                                <xsl:with-param name="anyCodes">p</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($partNumber))">
+                        <partNumber>
+                                <xsl:value-of select="$partNumber"></xsl:value-of>
+                        </partNumber>
+                </xsl:if>
+                <xsl:if test="string-length(normalize-space($partName))">
+                        <partName>
+                                <xsl:value-of select="$partName"></xsl:value-of>
+                        </partName>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedName">
+                <xsl:for-each select="marc:subfield[@code='a']">
+                        <name>
+                                <namePart>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </namePart>
+                        </name>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedForm">
+                <xsl:for-each select="marc:subfield[@code='h']">
+                        <physicalDescription>
+                                <form>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </form>
+                        </physicalDescription>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedExtent">
+                <xsl:for-each select="marc:subfield[@code='h']">
+                        <physicalDescription>
+                                <extent>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </extent>
+                        </physicalDescription>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedNote">
+                <xsl:for-each select="marc:subfield[@code='n']">
+                        <note>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedSubject">
+                <xsl:for-each select="marc:subfield[@code='j']">
+                        <subject>
+                                <temporal encoding="iso8601">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                        </xsl:call-template>
+                                </temporal>
+                        </subject>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifierISSN">
+                <xsl:for-each select="marc:subfield[@code='x']">
+                        <identifier type="issn">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifierLocal">
+                <xsl:for-each select="marc:subfield[@code='w']">
+                        <identifier type="local">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifier">
+                <xsl:for-each select="marc:subfield[@code='o']">
+                        <identifier>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedItem76X-78X">
+                <xsl:call-template name="displayLabel"></xsl:call-template>
+                <xsl:call-template name="relatedTitle76X-78X"></xsl:call-template>
+                <xsl:call-template name="relatedName"></xsl:call-template>
+                <xsl:call-template name="relatedOriginInfo"></xsl:call-template>
+                <xsl:call-template name="relatedLanguage"></xsl:call-template>
+                <xsl:call-template name="relatedExtent"></xsl:call-template>
+                <xsl:call-template name="relatedNote"></xsl:call-template>
+                <xsl:call-template name="relatedSubject"></xsl:call-template>
+                <xsl:call-template name="relatedIdentifier"></xsl:call-template>
+                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                <xsl:call-template name="relatedIdentifierLocal"></xsl:call-template>
+                <xsl:call-template name="relatedPart"></xsl:call-template>
+        </xsl:template>
+        <xsl:template name="subjectGeographicZ">
+                <geographic>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </geographic>
+        </xsl:template>
+        <xsl:template name="subjectTemporalY">
+                <temporal>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </temporal>
+        </xsl:template>
+        <xsl:template name="subjectTopic">
+                <topic>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </topic>
+        </xsl:template>
+        <!-- 3.2 change tmee 6xx $v genre -->
+        <xsl:template name="subjectGenre">
+                <genre>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </genre>
+        </xsl:template>
+
+        <xsl:template name="nameABCDN">
+                <xsl:for-each select="marc:subfield[@code='a']">
+                        <namePart>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='b']">
+                        <namePart>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </namePart>