[open-ils-commits] [GIT] Evergreen ILS branch tags/rel_2_5_1 created. aaecd05f29ad273e8b39c1c5dbeb186482bbe842
Evergreen Git
git at git.evergreen-ils.org
Thu Dec 5 09:55:57 EST 2013
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".
The branch, tags/rel_2_5_1 has been created
at aaecd05f29ad273e8b39c1c5dbeb186482bbe842 (commit)
- Log -----------------------------------------------------------------
commit aaecd05f29ad273e8b39c1c5dbeb186482bbe842
Author: Dan Wells <dbw2 at calvin.edu>
Date: Thu Dec 5 09:53:25 2013 -0500
Pull in missing 2.5.0 upgrade file
This file was never copied upstream, so it didn't make it into this
branch. Adding it manually now.
Signed-off-by: Dan Wells <dbw2 at calvin.edu>
diff --git a/Open-ILS/src/sql/Pg/version-upgrade/2.4.3-2.5.0-upgrade-db.sql b/Open-ILS/src/sql/Pg/version-upgrade/2.4.3-2.5.0-upgrade-db.sql
new file mode 100644
index 0000000..80531c9
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/version-upgrade/2.4.3-2.5.0-upgrade-db.sql
@@ -0,0 +1,16017 @@
+--Upgrade Script for 2.4.3 to 2.5.0
+
+\qecho **** Libraries that upgraded or installed 2.0 before May 2011 never
+\qecho **** got this schema, so add it first.
+\qecho **** If this fails, don't worry, it probably won't be an issue.
+\qecho
+
+BEGIN;
+
+CREATE SCHEMA staging;
+
+CREATE TABLE staging.user_stage (
+ row_id BIGSERIAL PRIMARY KEY,
+ row_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ usrname TEXT NOT NULL,
+ profile TEXT,
+ email TEXT,
+ passwd TEXT,
+ ident_type INT DEFAULT 3,
+ first_given_name TEXT,
+ second_given_name TEXT,
+ family_name TEXT,
+ day_phone TEXT,
+ evening_phone TEXT,
+ home_ou INT DEFAULT 2,
+ dob TEXT,
+ complete BOOL DEFAULT FALSE
+);
+
+CREATE TABLE staging.card_stage ( -- for new library barcodes
+ row_id BIGSERIAL PRIMARY KEY,
+ row_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ usrname TEXT NOT NULL,
+ barcode TEXT NOT NULL,
+ complete BOOL DEFAULT FALSE
+);
+
+CREATE TABLE staging.mailing_address_stage (
+ row_id BIGSERIAL PRIMARY KEY,
+ row_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ usrname TEXT NOT NULL, -- user's SIS barcode, for linking
+ street1 TEXT,
+ street2 TEXT,
+ city TEXT NOT NULL DEFAULT '',
+ state TEXT NOT NULL DEFAULT 'OK',
+ country TEXT NOT NULL DEFAULT 'US',
+ post_code TEXT NOT NULL,
+ complete BOOL DEFAULT FALSE
+);
+
+CREATE TABLE staging.billing_address_stage (
+ LIKE staging.mailing_address_stage INCLUDING DEFAULTS
+);
+
+ALTER TABLE staging.billing_address_stage ADD PRIMARY KEY (row_id);
+
+CREATE TABLE staging.statcat_stage (
+ row_id BIGSERIAL PRIMARY KEY,
+ row_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ usrname TEXT NOT NULL,
+ statcat TEXT NOT NULL, -- for things like 'Year of study'
+ value TEXT NOT NULL, -- and the value, such as 'Freshman'
+ complete BOOL DEFAULT FALSE
+);
+
+COMMIT;
+
+
+\qecho **** REAL 2.5 upgrade starting now...
+
+\set eg_version '''2.5.0'''
+BEGIN;
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.5.0', :eg_version);
+
+SELECT evergreen.upgrade_deps_block_check('0794', :eg_version);
+
+INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
+ VALUES (5,'PATRON_EXCEEDS_LOST_COUNT',oils_i18n_gettext(5, 'Patron exceeds max lost item threshold', 'csp', 'label'),'CIRC|FULFILL|HOLD|CAPTURE|RENEW', TRUE);
+
+INSERT INTO config.org_unit_setting_type ( name, grp, label, description, datatype ) VALUES (
+ 'circ.tally_lost', 'circ',
+ oils_i18n_gettext(
+ 'circ.tally_lost',
+ 'Include Lost circulations in lump sum tallies in Patron Display.',
+ 'coust',
+ 'label'),
+ oils_i18n_gettext(
+ 'circ.tally_lost',
+ 'In the Patron Display interface, the number of total active circulations for a given patron is presented in the Summary sidebar and underneath the Items Out navigation button. This setting will include Lost circulations as counting toward these tallies.',
+ 'coust',
+ 'description'),
+ 'bool'
+);
+
+-- Function: actor.calculate_system_penalties(integer, integer)
+-- DROP FUNCTION actor.calculate_system_penalties(integer, integer);
+
+CREATE OR REPLACE FUNCTION actor.calculate_system_penalties(match_user integer, context_org integer)
+ RETURNS SETOF actor.usr_standing_penalty AS
+$BODY$
+DECLARE
+ user_object actor.usr%ROWTYPE;
+ new_sp_row actor.usr_standing_penalty%ROWTYPE;
+ existing_sp_row actor.usr_standing_penalty%ROWTYPE;
+ collections_fines permission.grp_penalty_threshold%ROWTYPE;
+ max_fines permission.grp_penalty_threshold%ROWTYPE;
+ max_overdue permission.grp_penalty_threshold%ROWTYPE;
+ max_items_out permission.grp_penalty_threshold%ROWTYPE;
+ max_lost permission.grp_penalty_threshold%ROWTYPE;
+ tmp_grp INT;
+ items_overdue INT;
+ items_out INT;
+ items_lost INT;
+ context_org_list INT[];
+ current_fines NUMERIC(8,2) := 0.0;
+ tmp_fines NUMERIC(8,2);
+ tmp_groc RECORD;
+ tmp_circ RECORD;
+ tmp_org actor.org_unit%ROWTYPE;
+ tmp_penalty config.standing_penalty%ROWTYPE;
+ tmp_depth INTEGER;
+BEGIN
+ SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+
+ -- Max fines
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has a high fine balance
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 1 AND org_unit = tmp_org.id;
+
+ IF max_fines.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_fines.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 1;
+
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+ SELECT SUM(f.balance_owed) INTO current_fines
+ FROM money.materialized_billable_xact_summary f
+ JOIN (
+ SELECT r.id
+ FROM booking.reservation r
+ WHERE r.usr = match_user
+ AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+ AND xact_finish IS NULL
+ UNION ALL
+ SELECT g.id
+ FROM money.grocery g
+ WHERE g.usr = match_user
+ AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+ AND xact_finish IS NULL
+ UNION ALL
+ SELECT circ.id
+ FROM action.circulation circ
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND xact_finish IS NULL ) l USING (id);
+
+ IF current_fines >= max_fines.threshold THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_fines.org_unit;
+ new_sp_row.standing_penalty := 1;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for max overdue
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many overdue items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+
+ SELECT * INTO max_overdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 2 AND org_unit = tmp_org.id;
+
+ IF max_overdue.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_overdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_overdue.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_overdue.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 2;
+
+ SELECT INTO items_overdue COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_overdue.org_unit ) fp ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND circ.due_date < NOW()
+ AND (circ.stop_fines = 'MAXFINES' OR circ.stop_fines IS NULL);
+
+ IF items_overdue >= max_overdue.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_overdue.org_unit;
+ new_sp_row.standing_penalty := 2;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for max out
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many checked out items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_items_out FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 3 AND org_unit = tmp_org.id;
+
+ IF max_items_out.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_items_out.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ -- Fail if the user has too many items checked out
+ IF max_items_out.threshold IS NOT NULL THEN
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_items_out.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 3;
+ SELECT INTO items_out COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines IN (
+ SELECT 'MAXFINES'::TEXT
+ UNION ALL
+ SELECT 'LONGOVERDUE'::TEXT
+ UNION ALL
+ SELECT 'LOST'::TEXT
+ WHERE 'true' ILIKE
+ (
+ SELECT CASE
+ WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.tally_lost', circ.circ_lib)) ILIKE 'true' THEN 'true'
+ ELSE 'false'
+ END
+ )
+ UNION ALL
+ SELECT 'CLAIMSRETURNED'::TEXT
+ WHERE 'false' ILIKE
+ (
+ SELECT CASE
+ WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.do_not_tally_claims_returned', circ.circ_lib)) ILIKE 'true' THEN 'true'
+ ELSE 'false'
+ END
+ )
+ ) OR circ.stop_fines IS NULL)
+ AND xact_finish IS NULL;
+
+ IF items_out >= max_items_out.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_items_out.org_unit;
+ new_sp_row.standing_penalty := 3;
+ RETURN NEXT new_sp_row;
+ END IF;
+END IF;
+
+ -- Start over for max lost
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many lost items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_lost FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 5 AND org_unit = tmp_org.id;
+ IF max_lost.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_lost.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_lost.threshold IS NOT NULL THEN
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_lost.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 5;
+
+ SELECT INTO items_lost COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_lost.org_unit ) fp ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines = 'LOST')
+ AND xact_finish IS NULL;
+
+ IF items_lost >= max_lost.threshold::INT AND 0 < max_lost.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_lost.org_unit;
+ new_sp_row.standing_penalty := 5;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for collections warning
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has a collections-level fine balance
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 4 AND org_unit = tmp_org.id;
+ IF max_fines.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_fines.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 4;
+
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+ SELECT SUM(f.balance_owed) INTO current_fines
+ FROM money.materialized_billable_xact_summary f
+ JOIN (
+ SELECT r.id
+ FROM booking.reservation r
+ WHERE r.usr = match_user
+ AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+ AND r.xact_finish IS NULL
+ UNION ALL
+ SELECT g.id
+ FROM money.grocery g
+ WHERE g.usr = match_user
+ AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+ AND g.xact_finish IS NULL
+ UNION ALL
+ SELECT circ.id
+ FROM action.circulation circ
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND circ.xact_finish IS NULL ) l USING (id);
+
+ IF current_fines >= max_fines.threshold THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_fines.org_unit;
+ new_sp_row.standing_penalty := 4;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for in collections
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Remove the in-collections penalty if the user has paid down enough
+ -- This penalty is different, because this code is not responsible for creating
+ -- new in-collections penalties, only for removing them
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 30 AND org_unit = tmp_org.id;
+
+ IF max_fines.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL THEN
+
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+ -- first, see if the user had paid down to the threshold
+ SELECT SUM(f.balance_owed) INTO current_fines
+ FROM money.materialized_billable_xact_summary f
+ JOIN (
+ SELECT r.id
+ FROM booking.reservation r
+ WHERE r.usr = match_user
+ AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+ AND r.xact_finish IS NULL
+ UNION ALL
+ SELECT g.id
+ FROM money.grocery g
+ WHERE g.usr = match_user
+ AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+ AND g.xact_finish IS NULL
+ UNION ALL
+ SELECT circ.id
+ FROM action.circulation circ
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND circ.xact_finish IS NULL ) l USING (id);
+
+ IF current_fines IS NULL OR current_fines <= max_fines.threshold THEN
+ -- patron has paid down enough
+
+ SELECT INTO tmp_penalty * FROM config.standing_penalty WHERE id = 30;
+
+ IF tmp_penalty.org_depth IS NOT NULL THEN
+
+ -- since this code is not responsible for applying the penalty, it can't
+ -- guarantee the current context org will match the org at which the penalty
+ --- was applied. search up the org tree until we hit the configured penalty depth
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+ SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+
+ WHILE tmp_depth >= tmp_penalty.org_depth LOOP
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = tmp_org.id
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 30;
+
+ IF tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+ SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+ END LOOP;
+
+ ELSE
+
+ -- no penalty depth is defined, look for exact matches
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_fines.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 30;
+ END IF;
+
+ END IF;
+
+ END IF;
+
+ RETURN;
+END;
+$BODY$
+ LANGUAGE plpgsql VOLATILE
+ COST 100
+ ROWS 1000;
+
+
+SELECT evergreen.upgrade_deps_block_check('0795', :eg_version);
+
+CREATE OR REPLACE FUNCTION
+ evergreen.z3950_attr_name_is_valid(TEXT) RETURNS BOOLEAN AS $func$
+ SELECT EXISTS (SELECT 1 FROM config.z3950_attr WHERE name = $1);
+$func$ LANGUAGE SQL STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION evergreen.z3950_attr_name_is_valid(TEXT) IS $$
+Results in TRUE if there exists at least one config.z3950_attr
+with the provided name. Used by config.z3950_index_field_map
+to verify z3950_attr_type maps.
+$$;
+
+CREATE TABLE config.z3950_index_field_map (
+ id SERIAL PRIMARY KEY,
+ label TEXT NOT NULL, -- i18n
+ metabib_field INTEGER REFERENCES config.metabib_field(id),
+ record_attr TEXT REFERENCES config.record_attr_definition(name),
+ z3950_attr INTEGER REFERENCES config.z3950_attr(id),
+ z3950_attr_type TEXT,-- REFERENCES config.z3950_attr(name)
+ CONSTRAINT metabib_field_or_record_attr CHECK (
+ metabib_field IS NOT NULL OR
+ record_attr IS NOT NULL
+ ),
+ CONSTRAINT attr_or_attr_type CHECK (
+ z3950_attr IS NOT NULL OR
+ z3950_attr_type IS NOT NULL
+ ),
+ -- ensure the selected z3950_attr_type refers to a valid attr name
+ CONSTRAINT valid_z3950_attr_type CHECK (
+ z3950_attr_type IS NULL OR
+ evergreen.z3950_attr_name_is_valid(z3950_attr_type)
+ )
+);
+
+-- seed data
+
+INSERT INTO config.z3950_index_field_map
+ (id, label, metabib_field, z3950_attr_type) VALUES
+(1, oils_i18n_gettext(1, 'Title', 'czifm', 'label'), 5, 'title'),
+(2, oils_i18n_gettext(2, 'Author', 'czifm', 'label'), 8, 'author'),
+(3, oils_i18n_gettext(3, 'ISBN', 'czifm', 'label'), 18, 'isbn'),
+(4, oils_i18n_gettext(4, 'ISSN', 'czifm', 'label'), 19, 'issn'),
+(5, oils_i18n_gettext(5, 'LCCN', 'czifm', 'label'), 30, 'lccn');
+
+INSERT INTO config.z3950_index_field_map
+ (id, label, record_attr, z3950_attr_type) VALUES
+(6, oils_i18n_gettext(6, 'Pubdate', 'czifm', 'label'),'pubdate', 'pubdate'),
+(7, oils_i18n_gettext(7, 'Item Type', 'czifm', 'label'),'item_type', 'item_type');
+
+
+-- let's leave room for more stock mappings
+SELECT SETVAL('config.z3950_index_field_map_id_seq'::TEXT, 1000);
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+ VALUES (
+ 'cat.z3950.batch.max_parallel',
+ 'cat',
+ oils_i18n_gettext(
+ 'cat.z3950.batch.max_parallel',
+ 'Maximum Parallel Z39.50 Batch Searches',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'cat.z3950.batch.max_parallel',
+ 'The maximum number of Z39.50 searches that can be in-flight at any given time when performing batch Z39.50 searches',
+ 'coust',
+ 'description'
+ ),
+ 'integer'
+ );
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+ VALUES (
+ 'cat.z3950.batch.max_results',
+ 'cat',
+ oils_i18n_gettext(
+ 'cat.z3950.batch.max_results',
+ 'Maximum Z39.50 Batch Search Results',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'cat.z3950.batch.max_results',
+ 'The maximum number of search results to retrieve and queue for each record + Z39 source during batch Z39.50 searches',
+ 'coust',
+ 'description'
+ ),
+ 'integer'
+ );
+
+INSERT INTO vandelay.bib_attr_definition (id, code, description, xpath)
+ VALUES (
+ 16,
+ 'zsource',
+ oils_i18n_gettext(16, 'Z39.50 Source', 'vqbrad', 'description'),
+ '//*[@tag="901"]/*[@code="z"]'
+ );
+
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0796', :eg_version);
+
+ALTER TABLE vandelay.bib_queue ADD COLUMN match_bucket
+ INTEGER REFERENCES container.biblio_record_entry_bucket(id)
+ ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
+
+CREATE OR REPLACE FUNCTION vandelay.match_bib_record() RETURNS TRIGGER AS $func$
+DECLARE
+ incoming_existing_id TEXT;
+ test_result vandelay.match_set_test_result%ROWTYPE;
+ tmp_rec BIGINT;
+ match_set INT;
+ match_bucket INT;
+BEGIN
+ IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN
+ RETURN NEW;
+ END IF;
+
+ DELETE FROM vandelay.bib_match WHERE queued_record = NEW.id;
+
+ SELECT q.match_set INTO match_set FROM vandelay.bib_queue q WHERE q.id = NEW.queue;
+
+ IF match_set IS NOT NULL THEN
+ NEW.quality := vandelay.measure_record_quality( NEW.marc, match_set );
+ END IF;
+
+ -- Perfect matches on 901$c exit early with a match with high quality.
+ incoming_existing_id :=
+ oils_xpath_string('//*[@tag="901"]/*[@code="c"][1]', NEW.marc);
+
+ IF incoming_existing_id IS NOT NULL AND incoming_existing_id != '' THEN
+ SELECT id INTO tmp_rec FROM biblio.record_entry WHERE id = incoming_existing_id::bigint;
+ IF tmp_rec IS NOT NULL THEN
+ INSERT INTO vandelay.bib_match (queued_record, eg_record, match_score, quality)
+ SELECT
+ NEW.id,
+ b.id,
+ 9999,
+ -- note: no match_set means quality==0
+ vandelay.measure_record_quality( b.marc, match_set )
+ FROM biblio.record_entry b
+ WHERE id = incoming_existing_id::bigint;
+ END IF;
+ END IF;
+
+ IF match_set IS NULL THEN
+ RETURN NEW;
+ END IF;
+
+ SELECT q.match_bucket INTO match_bucket FROM vandelay.bib_queue q WHERE q.id = NEW.queue;
+
+ FOR test_result IN SELECT * FROM
+ vandelay.match_set_test_marcxml(match_set, NEW.marc, match_bucket) LOOP
+
+ INSERT INTO vandelay.bib_match ( queued_record, eg_record, match_score, quality )
+ SELECT
+ NEW.id,
+ test_result.record,
+ test_result.quality,
+ vandelay.measure_record_quality( b.marc, match_set )
+ FROM biblio.record_entry b
+ WHERE id = test_result.record;
+
+ END LOOP;
+
+ RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+DROP FUNCTION IF EXISTS vandelay.match_set_test_marcxml(INTEGER, TEXT);
+
+CREATE OR REPLACE FUNCTION vandelay.match_set_test_marcxml(
+ match_set_id INTEGER, record_xml TEXT, bucket_id INTEGER
+) RETURNS SETOF vandelay.match_set_test_result AS $$
+DECLARE
+ tags_rstore HSTORE;
+ svf_rstore HSTORE;
+ coal TEXT;
+ joins TEXT;
+ query_ TEXT;
+ wq TEXT;
+ qvalue INTEGER;
+ rec RECORD;
+BEGIN
+ tags_rstore := vandelay.flatten_marc_hstore(record_xml);
+ svf_rstore := vandelay.extract_rec_attrs(record_xml);
+
+ CREATE TEMPORARY TABLE _vandelay_tmp_qrows (q INTEGER);
+ CREATE TEMPORARY TABLE _vandelay_tmp_jrows (j TEXT);
+
+ -- generate the where clause and return that directly (into wq), and as
+ -- a side-effect, populate the _vandelay_tmp_[qj]rows tables.
+ wq := vandelay.get_expr_from_match_set(match_set_id, tags_rstore);
+
+ query_ := 'SELECT DISTINCT(record), ';
+
+ -- qrows table is for the quality bits we add to the SELECT clause
+ SELECT ARRAY_TO_STRING(
+ ARRAY_ACCUM('COALESCE(n' || q::TEXT || '.quality, 0)'), ' + '
+ ) INTO coal FROM _vandelay_tmp_qrows;
+
+ -- our query string so far is the SELECT clause and the inital FROM.
+ -- no JOINs yet nor the WHERE clause
+ query_ := query_ || coal || ' AS quality ' || E'\n';
+
+ -- jrows table is for the joins we must make (and the real text conditions)
+ SELECT ARRAY_TO_STRING(ARRAY_ACCUM(j), E'\n') INTO joins
+ FROM _vandelay_tmp_jrows;
+
+ -- add those joins and the where clause to our query.
+ query_ := query_ || joins || E'\n';
+
+ -- join the record bucket
+ IF bucket_id IS NOT NULL THEN
+ query_ := query_ || 'JOIN container.biblio_record_entry_bucket_item ' ||
+ 'brebi ON (brebi.target_biblio_record_entry = record ' ||
+ 'AND brebi.bucket = ' || bucket_id || E')\n';
+ END IF;
+
+ query_ := query_ || 'JOIN biblio.record_entry bre ON (bre.id = record) ' || 'WHERE ' || wq || ' AND not bre.deleted';
+
+ -- this will return rows of record,quality
+ FOR rec IN EXECUTE query_ USING tags_rstore, svf_rstore LOOP
+ RETURN NEXT rec;
+ END LOOP;
+
+ DROP TABLE _vandelay_tmp_qrows;
+ DROP TABLE _vandelay_tmp_jrows;
+ RETURN;
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+SELECT evergreen.upgrade_deps_block_check('0797', :eg_version);
+
+-- New global flags for the purge function
+INSERT INTO config.global_flag (name, label, enabled)
+ VALUES (
+ 'history.hold.retention_age',
+ oils_i18n_gettext('history.hold.retention_age', 'Historical Hold Retention Age', 'cgf', 'label'),
+ TRUE
+ ),(
+ 'history.hold.retention_age_fulfilled',
+ oils_i18n_gettext('history.hold.retention_age_fulfilled', 'Historical Hold Retention Age - Fulfilled', 'cgf', 'label'),
+ FALSE
+ ),(
+ 'history.hold.retention_age_canceled',
+ oils_i18n_gettext('history.hold.retention_age_canceled', 'Historical Hold Retention Age - Canceled (Default)', 'cgf', 'label'),
+ FALSE
+ ),(
+ 'history.hold.retention_age_canceled_1',
+ oils_i18n_gettext('history.hold.retention_age_canceled_1', 'Historical Hold Retention Age - Canceled (Untarged expiration)', 'cgf', 'label'),
+ FALSE
+ ),(
+ 'history.hold.retention_age_canceled_2',
+ oils_i18n_gettext('history.hold.retention_age_canceled_2', 'Historical Hold Retention Age - Canceled (Hold Shelf expiration)', 'cgf', 'label'),
+ FALSE
+ ),(
+ 'history.hold.retention_age_canceled_3',
+ oils_i18n_gettext('history.hold.retention_age_canceled_3', 'Historical Hold Retention Age - Canceled (Patron via phone)', 'cgf', 'label'),
+ TRUE
+ ),(
+ 'history.hold.retention_age_canceled_4',
+ oils_i18n_gettext('history.hold.retention_age_canceled_4', 'Historical Hold Retention Age - Canceled (Patron in person)', 'cgf', 'label'),
+ TRUE
+ ),(
+ 'history.hold.retention_age_canceled_5',
+ oils_i18n_gettext('history.hold.retention_age_canceled_5', 'Historical Hold Retention Age - Canceled (Staff forced)', 'cgf', 'label'),
+ TRUE
+ ),(
+ 'history.hold.retention_age_canceled_6',
+ oils_i18n_gettext('history.hold.retention_age_canceled_6', 'Historical Hold Retention Age - Canceled (Patron via OPAC)', 'cgf', 'label'),
+ FALSE
+ );
+
+CREATE OR REPLACE FUNCTION action.purge_holds() RETURNS INT AS $func$
+DECLARE
+ current_hold RECORD;
+ purged_holds INT;
+ cgf_d INTERVAL;
+ cgf_f INTERVAL;
+ cgf_c INTERVAL;
+ prev_usr INT;
+ user_start TIMESTAMPTZ;
+ user_age INTERVAL;
+ user_count INT;
+BEGIN
+ purged_holds := 0;
+ SELECT INTO cgf_d value::INTERVAL FROM config.global_flag WHERE name = 'history.hold.retention_age' AND enabled;
+ SELECT INTO cgf_f value::INTERVAL FROM config.global_flag WHERE name = 'history.hold.retention_age_fulfilled' AND enabled;
+ SELECT INTO cgf_c value::INTERVAL FROM config.global_flag WHERE name = 'history.hold.retention_age_canceled' AND enabled;
+ FOR current_hold IN
+ SELECT
+ rank() OVER (PARTITION BY usr ORDER BY COALESCE(fulfillment_time, cancel_time) DESC),
+ cgf_cs.value::INTERVAL as cgf_cs,
+ ahr.*
+ FROM
+ action.hold_request ahr
+ LEFT JOIN config.global_flag cgf_cs ON (ahr.cancel_cause IS NOT NULL AND cgf_cs.name = 'history.hold.retention_age_canceled_' || ahr.cancel_cause AND cgf_cs.enabled)
+ WHERE
+ (fulfillment_time IS NOT NULL OR cancel_time IS NOT NULL)
+ LOOP
+ IF prev_usr IS NULL OR prev_usr != current_hold.usr THEN
+ prev_usr := current_hold.usr;
+ SELECT INTO user_start oils_json_to_text(value)::TIMESTAMPTZ FROM actor.usr_setting WHERE usr = prev_usr AND name = 'history.hold.retention_start';
+ SELECT INTO user_age oils_json_to_text(value)::INTERVAL FROM actor.usr_setting WHERE usr = prev_usr AND name = 'history.hold.retention_age';
+ SELECT INTO user_count oils_json_to_text(value)::INT FROM actor.usr_setting WHERE usr = prev_usr AND name = 'history.hold.retention_count';
+ IF user_start IS NOT NULL THEN
+ user_age := LEAST(user_age, AGE(NOW(), user_start));
+ END IF;
+ IF user_count IS NULL THEN
+ user_count := 1000; -- Assumption based on the user visible holds routine
+ END IF;
+ END IF;
+ -- Library keep age trumps user keep anything, for purposes of being able to hold on to things when staff canceled and such.
+ IF current_hold.fulfillment_time IS NOT NULL AND current_hold.fulfillment_time > NOW() - COALESCE(cgf_f, cgf_d) THEN
+ CONTINUE;
+ END IF;
+ IF current_hold.cancel_time IS NOT NULL AND current_hold.cancel_time > NOW() - COALESCE(current_hold.cgf_cs, cgf_c, cgf_d) THEN
+ CONTINUE;
+ END IF;
+
+ -- User keep age needs combining with count. If too old AND within the count, keep!
+ IF user_start IS NOT NULL AND COALESCE(current_hold.fulfillment_time, current_hold.cancel_time) > NOW() - user_age AND current_hold.rank <= user_count THEN
+ CONTINUE;
+ END IF;
+
+ -- All checks should have passed, delete!
+ DELETE FROM action.hold_request WHERE id = current_hold.id;
+ purged_holds := purged_holds + 1;
+ END LOOP;
+ RETURN purged_holds;
+END;
+$func$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION action.usr_visible_holds (usr_id INT) RETURNS SETOF action.hold_request AS $func$
+DECLARE
+ h action.hold_request%ROWTYPE;
+ view_age INTERVAL;
+ view_count INT;
+ usr_view_count actor.usr_setting%ROWTYPE;
+ usr_view_age actor.usr_setting%ROWTYPE;
+ usr_view_start actor.usr_setting%ROWTYPE;
+BEGIN
+ SELECT * INTO usr_view_count FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.hold.retention_count';
+ SELECT * INTO usr_view_age FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.hold.retention_age';
+ SELECT * INTO usr_view_start FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.hold.retention_start';
+
+ FOR h IN
+ SELECT *
+ FROM action.hold_request
+ WHERE usr = usr_id
+ AND fulfillment_time IS NULL
+ AND cancel_time IS NULL
+ ORDER BY request_time DESC
+ LOOP
+ RETURN NEXT h;
+ END LOOP;
+
+ IF usr_view_start.value IS NULL THEN
+ RETURN;
+ END IF;
+
+ IF usr_view_age.value IS NOT NULL THEN
+ -- User opted in and supplied a retention age
+ IF oils_json_to_text(usr_view_age.value)::INTERVAL > AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ) THEN
+ view_age := AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ);
+ ELSE
+ view_age := oils_json_to_text(usr_view_age.value)::INTERVAL;
+ END IF;
+ ELSE
+ -- User opted in
+ view_age := AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ);
+ END IF;
+
+ IF usr_view_count.value IS NOT NULL THEN
+ view_count := oils_json_to_text(usr_view_count.value)::INT;
+ ELSE
+ view_count := 1000;
+ END IF;
+
+ -- show some fulfilled/canceled holds
+ FOR h IN
+ SELECT *
+ FROM action.hold_request
+ WHERE usr = usr_id
+ AND ( fulfillment_time IS NOT NULL OR cancel_time IS NOT NULL )
+ AND COALESCE(fulfillment_time, cancel_time) > NOW() - view_age
+ ORDER BY COALESCE(fulfillment_time, cancel_time) DESC
+ LIMIT view_count
+ LOOP
+ RETURN NEXT h;
+ END LOOP;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE TABLE action.aged_hold_request (
+ usr_post_code TEXT,
+ usr_home_ou INT NOT NULL,
+ usr_profile INT NOT NULL,
+ usr_birth_year INT,
+ staff_placed BOOLEAN NOT NULL,
+ LIKE action.hold_request
+);
+ALTER TABLE action.aged_hold_request
+ ADD PRIMARY KEY (id),
+ DROP COLUMN usr,
+ DROP COLUMN requestor,
+ DROP COLUMN sms_carrier,
+ ALTER COLUMN phone_notify TYPE BOOLEAN
+ USING CASE WHEN phone_notify IS NULL OR phone_notify = '' THEN FALSE ELSE TRUE END,
+ ALTER COLUMN sms_notify TYPE BOOLEAN
+ USING CASE WHEN sms_notify IS NULL OR sms_notify = '' THEN FALSE ELSE TRUE END,
+ ALTER COLUMN phone_notify SET NOT NULL,
+ ALTER COLUMN sms_notify SET NOT NULL;
+CREATE INDEX aged_hold_request_target_idx ON action.aged_hold_request (target);
+CREATE INDEX aged_hold_request_pickup_lib_idx ON action.aged_hold_request (pickup_lib);
+CREATE INDEX aged_hold_request_current_copy_idx ON action.aged_hold_request (current_copy);
+CREATE INDEX aged_hold_request_fulfillment_staff_idx ON action.aged_hold_request ( fulfillment_staff );
+
+CREATE OR REPLACE VIEW action.all_hold_request AS
+ SELECT DISTINCT
+ COALESCE(a.post_code, b.post_code) AS usr_post_code,
+ p.home_ou AS usr_home_ou,
+ p.profile AS usr_profile,
+ EXTRACT(YEAR FROM p.dob)::INT AS usr_birth_year,
+ CAST(ahr.requestor <> ahr.usr AS BOOLEAN) AS staff_placed,
+ ahr.id,
+ ahr.request_time,
+ ahr.capture_time,
+ ahr.fulfillment_time,
+ ahr.checkin_time,
+ ahr.return_time,
+ ahr.prev_check_time,
+ ahr.expire_time,
+ ahr.cancel_time,
+ ahr.cancel_cause,
+ ahr.cancel_note,
+ ahr.target,
+ ahr.current_copy,
+ ahr.fulfillment_staff,
+ ahr.fulfillment_lib,
+ ahr.request_lib,
+ ahr.selection_ou,
+ ahr.selection_depth,
+ ahr.pickup_lib,
+ ahr.hold_type,
+ ahr.holdable_formats,
+ CASE
+ WHEN ahr.phone_notify IS NULL THEN FALSE
+ WHEN ahr.phone_notify = '' THEN FALSE
+ ELSE TRUE
+ END AS phone_notify,
+ ahr.email_notify,
+ CASE
+ WHEN ahr.sms_notify IS NULL THEN FALSE
+ WHEN ahr.sms_notify = '' THEN FALSE
+ ELSE TRUE
+ END AS sms_notify,
+ ahr.frozen,
+ ahr.thaw_date,
+ ahr.shelf_time,
+ ahr.cut_in_line,
+ ahr.mint_condition,
+ ahr.shelf_expire_time,
+ ahr.current_shelf_lib
+ FROM action.hold_request ahr
+ JOIN actor.usr p ON (ahr.usr = p.id)
+ LEFT JOIN actor.usr_address a ON (p.mailing_address = a.id)
+ LEFT JOIN actor.usr_address b ON (p.billing_address = b.id)
+ UNION ALL
+ SELECT
+ usr_post_code,
+ usr_home_ou,
+ usr_profile,
+ usr_birth_year,
+ staff_placed,
+ id,
+ request_time,
+ capture_time,
+ fulfillment_time,
+ checkin_time,
+ return_time,
+ prev_check_time,
+ expire_time,
+ cancel_time,
+ cancel_cause,
+ cancel_note,
+ target,
+ current_copy,
+ fulfillment_staff,
+ fulfillment_lib,
+ request_lib,
+ selection_ou,
+ selection_depth,
+ pickup_lib,
+ hold_type,
+ holdable_formats,
+ phone_notify,
+ email_notify,
+ sms_notify,
+ frozen,
+ thaw_date,
+ shelf_time,
+ cut_in_line,
+ mint_condition,
+ shelf_expire_time,
+ current_shelf_lib
+ FROM action.aged_hold_request;
+
+CREATE OR REPLACE FUNCTION action.age_hold_on_delete () RETURNS TRIGGER AS $$
+DECLARE
+BEGIN
+ -- Archive a copy of the old row to action.aged_hold_request
+
+ INSERT INTO action.aged_hold_request
+ (usr_post_code,
+ usr_home_ou,
+ usr_profile,
+ usr_birth_year,
+ staff_placed,
+ id,
+ request_time,
+ capture_time,
+ fulfillment_time,
+ checkin_time,
+ return_time,
+ prev_check_time,
+ expire_time,
+ cancel_time,
+ cancel_cause,
+ cancel_note,
+ target,
+ current_copy,
+ fulfillment_staff,
+ fulfillment_lib,
+ request_lib,
+ selection_ou,
+ selection_depth,
+ pickup_lib,
+ hold_type,
+ holdable_formats,
+ phone_notify,
+ email_notify,
+ sms_notify,
+ frozen,
+ thaw_date,
+ shelf_time,
+ cut_in_line,
+ mint_condition,
+ shelf_expire_time,
+ current_shelf_lib)
+ SELECT
+ usr_post_code,
+ usr_home_ou,
+ usr_profile,
+ usr_birth_year,
+ staff_placed,
+ id,
+ request_time,
+ capture_time,
+ fulfillment_time,
+ checkin_time,
+ return_time,
+ prev_check_time,
+ expire_time,
+ cancel_time,
+ cancel_cause,
+ cancel_note,
+ target,
+ current_copy,
+ fulfillment_staff,
+ fulfillment_lib,
+ request_lib,
+ selection_ou,
+ selection_depth,
+ pickup_lib,
+ hold_type,
+ holdable_formats,
+ phone_notify,
+ email_notify,
+ sms_notify,
+ frozen,
+ thaw_date,
+ shelf_time,
+ cut_in_line,
+ mint_condition,
+ shelf_expire_time,
+ current_shelf_lib
+ FROM action.all_hold_request WHERE id = OLD.id;
+
+ RETURN OLD;
+END;
+$$ LANGUAGE 'plpgsql';
+
+CREATE TRIGGER action_hold_request_aging_tgr
+ BEFORE DELETE ON action.hold_request
+ FOR EACH ROW
+ EXECUTE PROCEDURE action.age_hold_on_delete ();
+
+
+SELECT evergreen.upgrade_deps_block_check('0798', :eg_version);
+
+INSERT INTO config.global_flag (name, label)
+ VALUES (
+ 'history.circ.retention_uses_last_finished',
+ oils_i18n_gettext(
+ 'history.circ.retention_uses_last_finished',
+ 'Historical Circulations use most recent xact_finish date instead of last circ''s.',
+ 'cgf',
+ 'label'
+ )
+ ),(
+ 'history.circ.retention_age_is_min',
+ oils_i18n_gettext(
+ 'history.circ.retention_age_is_min',
+ 'Historical Circulations are kept for global retention age at a minimum, regardless of user preferences.',
+ 'cgf',
+ 'label'
+ )
+ );
+
+
+-- Drop old variants
+DROP FUNCTION IF EXISTS action.circ_chain(INTEGER);
+DROP FUNCTION IF EXISTS action.summarize_circ_chain(INTEGER);
+
+CREATE OR REPLACE FUNCTION action.circ_chain ( ctx_circ_id BIGINT ) RETURNS SETOF action.circulation AS $$
+DECLARE
+ tmp_circ action.circulation%ROWTYPE;
+ circ_0 action.circulation%ROWTYPE;
+BEGIN
+
+ SELECT INTO tmp_circ * FROM action.circulation WHERE id = ctx_circ_id;
+
+ IF tmp_circ IS NULL THEN
+ RETURN NEXT tmp_circ;
+ END IF;
+ circ_0 := tmp_circ;
+
+ -- find the front of the chain
+ WHILE TRUE LOOP
+ SELECT INTO tmp_circ * FROM action.circulation WHERE id = tmp_circ.parent_circ;
+ IF tmp_circ IS NULL THEN
+ EXIT;
+ END IF;
+ circ_0 := tmp_circ;
+ END LOOP;
+
+ -- now send the circs to the caller, oldest to newest
+ tmp_circ := circ_0;
+ WHILE TRUE LOOP
+ IF tmp_circ IS NULL THEN
+ EXIT;
+ END IF;
+ RETURN NEXT tmp_circ;
+ SELECT INTO tmp_circ * FROM action.circulation WHERE parent_circ = tmp_circ.id;
+ END LOOP;
+
+END;
+$$ LANGUAGE 'plpgsql';
+
+CREATE OR REPLACE FUNCTION action.summarize_circ_chain ( ctx_circ_id BIGINT ) RETURNS action.circ_chain_summary AS $$
+
+DECLARE
+
+ -- first circ in the chain
+ circ_0 action.circulation%ROWTYPE;
+
+ -- last circ in the chain
+ circ_n action.circulation%ROWTYPE;
+
+ -- circ chain under construction
+ chain action.circ_chain_summary;
+ tmp_circ action.circulation%ROWTYPE;
+
+BEGIN
+
+ chain.num_circs := 0;
+ FOR tmp_circ IN SELECT * FROM action.circ_chain(ctx_circ_id) LOOP
+
+ IF chain.num_circs = 0 THEN
+ circ_0 := tmp_circ;
+ END IF;
+
+ chain.num_circs := chain.num_circs + 1;
+ circ_n := tmp_circ;
+ END LOOP;
+
+ chain.start_time := circ_0.xact_start;
+ chain.last_stop_fines := circ_n.stop_fines;
+ chain.last_stop_fines_time := circ_n.stop_fines_time;
+ chain.last_checkin_time := circ_n.checkin_time;
+ chain.last_checkin_scan_time := circ_n.checkin_scan_time;
+ SELECT INTO chain.checkout_workstation name FROM actor.workstation WHERE id = circ_0.workstation;
+ SELECT INTO chain.last_checkin_workstation name FROM actor.workstation WHERE id = circ_n.checkin_workstation;
+
+ IF chain.num_circs > 1 THEN
+ chain.last_renewal_time := circ_n.xact_start;
+ SELECT INTO chain.last_renewal_workstation name FROM actor.workstation WHERE id = circ_n.workstation;
+ END IF;
+
+ RETURN chain;
+
+END;
+$$ LANGUAGE 'plpgsql';
+
+CREATE OR REPLACE FUNCTION action.purge_circulations () RETURNS INT AS $func$
+DECLARE
+ usr_keep_age actor.usr_setting%ROWTYPE;
+ usr_keep_start actor.usr_setting%ROWTYPE;
+ org_keep_age INTERVAL;
+ org_use_last BOOL = false;
+ org_age_is_min BOOL = false;
+ org_keep_count INT;
+
+ keep_age INTERVAL;
+
+ target_acp RECORD;
+ circ_chain_head action.circulation%ROWTYPE;
+ circ_chain_tail action.circulation%ROWTYPE;
+
+ count_purged INT;
+ num_incomplete INT;
+
+ last_finished TIMESTAMP WITH TIME ZONE;
+BEGIN
+
+ count_purged := 0;
+
+ SELECT value::INTERVAL INTO org_keep_age FROM config.global_flag WHERE name = 'history.circ.retention_age' AND enabled;
+
+ SELECT value::INT INTO org_keep_count FROM config.global_flag WHERE name = 'history.circ.retention_count' AND enabled;
+ IF org_keep_count IS NULL THEN
+ RETURN count_purged; -- Gimme a count to keep, or I keep them all, forever
+ END IF;
+
+ SELECT enabled INTO org_use_last FROM config.global_flag WHERE name = 'history.circ.retention_uses_last_finished';
+ SELECT enabled INTO org_age_is_min FROM config.global_flag WHERE name = 'history.circ.retention_age_is_min';
+
+ -- First, find copies with more than keep_count non-renewal circs
+ FOR target_acp IN
+ SELECT target_copy,
+ COUNT(*) AS total_real_circs
+ FROM action.circulation
+ WHERE parent_circ IS NULL
+ AND xact_finish IS NOT NULL
+ GROUP BY target_copy
+ HAVING COUNT(*) > org_keep_count
+ LOOP
+ -- And, for those, select circs that are finished and older than keep_age
+ FOR circ_chain_head IN
+ -- For reference, the subquery uses a window function to order the circs newest to oldest and number them
+ -- The outer query then uses that information to skip the most recent set the library wants to keep
+ -- End result is we don't care what order they come out in, as they are all potentials for deletion.
+ SELECT ac.* FROM action.circulation ac JOIN (
+ SELECT rank() OVER (ORDER BY xact_start DESC), ac.id
+ FROM action.circulation ac
+ WHERE ac.target_copy = target_acp.target_copy
+ AND ac.parent_circ IS NULL
+ ORDER BY ac.xact_start ) ranked USING (id)
+ WHERE ranked.rank > org_keep_count
+ LOOP
+
+ SELECT * INTO circ_chain_tail FROM action.circ_chain(circ_chain_head.id) ORDER BY xact_start DESC LIMIT 1;
+ SELECT COUNT(CASE WHEN xact_finish IS NULL THEN 1 ELSE NULL END), MAX(xact_finish) INTO num_incomplete, last_finished FROM action.circ_chain(circ_chain_head.id);
+ CONTINUE WHEN circ_chain_tail.xact_finish IS NULL OR num_incomplete > 0;
+
+ IF NOT org_use_last THEN
+ last_finished := circ_chain_tail.xact_finish;
+ END IF;
+
+ -- Now get the user settings, if any, to block purging if the user wants to keep more circs
+ usr_keep_age.value := NULL;
+ SELECT * INTO usr_keep_age FROM actor.usr_setting WHERE usr = circ_chain_head.usr AND name = 'history.circ.retention_age';
+
+ usr_keep_start.value := NULL;
+ SELECT * INTO usr_keep_start FROM actor.usr_setting WHERE usr = circ_chain_head.usr AND name = 'history.circ.retention_start';
+
+ IF usr_keep_age.value IS NOT NULL AND usr_keep_start.value IS NOT NULL THEN
+ IF oils_json_to_text(usr_keep_age.value)::INTERVAL > AGE(NOW(), oils_json_to_text(usr_keep_start.value)::TIMESTAMPTZ) THEN
+ keep_age := AGE(NOW(), oils_json_to_text(usr_keep_start.value)::TIMESTAMPTZ);
+ ELSE
+ keep_age := oils_json_to_text(usr_keep_age.value)::INTERVAL;
+ END IF;
+ ELSIF usr_keep_start.value IS NOT NULL THEN
+ keep_age := AGE(NOW(), oils_json_to_text(usr_keep_start.value)::TIMESTAMPTZ);
+ ELSE
+ keep_age := COALESCE( org_keep_age, '2000 years'::INTERVAL );
+ END IF;
+
+ IF org_age_is_min THEN
+ keep_age := GREATEST( keep_age, org_keep_age );
+ END IF;
+
+ CONTINUE WHEN AGE(NOW(), last_finished) < keep_age;
+
+ -- We've passed the purging tests, purge the circ chain starting at the end
+ -- A trigger should auto-purge the rest of the chain.
+ DELETE FROM action.circulation WHERE id = circ_chain_tail.id;
+
+ count_purged := count_purged + 1;
+
+ END LOOP;
+ END LOOP;
+
+ return count_purged;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+SELECT evergreen.upgrade_deps_block_check('0799', :eg_version);
+
+-- allow state to be null
+ALTER TABLE actor.usr_address ALTER COLUMN state DROP NOT NULL;
+
+-- create new YAOUS
+INSERT into config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+ VALUES (
+ 'ui.patron.edit.au.state.require',
+ 'gui',
+ oils_i18n_gettext(
+ 'ui.patron.edit.au.state.require',
+ 'Require State field on patron registration',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.patron.edit.au.state.require',
+ 'The State field will be required on the patron registration screen.',
+ 'coust',
+ 'description'
+ ),
+ 'bool'
+ );
+
+INSERT into config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+ VALUES (
+ 'ui.patron.edit.au.state.show',
+ 'gui',
+ oils_i18n_gettext(
+ 'ui.patron.edit.au.state.show',
+ 'Show State field on patron registration',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.patron.edit.au.state.show',
+ 'The State field will be shown on the patron registration screen. Showing a field makes it appear with required fields even when not required. If the field is required this setting is ignored.',
+ 'coust',
+ 'description'
+ ),
+ 'bool'
+ );
+
+INSERT into config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+ VALUES (
+ 'ui.patron.edit.au.state.suggest',
+ 'gui',
+ oils_i18n_gettext(
+ 'ui.patron.edit.au.state.suggest',
+ 'Suggest State field on patron registration',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.patron.edit.au.state.suggest',
+ 'The State field will be suggested on the patron registration screen. Suggesting a field makes it appear when suggested fields are shown. If the field is shown or required this setting is ignored.',
+ 'coust',
+ 'description'
+ ),
+ 'bool'
+ );
+
+
+SELECT evergreen.upgrade_deps_block_check('0801', :eg_version);
+
+INSERT into config.org_unit_setting_type
+( name, grp, label, description, datatype, fm_class ) VALUES
+( 'ui.patron.edit.ac.barcode.regex', 'gui',
+ oils_i18n_gettext('ui.patron.edit.ac.barcode.regex',
+ 'Regex for barcodes on patron registration',
+ 'coust', 'label'),
+ oils_i18n_gettext('ui.patron.edit.ac.barcode.regex',
+ 'The Regular Expression for validation on barcodes in patron registration.',
+ 'coust', 'description'),
+ 'string', null);
+
+
+SELECT evergreen.upgrade_deps_block_check('0802', :eg_version);
+
+CREATE OR REPLACE FUNCTION authority.normalize_heading( marcxml TEXT, no_thesaurus BOOL ) RETURNS TEXT AS $func$
+DECLARE
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ sf_node TEXT;
+ tag_node TEXT;
+ thes_code TEXT;
+ cset INT;
+ heading_text TEXT;
+ tmp_text TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT;
+BEGIN
+ SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+ IF cset IS NULL THEN
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]))
+ LIMIT 1;
+ END IF;
+
+ thes_code := vandelay.marc21_extract_fixed_field(marcxml,'Subj');
+ IF thes_code IS NULL THEN
+ thes_code := '|';
+ ELSIF thes_code = 'z' THEN
+ thes_code := COALESCE( oils_xpath_string('//*[@tag="040"]/*[@code="f"][1]', marcxml), '' );
+ END IF;
+
+ heading_text := '';
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset AND main_entry IS NULL LOOP
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+ first_sf := TRUE;
+
+ FOR tag_node IN SELECT unnest(oils_xpath('//*[@tag="'||tag_used||'"]',marcxml)) LOOP
+ FOR sf_node IN SELECT unnest(oils_xpath('//*[contains("'||acsaf.sf_list||'", at code)]',tag_node)) LOOP
+
+ tmp_text := oils_xpath_string('.', sf_node);
+ sf := oils_xpath_string('./@code', sf_node);
+
+ IF first_sf AND tmp_text IS NOT NULL AND nfi_used IS NOT NULL THEN
+
+ tmp_text := SUBSTRING(
+ tmp_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('./@ind'||nfi_used, tag_node),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ END IF;
+
+ first_sf := FALSE;
+
+ IF tmp_text IS NOT NULL AND tmp_text <> '' THEN
+ heading_text := heading_text || E'\u2021' || sf || ' ' || tmp_text;
+ END IF;
+ END LOOP;
+
+ EXIT WHEN heading_text <> '';
+ END LOOP;
+
+ EXIT WHEN heading_text <> '';
+ END LOOP;
+
+ IF heading_text <> '' THEN
+ IF no_thesaurus IS TRUE THEN
+ heading_text := tag_used || ' ' || public.naco_normalize(heading_text);
+ ELSE
+ heading_text := tag_used || '_' || COALESCE(nfi_used,'-') || '_' || thes_code || ' ' || public.naco_normalize(heading_text);
+ END IF;
+ ELSE
+ heading_text := 'NOHEADING_' || thes_code || ' ' || MD5(marcxml);
+ END IF;
+
+ RETURN heading_text;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION authority.simple_heading_set( marcxml TEXT ) RETURNS SETOF authority.simple_heading AS $func$
+DECLARE
+ res authority.simple_heading%ROWTYPE;
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ cset INT;
+ heading_text TEXT;
+ sort_text TEXT;
+ tmp_text TEXT;
+ tmp_xml TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml)::INT;
+BEGIN
+
+ res.record := auth_id;
+
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]) )
+ LIMIT 1;
+
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset LOOP
+
+ res.atag := acsaf.id;
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+
+ FOR tmp_xml IN SELECT UNNEST(XPATH('//*[@tag="'||tag_used||'"]', marcxml::XML)) LOOP
+
+ heading_text := public.naco_normalize(
+ COALESCE(
+ oils_xpath_string('//*[contains("'||acsaf.sf_list||'", at code)]',tmp_xml::TEXT, ' '),
+ ''
+ )
+ );
+
+ IF nfi_used IS NOT NULL THEN
+
+ sort_text := SUBSTRING(
+ heading_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('./@ind'||nfi_used, tmp_xml::TEXT),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ ELSE
+ sort_text := heading_text;
+ END IF;
+
+ IF heading_text IS NOT NULL AND heading_text <> '' THEN
+ res.value := heading_text;
+ res.sort_value := sort_text;
+ RETURN NEXT res;
+ END IF;
+
+ END LOOP;
+
+ END LOOP;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0805', :eg_version);
+
+INSERT INTO config.global_flag (name, label, enabled)
+ VALUES (
+ 'circ.desk_renewal.use_original_circ_lib',
+ oils_i18n_gettext(
+ 'circ.desk_renewal.use_original_circ_lib',
+ 'Circ: Use original circulation library on desk renewal instead of user home library',
+ 'cgf',
+ 'label'
+ ),
+ FALSE
+ );
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0806', :eg_version);
+
+INSERT INTO action.hold_request_cancel_cause (id,label)
+ VALUES (7,'Patron via SIP');
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0807', :eg_version);
+
+ALTER TABLE config.usr_setting_type
+ ADD COLUMN reg_default TEXT;
+
+
+SELECT evergreen.upgrade_deps_block_check('0809', :eg_version);
+
+ALTER TABLE actor.org_address ALTER COLUMN state DROP NOT NULL;
+
+
+-- Evergreen DB patch 0812.data.add_library_info_url_OUS.sql
+--
+-- Adds YAOUS for enabling information links from the TPAC to a library URL
+--
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0812', :eg_version);
+
+-- FIXME: add/check SQL statements to perform the upgrade
+INSERT into config.org_unit_setting_type
+( name, grp, label, description, datatype, fm_class ) VALUES
+( 'lib.info_url', 'lib',
+ oils_i18n_gettext('lib.info_url',
+ 'Library information URL (such as "http://example.com/about.html")',
+ 'coust', 'label'),
+ oils_i18n_gettext('lib.info_url',
+ 'URL for information on this library, such as contact information, hours of operation, and directions. If set, the library name in the copy details section links to that URL. Use a complete URL, such as "http://example.com/hours.html".',
+ 'coust', 'description'),
+ 'string', null)
+;
+
+
+SELECT evergreen.upgrade_deps_block_check('0813', :eg_version);
+
+-- Don't require state in the auditor tracking for user addresses
+
+ALTER TABLE auditor.actor_usr_address_history ALTER COLUMN state DROP NOT NULL;
+
+-- Change constraint on actor.org_unit_setting_log to be deferrable initially
+
+ALTER TABLE config.org_unit_setting_type_log
+ DROP CONSTRAINT org_unit_setting_type_log_field_name_fkey,
+ ADD CONSTRAINT org_unit_setting_type_log_field_name_fkey FOREIGN KEY (field_name)
+ REFERENCES config.org_unit_setting_type (name) MATCH SIMPLE
+ ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED;
+
+-- Fix names in the org unit setting configuration
+
+UPDATE config.org_unit_setting_type SET name = overlay(name placing 'aua' from 16 for 2) where name like 'ui.patron.edit.au.state.%';
+
+-- Fix names if they have already been set in the editor
+
+UPDATE actor.org_unit_setting SET name = overlay(name placing 'aua' from 16 for 2) where name like 'ui.patron.edit.au.state.%';
+
+-- and the logs too
+
+UPDATE config.org_unit_setting_type_log SET field_name = overlay(field_name placing 'aua' from 16 for 2) where field_name like 'ui.patron.edit.au.state.%';
+
+
+SELECT evergreen.upgrade_deps_block_check('0814', :eg_version);
+
+UPDATE permission.perm_list
+SET description = 'Allow a user to delete a provider'
+WHERE code = 'DELETE_PROVIDER';
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0815', :eg_version);
+
+ALTER TABLE authority.control_set_authority_field
+ ADD COLUMN linking_subfield CHAR(1);
+
+UPDATE authority.control_set_authority_field
+ SET linking_subfield = '0' WHERE main_entry IS NOT NULL;
+
+CREATE TABLE authority.authority_linking (
+ id BIGSERIAL PRIMARY KEY,
+ source BIGINT REFERENCES authority.record_entry (id) NOT NULL,
+ target BIGINT REFERENCES authority.record_entry (id) NOT NULL,
+ field INT REFERENCES authority.control_set_authority_field (id) NOT NULL
+);
+
+-- Given an authority record's ID, control set ID (if known), and marc::XML,
+-- return all links to other authority records in the form of rows that
+-- can be inserted into authority.authority_linking.
+CREATE OR REPLACE FUNCTION authority.calculate_authority_linking(
+ rec_id BIGINT, rec_control_set INT, rec_marc_xml XML
+) RETURNS SETOF authority.authority_linking AS $func$
+DECLARE
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ link TEXT;
+ aal authority.authority_linking%ROWTYPE;
+BEGIN
+ IF rec_control_set IS NULL THEN
+ -- No control_set on record? Guess at one
+ SELECT control_set INTO rec_control_set
+ FROM authority.control_set_authority_field
+ WHERE tag IN (
+ SELECT UNNEST(
+ XPATH('//*[starts-with(@tag,"1")]/@tag',rec_marc_xml::XML)::TEXT[]
+ )
+ ) LIMIT 1;
+
+ IF NOT FOUND THEN
+ RAISE WARNING 'Could not even guess at control set for authority record %', rec_id;
+ RETURN;
+ END IF;
+ END IF;
+
+ aal.source := rec_id;
+
+ FOR acsaf IN
+ SELECT * FROM authority.control_set_authority_field
+ WHERE control_set = rec_control_set
+ AND linking_subfield IS NOT NULL
+ AND main_entry IS NOT NULL
+ LOOP
+ link := SUBSTRING(
+ (XPATH('//*[@tag="' || acsaf.tag || '"]/*[@code="' ||
+ acsaf.linking_subfield || '"]/text()', rec_marc_xml))[1]::TEXT,
+ '\d+$'
+ );
+
+ -- Ignore links that are null, malformed, circular, or point to
+ -- non-existent authority records.
+ IF link IS NOT NULL AND link::BIGINT <> rec_id THEN
+ PERFORM * FROM authority.record_entry WHERE id = link::BIGINT;
+ IF FOUND THEN
+ aal.target := link::BIGINT;
+ aal.field := acsaf.id;
+ RETURN NEXT aal;
+ END IF;
+ END IF;
+ END LOOP;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+-- AFTER UPDATE OR INSERT trigger for authority.record_entry
+CREATE OR REPLACE FUNCTION authority.indexing_ingest_or_delete () RETURNS TRIGGER AS $func$
+BEGIN
+
+ IF NEW.deleted IS TRUE THEN -- If this authority is deleted
+ DELETE FROM authority.bib_linking WHERE authority = NEW.id; -- Avoid updating fields in bibs that are no longer visible
+ DELETE FROM authority.full_rec WHERE record = NEW.id; -- Avoid validating fields against deleted authority records
+ DELETE FROM authority.simple_heading WHERE record = NEW.id;
+ -- Should remove matching $0 from controlled fields at the same time?
+
+ -- XXX What do we about the actual linking subfields present in
+ -- authority records that target this one when this happens?
+ DELETE FROM authority.authority_linking
+ WHERE source = NEW.id OR target = NEW.id;
+
+ RETURN NEW; -- and we're done
+ END IF;
+
+ IF TG_OP = 'UPDATE' THEN -- re-ingest?
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled;
+
+ IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
+ RETURN NEW;
+ END IF;
+
+ -- Propagate these updates to any linked bib records
+ PERFORM authority.propagate_changes(NEW.id) FROM authority.record_entry WHERE id = NEW.id;
+
+ DELETE FROM authority.simple_heading WHERE record = NEW.id;
+ DELETE FROM authority.authority_linking WHERE source = NEW.id;
+ END IF;
+
+ INSERT INTO authority.authority_linking (source, target, field)
+ SELECT source, target, field FROM authority.calculate_authority_linking(
+ NEW.id, NEW.control_set, NEW.marc::XML
+ );
+
+ INSERT INTO authority.simple_heading (record,atag,value,sort_value)
+ SELECT record, atag, value, sort_value FROM authority.simple_heading_set(NEW.marc);
+
+ -- Flatten and insert the afr data
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_full_rec' AND enabled;
+ IF NOT FOUND THEN
+ PERFORM authority.reingest_authority_full_rec(NEW.id);
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_rec_descriptor' AND enabled;
+ IF NOT FOUND THEN
+ PERFORM authority.reingest_authority_rec_descriptor(NEW.id);
+ END IF;
+ END IF;
+
+ RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0816', :eg_version);
+
+-- To avoid problems with altering a table column after doing an
+-- update.
+ALTER TABLE authority.control_set_authority_field
+ DISABLE TRIGGER ALL;
+
+ALTER TABLE authority.control_set_authority_field
+ ADD COLUMN display_sf_list TEXT;
+
+UPDATE authority.control_set_authority_field
+ SET display_sf_list = REGEXP_REPLACE(sf_list, '[w254]', '', 'g');
+
+ALTER TABLE authority.control_set_authority_field
+ ALTER COLUMN display_sf_list SET NOT NULL;
+
+ALTER TABLE authority.control_set_authority_field
+ ENABLE TRIGGER ALL;
+
+ALTER TABLE metabib.browse_entry_def_map
+ ADD COLUMN authority BIGINT REFERENCES authority.record_entry (id)
+ ON DELETE SET NULL;
+
+ALTER TABLE config.metabib_field ADD COLUMN authority_xpath TEXT;
+ALTER TABLE config.metabib_field ADD COLUMN browse_sort_xpath TEXT;
+
+UPDATE config.metabib_field
+ SET authority_xpath = '//@xlink:href'
+ WHERE
+ format = 'mods32' AND
+ field_class IN ('subject','series','title','author') AND
+ browse_field IS TRUE;
+
+ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE authority BIGINT;
+ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE sort_value TEXT;
+
+CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+DECLARE
+ fclass RECORD;
+ ind_data metabib.field_entry_template%ROWTYPE;
+ mbe_row metabib.browse_entry%ROWTYPE;
+ mbe_id BIGINT;
+ b_skip_facet BOOL;
+ b_skip_browse BOOL;
+ b_skip_search BOOL;
+ value_prepped TEXT;
+BEGIN
+
+ SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
+ SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
+ SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
+
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
+ IF NOT FOUND THEN
+ IF NOT b_skip_search THEN
+ FOR fclass IN SELECT * FROM config.metabib_class LOOP
+ -- RAISE NOTICE 'Emptying out %', fclass.name;
+ EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
+ END LOOP;
+ END IF;
+ IF NOT b_skip_facet THEN
+ DELETE FROM metabib.facet_entry WHERE source = bib_id;
+ END IF;
+ IF NOT b_skip_browse THEN
+ DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
+ END IF;
+ END IF;
+
+ FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+ IF ind_data.field < 0 THEN
+ ind_data.field = -1 * ind_data.field;
+ END IF;
+
+ IF ind_data.facet_field AND NOT b_skip_facet THEN
+ INSERT INTO metabib.facet_entry (field, source, value)
+ VALUES (ind_data.field, ind_data.source, ind_data.value);
+ END IF;
+
+ IF ind_data.browse_field AND NOT b_skip_browse THEN
+ -- A caveat about this SELECT: this should take care of replacing
+ -- old mbe rows when data changes, but not if normalization (by
+ -- which I mean specifically the output of
+ -- evergreen.oils_tsearch2()) changes. It may or may not be
+ -- expensive to add a comparison of index_vector to index_vector
+ -- to the WHERE clause below.
+
+ value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
+ SELECT INTO mbe_row * FROM metabib.browse_entry
+ WHERE value = value_prepped AND sort_value = ind_data.sort_value;
+
+ IF FOUND THEN
+ mbe_id := mbe_row.id;
+ ELSE
+ INSERT INTO metabib.browse_entry
+ ( value, sort_value ) VALUES
+ ( value_prepped, ind_data.sort_value );
+
+ mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
+ END IF;
+
+ INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
+ VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
+ END IF;
+
+ IF ind_data.search_field AND NOT b_skip_search THEN
+ EXECUTE $$
+ INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
+ VALUES ($$ ||
+ quote_literal(ind_data.field) || $$, $$ ||
+ quote_literal(ind_data.source) || $$, $$ ||
+ quote_literal(ind_data.value) ||
+ $$);$$;
+ END IF;
+
+ END LOOP;
+
+ IF NOT b_skip_search THEN
+ PERFORM metabib.update_combined_index_vectors(bib_id);
+ END IF;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) 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;
+ 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;
+BEGIN
+
+ -- 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 ORDER BY format LOOP
+
+ 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*<';
+
+ curr_text := ARRAY_TO_STRING(
+ oils_xpath( '//text()',
+ REGEXP_REPLACE( -- This escapes all &s not followed by "amp;". Data ise returned from oils_xpath (above) in UTF-8, not entity encoded
+ REGEXP_REPLACE( -- This escapes embeded <s
+ xml_node,
+ $re$(>[^<]+)(<)([^>]+<)$re$,
+ E'\\1<\\3',
+ 'g'
+ ),
+ '&(?!amp;)',
+ '&',
+ 'g'
+ )
+ ),
+ ' '
+ );
+
+ 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.search_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;
+ RETURN NEXT output_row;
+ output_row.browse_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;
+
+ 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;
+
+
+-- 953.data.MODS32-xsl.sql
+UPDATE config.xml_transform SET xslt=$$<?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:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@ind2>0">
+ <nonSort>
+ <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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>
+ <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>
+ <title>
+ <xsl:value-of select="$title"/>
+ </title>
+ <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>
+ </titleNonfiling>
+ </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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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', at 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, at ind1)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind1)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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>
+ </xsl:for-each>
+ <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="nameABCDQ">
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="punctuation">
+ <xsl:text>:,;/ </xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="termsOfAddress"></xsl:call-template>
+ <xsl:call-template name="nameDate"></xsl:call-template>
+ </xsl:template>
+ <xsl:template name="nameACDEQ">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">acdeq</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:template>
+ <xsl:template name="constituentOrRelatedType">
+ <xsl:if test="@ind2=2">
+ <xsl:attribute name="type">constituent</xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="relatedTitle">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedTitle76X-78X">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='p']">
+ <titleInfo type="abbreviated">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='s']">
+ <titleInfo type="uniform">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedOriginInfo">
+ <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
+ <originInfo>
+ <xsl:if test="@tag=775">
+ <xsl:for-each select="marc:subfield[@code='f']">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">code</xsl:attribute>
+ <xsl:attribute name="authority">marcgac</xsl:attribute>
+ <xsl:value-of select="."></xsl:value-of>
+ </placeTerm>
+ </place>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <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:template>
+ <xsl:template name="relatedLanguage">
+ <xsl:for-each select="marc:subfield[@code='e']">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="nameDate">
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <namePart type="date">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."></xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="subjectAuthority">
+ <xsl:if test="@ind2!=4">
+ <xsl:if test="@ind2!=' '">
+ <xsl:if test="@ind2!=8">
+ <xsl:if test="@ind2!=9">
+ <xsl:attribute name="authority">
+ <xsl:choose>
+ <xsl:when test="@ind2=0">lcsh</xsl:when>
+ <xsl:when test="@ind2=1">lcshac</xsl:when>
+ <xsl:when test="@ind2=2">mesh</xsl:when>
+ <!-- 1/04 fix -->
+ <xsl:when test="@ind2=3">nal</xsl:when>
+ <xsl:when test="@ind2=5">csh</xsl:when>
+ <xsl:when test="@ind2=6">rvm</xsl:when>
+ <xsl:when test="@ind2=7">
+ <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:if>
+ </xsl:if>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="subjectAnyOrder">
+ <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
+ <xsl:choose>
+ <xsl:when test="@code='v'">
+ <xsl:call-template name="subjectGenre"></xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@code='x'">
+ <xsl:call-template name="subjectTopic"></xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@code='y'">
+ <xsl:call-template name="subjectTemporalY"></xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@code='z'">
+ <xsl:call-template name="subjectGeographicZ"></xsl:call-template>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="specialSubfieldSelect">
+ <xsl:param name="anyCodes"></xsl:param>
+ <xsl:param name="axis"></xsl:param>
+ <xsl:param name="beforeCodes"></xsl:param>
+ <xsl:param name="afterCodes"></xsl:param>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="contains($anyCodes, @code) or (contains($beforeCodes, at code) and following-sibling::marc:subfield[@code=$axis]) or (contains($afterCodes, at code) and preceding-sibling::marc:subfield[@code=$axis])">
+ <xsl:value-of select="text()"></xsl:value-of>
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+ </xsl:template>
+
+ <!-- 3.2 change tmee 6xx $v genre -->
+ <xsl:template match="marc:datafield[@tag=600]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <name type="personal">
+ <xsl:call-template name="uri" />
+ <xsl:call-template name="termsOfAddress"></xsl:call-template>
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="nameDate"></xsl:call-template>
+ <xsl:call-template name="affiliation"></xsl:call-template>
+ <xsl:call-template name="role"></xsl:call-template>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=610]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <name type="corporate">
+ <xsl:call-template name="uri" />
+ <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:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ <xsl:call-template name="role"></xsl:call-template>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=611]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <name type="conference">
+ <xsl:call-template name="uri" />
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <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>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=630]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <xsl:variable name="titleChop">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">adfhklor</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="@ind1>0">
+ <nonSort>
+ <xsl:value-of select="substring($titleChop,1, at ind1)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at ind1+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>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=650]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <topic>
+ <xsl:call-template name="uri" />
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </topic>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=651]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <geographic>
+ <xsl:call-template name="uri" />
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."></xsl:with-param>
+ </xsl:call-template>
+ </geographic>
+ </xsl:for-each>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=653]">
+ <subject>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <topic>
+ <xsl:call-template name="uri" />
+ <xsl:value-of select="."></xsl:value-of>
+ </topic>
+ </xsl:for-each>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=656]">
+ <subject>
+ <xsl:if test="marc:subfield[@code=2]">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code=2]"></xsl:value-of>
+ </xsl:attribute>
+ </xsl:if>
+ <occupation>
+ <xsl:call-template name="uri" />
+ <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>
+ </occupation>
+ </subject>
+ </xsl:template>
+ <xsl:template name="termsOfAddress">
+ <xsl:if test="marc:subfield[@code='b' or @code='c']">
+ <namePart type="termsOfAddress">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">bc</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="displayLabel">
+ <xsl:if test="marc:subfield[@code='i']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="marc:subfield[@code='i']"></xsl:value-of>
+ </xsl:attribute>
+ </xsl:if>
+ <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:template>
+ <xsl:template name="isInvalid">
+ <xsl:param name="type"/>
+ <xsl:if test="marc:subfield[@code='z'] or marc:subfield[@code='y']">
+ <identifier>
+ <xsl:attribute name="type">
+ <xsl:value-of select="$type"/>
+ </xsl:attribute>
+ <xsl:attribute name="invalid">
+ <xsl:text>yes</xsl:text>
+ </xsl:attribute>
+ <xsl:if test="marc:subfield[@code='z']">
+ <xsl:value-of select="marc:subfield[@code='z']"/>
+ </xsl:if>
+ <xsl:if test="marc:subfield[@code='y']">
+ <xsl:value-of select="marc:subfield[@code='y']"/>
+ </xsl:if>
+ </identifier>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="subtitle">
+ <xsl:if test="marc:subfield[@code='b']">
+ <subTitle>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='b']"/>
+ <!--<xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">b</xsl:with-param>
+ </xsl:call-template>-->
+ </xsl:with-param>
+ </xsl:call-template>
+ </subTitle>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="script">
+ <xsl:param name="scriptCode"></xsl:param>
+ <xsl:attribute name="script">
+ <xsl:choose>
+ <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
+ <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
+ <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
+ <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
+ <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
+ <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:template>
+ <xsl:template name="parsePart">
+ <!-- assumes 773$q= 1:2:3<4
+ with up to 3 levels and one optional start page
+ -->
+ <xsl:variable name="level1">
+ <xsl:choose>
+ <xsl:when test="contains(text(),':')">
+ <!-- 1:2 -->
+ <xsl:value-of select="substring-before(text(),':')"></xsl:value-of>
+ </xsl:when>
+ <xsl:when test="not(contains(text(),':'))">
+ <!-- 1 or 1<3 -->
+ <xsl:if test="contains(text(),'<')">
+ <!-- 1<3 -->
+ <xsl:value-of select="substring-before(text(),'<')"></xsl:value-of>
+ </xsl:if>
+ <xsl:if test="not(contains(text(),'<'))">
+ <!-- 1 -->
+ <xsl:value-of select="text()"></xsl:value-of>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici2">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after(text(),$level1),':')">
+ <xsl:value-of select="substring(substring-after(text(),$level1),2)"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring-after(text(),$level1)"></xsl:value-of>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level2">
+ <xsl:choose>
+ <xsl:when test="contains($sici2,':')">
+ <!-- 2:3<4 -->
+ <xsl:value-of select="substring-before($sici2,':')"></xsl:value-of>
+ </xsl:when>
+ <xsl:when test="contains($sici2,'<')">
+ <!-- 1: 2<4 -->
+ <xsl:value-of select="substring-before($sici2,'<')"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici2"></xsl:value-of>
+ <!-- 1:2 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici3">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
+ <xsl:value-of select="substring(substring-after($sici2,$level2),2)"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring-after($sici2,$level2)"></xsl:value-of>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level3">
+ <xsl:choose>
+ <xsl:when test="contains($sici3,'<')">
+ <!-- 2<4 -->
+ <xsl:value-of select="substring-before($sici3,'<')"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici3"></xsl:value-of>
+ <!-- 3 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="page">
+ <xsl:if test="contains(text(),'<')">
+ <xsl:value-of select="substring-after(text(),'<')"></xsl:value-of>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:if test="$level1">
+ <detail level="1">
+ <number>
+ <xsl:value-of select="$level1"></xsl:value-of>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level2">
+ <detail level="2">
+ <number>
+ <xsl:value-of select="$level2"></xsl:value-of>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level3">
+ <detail level="3">
+ <number>
+ <xsl:value-of select="$level3"></xsl:value-of>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$page">
+ <extent unit="page">
+ <start>
+ <xsl:value-of select="$page"></xsl:value-of>
+ </start>
+ </extent>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="getLanguage">
+ <xsl:param name="langString"></xsl:param>
+ <xsl:param name="controlField008-35-37"></xsl:param>
+ <xsl:variable name="length" select="string-length($langString)"></xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$length=0"></xsl:when>
+ <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <language>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="substring($langString,1,3)"></xsl:value-of>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="isoLanguage">
+ <xsl:param name="currentLanguage"></xsl:param>
+ <xsl:param name="usedLanguages"></xsl:param>
+ <xsl:param name="remainingLanguages"></xsl:param>
+ <xsl:choose>
+ <xsl:when test="string-length($currentLanguage)=0"></xsl:when>
+ <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
+ <language>
+ <xsl:if test="@code!='a'">
+ <xsl:attribute name="objectPart">
+ <xsl:choose>
+ <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+ <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+ <xsl:when test="@code='e'">libretto</xsl:when>
+ <xsl:when test="@code='f'">table of contents</xsl:when>
+ <xsl:when test="@code='g'">accompanying material</xsl:when>
+ <xsl:when test="@code='h'">translation</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="$currentLanguage"></xsl:value-of>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="chopBrackets">
+ <xsl:param name="chopString"></xsl:param>
+ <xsl:variable name="string">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="$chopString"></xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="substring($string, 1,1)='['">
+ <xsl:value-of select="substring($string,2, string-length($string)-2)"></xsl:value-of>
+ </xsl:if>
+ <xsl:if test="substring($string, 1,1)!='['">
+ <xsl:value-of select="$string"></xsl:value-of>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="rfcLanguages">
+ <xsl:param name="nodeNum"></xsl:param>
+ <xsl:param name="usedLanguages"></xsl:param>
+ <xsl:param name="controlField008-35-37"></xsl:param>
+ <xsl:variable name="currentLanguage" select="."></xsl:variable>
+ <xsl:choose>
+ <xsl:when test="not($currentLanguage)"></xsl:when>
+ <xsl:when test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
+ <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
+ <language>
+ <xsl:if test="@code!='a'">
+ <xsl:attribute name="objectPart">
+ <xsl:choose>
+ <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+ <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+ <xsl:when test="@code='e'">libretto</xsl:when>
+ <xsl:when test="@code='f'">table of contents</xsl:when>
+ <xsl:when test="@code='g'">accompanying material</xsl:when>
+ <xsl:when test="@code='h'">translation</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ <languageTerm authority="rfc3066" type="code">
+ <xsl:value-of select="$currentLanguage"/>
+ </languageTerm>
+ </language>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="datafield">
+ <xsl:param name="tag"/>
+ <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
+ <xsl:param name="ind2"><xsl:text> </xsl:text></xsl:param>
+ <xsl:param name="subfields"/>
+ <xsl:element name="marc:datafield">
+ <xsl:attribute name="tag">
+ <xsl:value-of select="$tag"/>
+ </xsl:attribute>
+ <xsl:attribute name="ind1">
+ <xsl:value-of select="$ind1"/>
+ </xsl:attribute>
+ <xsl:attribute name="ind2">
+ <xsl:value-of select="$ind2"/>
+ </xsl:attribute>
+ <xsl:copy-of select="$subfields"/>
+ </xsl:element>
+ </xsl:template>
+
+ <xsl:template name="subfieldSelect">
+ <xsl:param name="codes"/>
+ <xsl:param name="delimeter"><xsl:text> </xsl:text></xsl:param>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="contains($codes, @code)">
+ <xsl:value-of select="text()"/><xsl:value-of select="$delimeter"/>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
+ </xsl:template>
+
+ <xsl:template name="buildSpaces">
+ <xsl:param name="spaces"/>
+ <xsl:param name="char"><xsl:text> </xsl:text></xsl:param>
+ <xsl:if test="$spaces>0">
+ <xsl:value-of select="$char"/>
+ <xsl:call-template name="buildSpaces">
+ <xsl:with-param name="spaces" select="$spaces - 1"/>
+ <xsl:with-param name="char" select="$char"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuation">
+ <xsl:param name="chopString"/>
+ <xsl:param name="punctuation"><xsl:text>.:,;/ </xsl:text></xsl:param>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+ <xsl:with-param name="punctuation" select="$punctuation"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuationFront">
+ <xsl:param name="chopString"/>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
+ <xsl:call-template name="chopPunctuationFront">
+ <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+</xsl:stylesheet>$$ WHERE name = 'mods32';
+
+
+-- 954.data.MODS33-xsl.sql
+UPDATE config.xml_transform SET xslt=$$<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"/>
+
+ <xsl:variable name="ascii">
+ <xsl:text> !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~</xsl:text>
+ </xsl:variable>
+
+ <xsl:variable name="latin1">
+ <xsl:text> ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ</xsl:text>
+ </xsl:variable>
+ <!-- Characters that usually don't need to be escaped -->
+ <xsl:variable name="safe">
+ <xsl:text>!'()*-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~</xsl:text>
+ </xsl:variable>
+
+ <xsl:variable name="hex">0123456789ABCDEF</xsl:variable>
+
+ <!-- Evergreen specific: revert Revision 1.23, so we can have those authority xlink attributes back. -->
+
+ <!--MARC21slim2MODS3-3.xsl
+Revision 1.27 - Mapped 648 to <subject> 2009/03/13 tmee
+Revision 1.26 - Added subfield $s mapping for 130/240/730 2008/10/16 tmee
+Revision 1.25 - Mapped 040e to <descriptiveStandard> and Leader/18 to <descriptive standard>aacr2 2008/09/18 tmee
+Revision 1.24 - Mapped 852 subfields $h, $i, $j, $k, $l, $m, $t to <shelfLocation> and 852 subfield $u to <physicalLocation> with @xlink 2008/09/17 tmee
+Revision 1.23 - Commented out xlink/uri for subfield 0 for 130/240/730, 100/700, 110/710, 111/711 as these are currently unactionable 2008/09/17 tmee
+Revision 1.22 - Mapped 022 subfield $l to type "issn-l" subfield $m to output identifier element with corresponding @type and @invalid eq 'yes'2008/09/17 tmee
+Revision 1.21 - Mapped 856 ind2=1 or ind2=2 to <relatedItem><location><url> 2008/07/03 tmee
+Revision 1.20 - Added genre w/@auth="contents of 2" and type= "musical composition" 2008/07/01 tmee
+Revision 1.19 - Added genre offprint for 008/24+ BK code 2 2008/07/01 tmee
+Revision 1.18 - Added xlink/uri for subfield 0 for 130/240/730, 100/700, 110/710, 111/711 2008/06/26 tmee
+Revision 1.17 - Added mapping of 662 2008/05/14 tmee
+Revision 1.16 - Changed @authority from "marc" to "marcgt" for 007 and 008 codes mapped to a term in <genre> 2007/07/10 tmee
+Revision 1.15 - For field 630, moved call to part template outside title element 2007/07/10 tmee
+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 - MODS2 to MODS3 updates, language unstacking and de-duping, chopPunctuation expanded 2003/10/02 16:18:58 ntra
+Revision 1.3 - Additional Changes not related to MODS Version 2.0 by ntra
+Revision 1.2 - Added Log Comment 2003/03/24 19:37:42 ckeith
+-->
+ <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.3">
+ <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.3"
+ 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:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@ind2>0">
+ <nonSort>
+ <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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"/>
+ </titleInfo>
+ </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']">
+ <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>
+ <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">a</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <!-- 1/04 fix -->
+ <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']">
+ <titleInfo type="uniform">
+ <title>
+ <xsl:call-template name="uri"/>
+
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if
+ test="(contains('adfklmors', at 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>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
+ <titleInfo type="alternative">
+ <title>
+ <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>
+ </title>
+ <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="marcgt">globe</genre>
+ </xsl:if>
+ <xsl:if
+ test="marc:controlfield[@tag='007'][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+ <genre authority="marcgt">remote-sensing image</genre>
+ </xsl:if>
+ <xsl:if test="$typeOf008='MP'">
+ <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"/>
+ <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="marcgt">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="marcgt">atlas</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+ <xsl:if test="$typeOf008='SE'">
+ <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-21='d'">
+ <genre authority="marcgt">database</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='l'">
+ <genre authority="marcgt">loose-leaf</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='m'">
+ <genre authority="marcgt">series</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='n'">
+ <genre authority="marcgt">newspaper</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='p'">
+ <genre authority="marcgt">periodical</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-21='w'">
+ <genre authority="marcgt">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:choose>
+ <xsl:when test="contains($controlField008-24,'a')">
+ <genre authority="marcgt">abstract or summary</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'b')">
+ <genre authority="marcgt">bibliography</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'c')">
+ <genre authority="marcgt">catalog</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'d')">
+ <genre authority="marcgt">dictionary</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'e')">
+ <genre authority="marcgt">encyclopedia</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'f')">
+ <genre authority="marcgt">handbook</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'g')">
+ <genre authority="marcgt">legal article</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'i')">
+ <genre authority="marcgt">index</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'k')">
+ <genre authority="marcgt">discography</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'l')">
+ <genre authority="marcgt">legislation</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'m')">
+ <genre authority="marcgt">theses</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'n')">
+ <genre authority="marcgt">survey of literature</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'o')">
+ <genre authority="marcgt">review</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'p')">
+ <genre authority="marcgt">programmed text</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'q')">
+ <genre authority="marcgt">filmography</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'r')">
+ <genre authority="marcgt">directory</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'s')">
+ <genre authority="marcgt">statistics</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'t')">
+ <genre authority="marcgt">technical report</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'v')">
+ <genre authority="marcgt">legal case and case notes</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'w')">
+ <genre authority="marcgt">law report or digest</genre>
+ </xsl:when>
+ <xsl:when test="contains($controlField008-24,'z')">
+ <genre authority="marcgt">treaty</genre>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-29='1'">
+ <genre authority="marcgt">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:choose>
+ <xsl:when test="$controlField008-26='a'">
+ <genre authority="marcgt">numeric data</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-26='e'">
+ <genre authority="marcgt">database</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-26='f'">
+ <genre authority="marcgt">font</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-26='g'">
+ <genre authority="marcgt">game</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+ <xsl:if test="$typeOf008='BK'">
+ <xsl:if test="substring($controlField008,25,1)='j'">
+ <genre authority="marcgt">patent</genre>
+ </xsl:if>
+ <xsl:if test="substring($controlField008,25,1)='2'">
+ <genre authority="marcgt">offprint</genre>
+ </xsl:if>
+ <xsl:if test="substring($controlField008,31,1)='1'">
+ <genre authority="marcgt">festschrift</genre>
+ </xsl:if>
+ <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"/>
+ <xsl:if
+ test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
+ <genre authority="marcgt">biography</genre>
+ </xsl:if>
+ <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-33='e'">
+ <genre authority="marcgt">essay</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='d'">
+ <genre authority="marcgt">drama</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='c'">
+ <genre authority="marcgt">comic strip</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='l'">
+ <genre authority="marcgt">fiction</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='h'">
+ <genre authority="marcgt">humor, satire</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='i'">
+ <genre authority="marcgt">letter</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='f'">
+ <genre authority="marcgt">novel</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='j'">
+ <genre authority="marcgt">short story</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='s'">
+ <genre authority="marcgt">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:if test="contains($controlField008-30-31,'b')">
+ <genre authority="marcgt">biography</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'c')">
+ <genre authority="marcgt">conference publication</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'d')">
+ <genre authority="marcgt">drama</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'e')">
+ <genre authority="marcgt">essay</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'f')">
+ <genre authority="marcgt">fiction</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'o')">
+ <genre authority="marcgt">folktale</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'h')">
+ <genre authority="marcgt">history</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'k')">
+ <genre authority="marcgt">humor, satire</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'m')">
+ <genre authority="marcgt">memoir</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'p')">
+ <genre authority="marcgt">poetry</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'r')">
+ <genre authority="marcgt">rehearsal</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'g')">
+ <genre authority="marcgt">reporting</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'s')">
+ <genre authority="marcgt">sound</genre>
+ </xsl:if>
+ <xsl:if test="contains($controlField008-30-31,'l')">
+ <genre authority="marcgt">speech</genre>
+ </xsl:if>
+ </xsl:if>
+ <xsl:if test="$typeOf008='VM'">
+ <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
+ <xsl:choose>
+ <xsl:when test="$controlField008-33='a'">
+ <genre authority="marcgt">art original</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='b'">
+ <genre authority="marcgt">kit</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='c'">
+ <genre authority="marcgt">art reproduction</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='d'">
+ <genre authority="marcgt">diorama</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='f'">
+ <genre authority="marcgt">filmstrip</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='g'">
+ <genre authority="marcgt">legal article</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='i'">
+ <genre authority="marcgt">picture</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='k'">
+ <genre authority="marcgt">graphic</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='l'">
+ <genre authority="marcgt">technical drawing</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='m'">
+ <genre authority="marcgt">motion picture</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='n'">
+ <genre authority="marcgt">chart</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='o'">
+ <genre authority="marcgt">flash card</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='p'">
+ <genre authority="marcgt">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="marcgt">model</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='r'">
+ <genre authority="marcgt">realia</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='s'">
+ <genre authority="marcgt">slide</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='t'">
+ <genre authority="marcgt">transparency</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='v'">
+ <genre authority="marcgt">videorecording</genre>
+ </xsl:when>
+ <xsl:when test="$controlField008-33='w'">
+ <genre authority="marcgt">toy</genre>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <!-- 1.20 047 genre tmee-->
+
+ <xsl:for-each select="marc:datafield[@tag=047]">
+ <genre authority="marcgt">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:attribute>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdef</xsl:with-param>
+ <xsl:with-param name="delimeter">-</xsl:with-param>
+ </xsl:call-template>
+ </genre>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=655]">
+ <genre authority="marcgt">
+ <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: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:call-template>
+ </xsl:variable>
+ <xsl:variable name="controlField008-7-10"
+ select="normalize-space(substring($controlField008, 8, 4))"/>
+ <xsl:variable name="controlField008-11-14"
+ select="normalize-space(substring($controlField008, 12, 4))"/>
+ <xsl:variable name="controlField008-6"
+ select="normalize-space(substring($controlField008, 7, 1))"/>
+ <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: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:with-param>
+ <xsl:with-param name="controlField008-35-37">
+ <xsl:value-of select="$controlField008-35-37"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- iso -->
+ <xsl:variable name="allLanguages">
+ <xsl:copy-of select="$langCodes"/>
+ </xsl:variable>
+ <xsl:variable name="currentLanguage">
+ <xsl:value-of select="substring($allLanguages,1,3)"/>
+ </xsl:variable>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($allLanguages,1,3)"/>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of
+ select="substring($allLanguages,4,string-length($allLanguages)-3)"
+ />
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:if test="$controlField008-35-37">
+ <xsl:value-of select="$controlField008-35-37"/>
+ </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 name="controlField008-29" select="substring($controlField008,30,1)"/>
+ <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:if>
+ </xsl:variable>
+ <xsl:variable name="check008-29">
+ <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
+ <xsl:value-of select="true()"/>
+ </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: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: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: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: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: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: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="."/>
+ </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="."/>
+ </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"/>
+ </physicalDescription>
+ </xsl:if>
+ <xsl:for-each select="marc:datafield[@tag=520]">
+ <abstract>
+ <xsl:call-template name="uri"/>
+ <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 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: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="."/>
+ </note>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=500]">
+ <note>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ <xsl:call-template name="uri"/>
+ </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:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=510]">
+ <note type="citation/reference">
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+
+ <xsl:for-each select="marc:datafield[@tag=511]">
+ <note type="performers">
+ <xsl:call-template name="uri"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </note>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=518]">
+ <note type="venue">
+ <xsl:call-template name="uri"/>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=530]">
+ <note type="additional physical form">
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=533]">
+ <note type="reproduction">
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=534]">
+ <note type="original version">
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=538]">
+ <note type="system details">
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </note>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=583]">
+ <note type="action">
+ <xsl:call-template name="uri"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </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:variable name="str">
+ <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+ <xsl:value-of select="."/>
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </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:if>
+ <xsl:if test="@code='c'">
+ <xsl:text>iso3166</xsl:text>
+ </xsl:if>
+ </xsl:attribute>
+ <xsl:value-of select="self::marc:subfield"/>
+ </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="."/>
+ </scale>
+ </xsl:if>
+ <xsl:if test="@code='b'">
+ <projection>
+ <xsl:value-of select="."/>
+ </projection>
+ </xsl:if>
+ <xsl:if test="@code='c'">
+ <coordinates>
+ <xsl:value-of select="."/>
+ </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 select="marc:datafield[@tag=656]"/>
+ <xsl:for-each select="marc:datafield[@tag=752 or @tag=662]">
+ <subject>
+ <hierarchicalGeographic>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <country>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </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: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: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:call-template>
+ </city>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='e']">
+ <citySection>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </citySection>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='g']">
+ <region>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </region>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='h']">
+ <extraterrestrialArea>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </extraterrestrialArea>
+ </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: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: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: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:attribute>
+ </xsl:if>
+ <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="text()"/>
+ </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:attribute>
+ </xsl:if>
+ <xsl:value-of select="text()"/>
+ </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: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']"/>
+ </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']"/>
+ </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:attribute>
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </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: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">
+ <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"/>
+ </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"/>
+ </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 name="relatedName"/>
+ <xsl:if test="marc:subfield[@code='b' or @code='c']">
+ <originInfo>
+ <xsl:for-each select="marc:subfield[@code='c']">
+ <publisher>
+ <xsl:value-of select="."/>
+ </publisher>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <edition>
+ <xsl:value-of select="."/>
+ </edition>
+ </xsl:for-each>
+ </originInfo>
+ </xsl:if>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ <xsl:for-each select="marc:subfield[@code='z']">
+ <identifier type="isbn">
+ <xsl:value-of select="."/>
+ </identifier>
+ </xsl:for-each>
+ <xsl:call-template name="relatedNote"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <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"/>
+ </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 name="nameDate"/>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <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"/>
+ </titleInfo>
+ <name type="corporate">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </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"/>
+ </namePart>
+ </xsl:if>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <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>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <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"/>
+ </titleInfo>
+ <xsl:call-template name="relatedForm"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
+ <relatedItem>
+ <xsl:call-template name="constituentOrRelatedType"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <xsl:call-template name="relatedForm"/>
+ </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"/>
+ </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"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=775]">
+ <relatedItem type="otherVersion">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </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"/>
+ </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"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=776]">
+ <relatedItem type="otherFormat">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=780]">
+ <relatedItem type="preceding">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=785]">
+ <relatedItem type="succeeding">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=786]">
+ <relatedItem type="original">
+ <xsl:call-template name="relatedItem76X-78X"/>
+ </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"/>
+ </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 name="nameDate"/>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ </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"/>
+ </titleInfo>
+ <name type="corporate">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </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"/>
+ </name>
+ <xsl:call-template name="relatedForm"/>
+ </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">
+ <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"/>
+ </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:if test="marc:subfield[@code='a']">
+ <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:if>
+ <xsl:if test="marc:subfield[@code='l']">
+ <xsl:call-template name="isInvalid">
+ <xsl:with-param name="type">issn-l</xsl:with-param>
+ </xsl:call-template>
+ <identifier type="issn-l">
+ <xsl:value-of select="marc:subfield[@code='l']"/>
+ </identifier>
+ </xsl:if>
+ </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:when>
+ <xsl:otherwise>
+ <xsl:value-of select="marc:subfield[@code='u']"/>
+ </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/'))"
+ />
+ </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 -->
+
+ <!-- 1.21 tmee-->
+ <xsl:for-each select="marc:datafield[@tag=856][@ind2=1][marc:subfield[@code='u']]">
+ <relatedItem type="otherVersion">
+ <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']"/>
+ </url>
+ </location>
+ </relatedItem>
+ </xsl:for-each>
+ <xsl:for-each select="marc:datafield[@tag=856][@ind2=2][marc:subfield[@code='u']]">
+ <relatedItem>
+ <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']"/>
+ </url>
+ </location>
+ </relatedItem>
+ </xsl:for-each>
+
+ <!-- 3.2 change tmee 856z -->
+
+ <!-- 1.24 tmee -->
+ <xsl:for-each select="marc:datafield[@tag=852]">
+ <location>
+ <xsl:if test="marc:subfield[@code='a' or @code='b' or @code='e']">
+ <physicalLocation>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abe</xsl:with-param>
+ </xsl:call-template>
+ </physicalLocation>
+ </xsl:if>
+
+ <xsl:if test="marc:subfield[@code='u']">
+ <physicalLocation>
+ <xsl:call-template name="uri"/>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">u</xsl:with-param>
+ </xsl:call-template>
+ </physicalLocation>
+ </xsl:if>
+
+ <xsl:if
+ test="marc:subfield[@code='h' or @code='i' or @code='j' or @code='k' or @code='l' or @code='m' or @code='t']">
+ <shelfLocation>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">hijklmt</xsl:with-param>
+ </xsl:call-template>
+ </shelfLocation>
+ </xsl:if>
+ </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>
+ <!-- 1.25 tmee-->
+
+
+ <xsl:for-each select="marc:leader[substring($leader,19,1)='a']">
+ <descriptionStandard>aacr2</descriptionStandard>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:datafield[@tag=040]">
+ <xsl:if test="marc:subfield[@code='e']">
+ <descriptionStandard>
+ <xsl:value-of select="marc:subfield[@code='e']"/>
+ </descriptionStandard>
+ </xsl:if>
+ <recordContentSource authority="marcorg">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </recordContentSource>
+ </xsl:for-each>
+ <xsl:for-each select="marc:controlfield[@tag=008]">
+ <recordCreationDate encoding="marc">
+ <xsl:value-of select="substring(.,1,6)"/>
+ </recordCreationDate>
+ </xsl:for-each>
+
+ <xsl:for-each select="marc:controlfield[@tag=005]">
+ <recordChangeDate encoding="iso8601">
+ <xsl:value-of select="."/>
+ </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:attribute>
+ </xsl:if>
+ <xsl:value-of select="."/>
+ </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="."/>
+ </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="."/>
+ </displayForm>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="affiliation">
+ <xsl:for-each select="marc:subfield[@code='u']">
+ <affiliation>
+ <xsl:value-of select="."/>
+ </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: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="."/>
+ </roleTerm>
+ </role>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='4']">
+ <role>
+ <roleTerm authority="marcrelator" type="code">
+ <xsl:value-of select="."/>
+ </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: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: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="."/>
+ </text>
+ </part>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='q']">
+ <part>
+ <xsl:call-template name="parsePart"/>
+ </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"/>
+ </partNumber>
+ </xsl:if>
+ <xsl:if test="string-length(normalize-space($partName))">
+ <partName>
+ <xsl:value-of select="$partName"/>
+ </partName>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="relatedName">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <name>
+ <namePart>
+ <xsl:value-of select="."/>
+ </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="."/>
+ </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="."/>
+ </extent>
+ </physicalDescription>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedNote">
+ <xsl:for-each select="marc:subfield[@code='n']">
+ <note>
+ <xsl:value-of select="."/>
+ </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: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="."/>
+ </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="."/>
+ </identifier>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedIdentifier">
+ <xsl:for-each select="marc:subfield[@code='o']">
+ <identifier>
+ <xsl:value-of select="."/>
+ </identifier>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedItem76X-78X">
+ <xsl:call-template name="displayLabel"/>
+ <xsl:call-template name="relatedTitle76X-78X"/>
+ <xsl:call-template name="relatedName"/>
+ <xsl:call-template name="relatedOriginInfo"/>
+ <xsl:call-template name="relatedLanguage"/>
+ <xsl:call-template name="relatedExtent"/>
+ <xsl:call-template name="relatedNote"/>
+ <xsl:call-template name="relatedSubject"/>
+ <xsl:call-template name="relatedIdentifier"/>
+ <xsl:call-template name="relatedIdentifierISSN"/>
+ <xsl:call-template name="relatedIdentifierLocal"/>
+ <xsl:call-template name="relatedPart"/>
+ </xsl:template>
+ <xsl:template name="subjectGeographicZ">
+ <geographic>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </geographic>
+ </xsl:template>
+ <xsl:template name="subjectTemporalY">
+ <temporal>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </temporal>
+ </xsl:template>
+ <xsl:template name="subjectTopic">
+ <topic>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </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: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:call-template>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:if
+ test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="nameABCDQ">
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="punctuation">
+ <xsl:text>:,;/ </xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="termsOfAddress"/>
+ <xsl:call-template name="nameDate"/>
+ </xsl:template>
+ <xsl:template name="nameACDEQ">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">acdeq</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:template>
+ <xsl:template name="constituentOrRelatedType">
+ <xsl:if test="@ind2=2">
+ <xsl:attribute name="type">constituent</xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="relatedTitle">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedTitle76X-78X">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"/>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='p']">
+ <titleInfo type="abbreviated">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"/>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='s']">
+ <titleInfo type="uniform">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"/>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedOriginInfo">
+ <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
+ <originInfo>
+ <xsl:if test="@tag=775">
+ <xsl:for-each select="marc:subfield[@code='f']">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">code</xsl:attribute>
+ <xsl:attribute name="authority">marcgac</xsl:attribute>
+ <xsl:value-of select="."/>
+ </placeTerm>
+ </place>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <publisher>
+ <xsl:value-of select="."/>
+ </publisher>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <edition>
+ <xsl:value-of select="."/>
+ </edition>
+ </xsl:for-each>
+ </originInfo>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="relatedLanguage">
+ <xsl:for-each select="marc:subfield[@code='e']">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString">
+ <xsl:value-of select="."/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="nameDate">
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <namePart type="date">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </namePart>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="subjectAuthority">
+ <xsl:if test="@ind2!=4">
+ <xsl:if test="@ind2!=' '">
+ <xsl:if test="@ind2!=8">
+ <xsl:if test="@ind2!=9">
+ <xsl:attribute name="authority">
+ <xsl:choose>
+ <xsl:when test="@ind2=0">lcsh</xsl:when>
+ <xsl:when test="@ind2=1">lcshac</xsl:when>
+ <xsl:when test="@ind2=2">mesh</xsl:when>
+ <!-- 1/04 fix -->
+ <xsl:when test="@ind2=3">nal</xsl:when>
+ <xsl:when test="@ind2=5">csh</xsl:when>
+ <xsl:when test="@ind2=6">rvm</xsl:when>
+ <xsl:when test="@ind2=7">
+ <xsl:value-of select="marc:subfield[@code='2']"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:if>
+ </xsl:if>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="subjectAnyOrder">
+ <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
+ <xsl:choose>
+ <xsl:when test="@code='v'">
+ <xsl:call-template name="subjectGenre"/>
+ </xsl:when>
+ <xsl:when test="@code='x'">
+ <xsl:call-template name="subjectTopic"/>
+ </xsl:when>
+ <xsl:when test="@code='y'">
+ <xsl:call-template name="subjectTemporalY"/>
+ </xsl:when>
+ <xsl:when test="@code='z'">
+ <xsl:call-template name="subjectGeographicZ"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="specialSubfieldSelect">
+ <xsl:param name="anyCodes"/>
+ <xsl:param name="axis"/>
+ <xsl:param name="beforeCodes"/>
+ <xsl:param name="afterCodes"/>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if
+ test="contains($anyCodes, @code) or (contains($beforeCodes, at code) and following-sibling::marc:subfield[@code=$axis]) or (contains($afterCodes, at code) and preceding-sibling::marc:subfield[@code=$axis])">
+ <xsl:value-of select="text()"/>
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+ </xsl:template>
+
+ <!-- 3.2 change tmee 6xx $v genre -->
+ <xsl:template match="marc:datafield[@tag=600]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <name type="personal">
+ <xsl:call-template name="termsOfAddress"/>
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="nameDate"/>
+ <xsl:call-template name="affiliation"/>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=610]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <name type="corporate">
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='b']">
+ <namePart>
+ <xsl:value-of select="."/>
+ </namePart>
+ </xsl:for-each>
+ <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ <xsl:call-template name="role"/>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=611]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <name type="conference">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:for-each select="marc:subfield[@code='4']">
+ <role>
+ <roleTerm authority="marcrelator" type="code">
+ <xsl:value-of select="."/>
+ </roleTerm>
+ </role>
+ </xsl:for-each>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=630]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">adfhklor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:call-template name="part"/>
+ </titleInfo>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+ <!-- 1.27 648 tmee-->
+ <xsl:template match="marc:datafield[@tag=648]">
+ <subject>
+ <xsl:if test="marc:subfield[@code=2]">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code=2]"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:call-template name="uri"/>
+
+ <xsl:call-template name="subjectAuthority"/>
+ <temporal>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </temporal>
+ <xsl:call-template name="subjectAnyOrder"/>
+
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=650]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <topic>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </topic>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=651]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"/>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <geographic>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."/>
+ </xsl:call-template>
+ </geographic>
+ </xsl:for-each>
+ <xsl:call-template name="subjectAnyOrder"/>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=653]">
+ <subject>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <topic>
+ <xsl:value-of select="."/>
+ </topic>
+ </xsl:for-each>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=656]">
+ <subject>
+ <xsl:if test="marc:subfield[@code=2]">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code=2]"/>
+ </xsl:attribute>
+ </xsl:if>
+ <occupation>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='a']"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </occupation>
+ </subject>
+ </xsl:template>
+ <xsl:template name="termsOfAddress">
+ <xsl:if test="marc:subfield[@code='b' or @code='c']">
+ <namePart type="termsOfAddress">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">bc</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="displayLabel">
+ <xsl:if test="marc:subfield[@code='i']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="marc:subfield[@code='i']"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="marc:subfield[@code='3']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="marc:subfield[@code='3']"/>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="isInvalid">
+ <xsl:param name="type"/>
+ <xsl:if
+ test="marc:subfield[@code='z'] or marc:subfield[@code='y'] or marc:subfield[@code='m']">
+ <identifier>
+ <xsl:attribute name="type">
+ <xsl:value-of select="$type"/>
+ </xsl:attribute>
+ <xsl:attribute name="invalid">
+ <xsl:text>yes</xsl:text>
+ </xsl:attribute>
+ <xsl:if test="marc:subfield[@code='z']">
+ <xsl:value-of select="marc:subfield[@code='z']"/>
+ </xsl:if>
+ <xsl:if test="marc:subfield[@code='y']">
+ <xsl:value-of select="marc:subfield[@code='y']"/>
+ </xsl:if>
+ <xsl:if test="marc:subfield[@code='m']">
+ <xsl:value-of select="marc:subfield[@code='m']"/>
+ </xsl:if>
+ </identifier>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="subtitle">
+ <xsl:if test="marc:subfield[@code='b']">
+ <subTitle>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='b']"/>
+ <!--<xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">b</xsl:with-param>
+ </xsl:call-template>-->
+ </xsl:with-param>
+ </xsl:call-template>
+ </subTitle>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="script">
+ <xsl:param name="scriptCode"/>
+ <xsl:attribute name="script">
+ <xsl:choose>
+ <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
+ <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
+ <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
+ <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
+ <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
+ <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:template>
+ <xsl:template name="parsePart">
+ <!-- assumes 773$q= 1:2:3<4
+ with up to 3 levels and one optional start page
+ -->
+ <xsl:variable name="level1">
+ <xsl:choose>
+ <xsl:when test="contains(text(),':')">
+ <!-- 1:2 -->
+ <xsl:value-of select="substring-before(text(),':')"/>
+ </xsl:when>
+ <xsl:when test="not(contains(text(),':'))">
+ <!-- 1 or 1<3 -->
+ <xsl:if test="contains(text(),'<')">
+ <!-- 1<3 -->
+ <xsl:value-of select="substring-before(text(),'<')"/>
+ </xsl:if>
+ <xsl:if test="not(contains(text(),'<'))">
+ <!-- 1 -->
+ <xsl:value-of select="text()"/>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici2">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after(text(),$level1),':')">
+ <xsl:value-of select="substring(substring-after(text(),$level1),2)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring-after(text(),$level1)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level2">
+ <xsl:choose>
+ <xsl:when test="contains($sici2,':')">
+ <!-- 2:3<4 -->
+ <xsl:value-of select="substring-before($sici2,':')"/>
+ </xsl:when>
+ <xsl:when test="contains($sici2,'<')">
+ <!-- 1: 2<4 -->
+ <xsl:value-of select="substring-before($sici2,'<')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici2"/>
+ <!-- 1:2 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici3">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
+ <xsl:value-of select="substring(substring-after($sici2,$level2),2)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring-after($sici2,$level2)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level3">
+ <xsl:choose>
+ <xsl:when test="contains($sici3,'<')">
+ <!-- 2<4 -->
+ <xsl:value-of select="substring-before($sici3,'<')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici3"/>
+ <!-- 3 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="page">
+ <xsl:if test="contains(text(),'<')">
+ <xsl:value-of select="substring-after(text(),'<')"/>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:if test="$level1">
+ <detail level="1">
+ <number>
+ <xsl:value-of select="$level1"/>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level2">
+ <detail level="2">
+ <number>
+ <xsl:value-of select="$level2"/>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level3">
+ <detail level="3">
+ <number>
+ <xsl:value-of select="$level3"/>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$page">
+ <extent unit="page">
+ <start>
+ <xsl:value-of select="$page"/>
+ </start>
+ </extent>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="getLanguage">
+ <xsl:param name="langString"/>
+ <xsl:param name="controlField008-35-37"/>
+ <xsl:variable name="length" select="string-length($langString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <language>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="substring($langString,1,3)"/>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="isoLanguage">
+ <xsl:param name="currentLanguage"/>
+ <xsl:param name="usedLanguages"/>
+ <xsl:param name="remainingLanguages"/>
+ <xsl:choose>
+ <xsl:when test="string-length($currentLanguage)=0"/>
+ <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
+ <language>
+ <xsl:if test="@code!='a'">
+ <xsl:attribute name="objectPart">
+ <xsl:choose>
+ <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+ <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+ <xsl:when test="@code='e'">libretto</xsl:when>
+ <xsl:when test="@code='f'">table of contents</xsl:when>
+ <xsl:when test="@code='g'">accompanying material</xsl:when>
+ <xsl:when test="@code='h'">translation</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="$currentLanguage"/>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($remainingLanguages,1,3)"/>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:value-of select="concat($usedLanguages,$currentLanguage)"/>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of
+ select="substring($remainingLanguages,4,string-length($remainingLanguages))"
+ />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($remainingLanguages,1,3)"/>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:value-of select="concat($usedLanguages,$currentLanguage)"/>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of
+ select="substring($remainingLanguages,4,string-length($remainingLanguages))"
+ />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="chopBrackets">
+ <xsl:param name="chopString"/>
+ <xsl:variable name="string">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="$chopString"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="substring($string, 1,1)='['">
+ <xsl:value-of select="substring($string,2, string-length($string)-2)"/>
+ </xsl:if>
+ <xsl:if test="substring($string, 1,1)!='['">
+ <xsl:value-of select="$string"/>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="rfcLanguages">
+ <xsl:param name="nodeNum"/>
+ <xsl:param name="usedLanguages"/>
+ <xsl:param name="controlField008-35-37"/>
+ <xsl:variable name="currentLanguage" select="."/>
+ <xsl:choose>
+ <xsl:when test="not($currentLanguage)"/>
+ <xsl:when
+ test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
+ <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
+ <language>
+ <xsl:if test="@code!='a'">
+ <xsl:attribute name="objectPart">
+ <xsl:choose>
+ <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+ <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+ <xsl:when test="@code='e'">libretto</xsl:when>
+ <xsl:when test="@code='f'">table of contents</xsl:when>
+ <xsl:when test="@code='g'">accompanying material</xsl:when>
+ <xsl:when test="@code='h'">translation</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ <languageTerm authority="rfc3066" type="code">
+ <xsl:value-of select="$currentLanguage"/>
+ </languageTerm>
+ </language>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise> </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="datafield">
+ <xsl:param name="tag"/>
+ <xsl:param name="ind1">
+ <xsl:text> </xsl:text>
+ </xsl:param>
+ <xsl:param name="ind2">
+ <xsl:text> </xsl:text>
+ </xsl:param>
+ <xsl:param name="subfields"/>
+ <xsl:element name="marc:datafield">
+ <xsl:attribute name="tag">
+ <xsl:value-of select="$tag"/>
+ </xsl:attribute>
+ <xsl:attribute name="ind1">
+ <xsl:value-of select="$ind1"/>
+ </xsl:attribute>
+ <xsl:attribute name="ind2">
+ <xsl:value-of select="$ind2"/>
+ </xsl:attribute>
+ <xsl:copy-of select="$subfields"/>
+ </xsl:element>
+ </xsl:template>
+
+ <xsl:template name="subfieldSelect">
+ <xsl:param name="codes">abcdefghijklmnopqrstuvwxyz</xsl:param>
+ <xsl:param name="delimeter">
+ <xsl:text> </xsl:text>
+ </xsl:param>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="contains($codes, @code)">
+ <xsl:value-of select="text()"/>
+ <xsl:value-of select="$delimeter"/>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
+ </xsl:template>
+
+ <xsl:template name="buildSpaces">
+ <xsl:param name="spaces"/>
+ <xsl:param name="char">
+ <xsl:text> </xsl:text>
+ </xsl:param>
+ <xsl:if test="$spaces>0">
+ <xsl:value-of select="$char"/>
+ <xsl:call-template name="buildSpaces">
+ <xsl:with-param name="spaces" select="$spaces - 1"/>
+ <xsl:with-param name="char" select="$char"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuation">
+ <xsl:param name="chopString"/>
+ <xsl:param name="punctuation">
+ <xsl:text>.:,;/ </xsl:text>
+ </xsl:param>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+ <xsl:with-param name="punctuation" select="$punctuation"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise>
+ <xsl:value-of select="$chopString"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuationFront">
+ <xsl:param name="chopString"/>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
+ <xsl:call-template name="chopPunctuationFront">
+ <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"
+ />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise>
+ <xsl:value-of select="$chopString"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuationBack">
+ <xsl:param name="chopString"/>
+ <xsl:param name="punctuation">
+ <xsl:text>.:,;/] </xsl:text>
+ </xsl:param>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+ <xsl:with-param name="punctuation" select="$punctuation"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise>
+ <xsl:value-of select="$chopString"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- nate added 12/14/2007 for lccn.loc.gov: url encode ampersand, etc. -->
+ <xsl:template name="url-encode">
+
+ <xsl:param name="str"/>
+
+ <xsl:if test="$str">
+ <xsl:variable name="first-char" select="substring($str,1,1)"/>
+ <xsl:choose>
+ <xsl:when test="contains($safe,$first-char)">
+ <xsl:value-of select="$first-char"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="codepoint">
+ <xsl:choose>
+ <xsl:when test="contains($ascii,$first-char)">
+ <xsl:value-of
+ select="string-length(substring-before($ascii,$first-char)) + 32"
+ />
+ </xsl:when>
+ <xsl:when test="contains($latin1,$first-char)">
+ <xsl:value-of
+ select="string-length(substring-before($latin1,$first-char)) + 160"/>
+ <!-- was 160 -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="no">Warning: string contains a character
+ that is out of range! Substituting "?".</xsl:message>
+ <xsl:text>63</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="hex-digit1"
+ select="substring($hex,floor($codepoint div 16) + 1,1)"/>
+ <xsl:variable name="hex-digit2" select="substring($hex,$codepoint mod 16 + 1,1)"/>
+ <!-- <xsl:value-of select="concat('%',$hex-digit2)"/> -->
+ <xsl:value-of select="concat('%',$hex-digit1,$hex-digit2)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:if test="string-length($str) > 1">
+ <xsl:call-template name="url-encode">
+ <xsl:with-param name="str" select="substring($str,2)"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>$$ WHERE name = 'mods33';
+
+
+INSERT INTO config.global_flag (name, value, enabled, label) VALUES
+(
+ 'opac.browse.warnable_regexp_per_class',
+ '{"title": "^(a|the|an)\\s"}',
+ FALSE,
+ oils_i18n_gettext(
+ 'opac.browse.warnable_regexp_per_class',
+ 'Map of search classes to regular expressions to warn user about leading articles.',
+ 'cgf',
+ 'label'
+ )
+),
+(
+ 'opac.browse.holdings_visibility_test_limit',
+ '100',
+ TRUE,
+ oils_i18n_gettext(
+ 'opac.browse.holdings_visibility_test_limit',
+ 'Don''t look for more than this number of records with holdings when displaying browse headings with visible record counts.',
+ 'cgf',
+ 'label'
+ )
+);
+
+ALTER TABLE metabib.browse_entry DROP CONSTRAINT browse_entry_value_key;
+ALTER TABLE metabib.browse_entry ADD COLUMN sort_value TEXT;
+DELETE FROM metabib.browse_entry_def_map; -- Yeah.
+DELETE FROM metabib.browse_entry WHERE sort_value IS NULL;
+ALTER TABLE metabib.browse_entry ALTER COLUMN sort_value SET NOT NULL;
+ALTER TABLE metabib.browse_entry ADD UNIQUE (sort_value, value);
+DROP TRIGGER IF EXISTS mbe_sort_value ON metabib.browse_entry;
+
+CREATE INDEX browse_entry_sort_value_idx
+ ON metabib.browse_entry USING BTREE (sort_value);
+
+-- NOTE If I understand ordered indices correctly, an index on sort_value DESC
+-- is not actually needed, even though we do have a query that does ORDER BY
+-- on this column in that direction. The previous index serves for both
+-- directions, and ordering in an index is only helpful for multi-column
+-- indices, I think. See http://www.postgresql.org/docs/9.1/static/indexes-ordering.html
+
+-- CREATE INDEX CONCURRENTLY browse_entry_sort_value_idx_desc
+-- ON metabib.browse_entry USING BTREE (sort_value DESC);
+
+CREATE TYPE metabib.flat_browse_entry_appearance AS (
+ browse_entry BIGINT,
+ value TEXT,
+ fields TEXT,
+ authorities TEXT,
+ sources INT, -- visible ones, that is
+ row_number INT, -- internal use, sort of
+ accurate BOOL, -- Count in sources field is accurate? Not
+ -- if we had more than a browse superpage
+ -- of records to look at.
+ pivot_point BIGINT
+);
+
+
+CREATE OR REPLACE FUNCTION metabib.browse_pivot(
+ search_field INT[],
+ browse_term TEXT
+) RETURNS BIGINT AS $p$
+DECLARE
+ id BIGINT;
+BEGIN
+ SELECT INTO id mbe.id FROM metabib.browse_entry mbe
+ JOIN metabib.browse_entry_def_map mbedm ON (
+ mbedm.entry = mbe.id AND
+ mbedm.def = ANY(search_field)
+ )
+ WHERE mbe.sort_value >= public.search_normalize(browse_term)
+ ORDER BY mbe.sort_value, mbe.value LIMIT 1;
+
+ RETURN id;
+END;
+$p$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION metabib.staged_browse(
+ query TEXT,
+ fields INT[],
+ context_org INT,
+ context_locations INT[],
+ staff BOOL,
+ browse_superpage_size INT,
+ count_up_from_zero BOOL, -- if false, count down from -1
+ result_limit INT,
+ next_pivot_pos INT
+) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
+DECLARE
+ curs REFCURSOR;
+ rec RECORD;
+ qpfts_query TEXT;
+ result_row metabib.flat_browse_entry_appearance%ROWTYPE;
+ results_skipped INT := 0;
+ row_counter INT := 0;
+ row_number INT;
+ slice_start INT;
+ slice_end INT;
+ full_end INT;
+ all_records BIGINT[];
+ superpage_of_records BIGINT[];
+ superpage_size INT;
+BEGIN
+ IF count_up_from_zero THEN
+ row_number := 0;
+ ELSE
+ row_number := -1;
+ END IF;
+
+ OPEN curs FOR EXECUTE query;
+
+ LOOP
+ FETCH curs INTO rec;
+ IF NOT FOUND THEN
+ IF result_row.pivot_point IS NOT NULL THEN
+ RETURN NEXT result_row;
+ END IF;
+ RETURN;
+ END IF;
+
+ -- Gather aggregate data based on the MBE row we're looking at now
+ SELECT INTO all_records, result_row.authorities, result_row.fields
+ ARRAY_AGG(DISTINCT source),
+ ARRAY_TO_STRING(ARRAY_AGG(DISTINCT authority), $$,$$),
+ ARRAY_TO_STRING(ARRAY_AGG(DISTINCT def), $$,$$)
+ FROM metabib.browse_entry_def_map
+ WHERE entry = rec.id
+ AND def = ANY(fields);
+
+ result_row.sources := 0;
+
+ full_end := ARRAY_LENGTH(all_records, 1);
+ superpage_size := COALESCE(browse_superpage_size, full_end);
+ slice_start := 1;
+ slice_end := superpage_size;
+
+ WHILE result_row.sources = 0 AND slice_start <= full_end LOOP
+ superpage_of_records := all_records[slice_start:slice_end];
+ qpfts_query :=
+ 'SELECT NULL::BIGINT AS id, ARRAY[r] AS records, ' ||
+ '1::INT AS rel FROM (SELECT UNNEST(' ||
+ quote_literal(superpage_of_records) || '::BIGINT[]) AS r) rr';
+
+ -- We use search.query_parser_fts() for visibility testing.
+ -- We're calling it once per browse-superpage worth of records
+ -- out of the set of records related to a given mbe, until we've
+ -- either exhausted that set of records or found at least 1
+ -- visible record.
+
+ SELECT INTO result_row.sources visible
+ FROM search.query_parser_fts(
+ context_org, NULL, qpfts_query, NULL,
+ context_locations, 0, NULL, NULL, FALSE, staff, FALSE
+ ) qpfts
+ WHERE qpfts.rel IS NULL;
+
+ slice_start := slice_start + superpage_size;
+ slice_end := slice_end + superpage_size;
+ END LOOP;
+
+ -- Accurate? Well, probably.
+ result_row.accurate := browse_superpage_size IS NULL OR
+ browse_superpage_size >= full_end;
+
+ IF result_row.sources > 0 THEN
+ -- We've got a browse entry with visible holdings. Yay.
+
+
+ -- The function that calls this function needs row_number in order
+ -- to correctly order results from two different runs of this
+ -- functions.
+ result_row.row_number := row_number;
+
+ -- Now, if row_counter is still less than limit, return a row. If
+ -- not, but it is less than next_pivot_pos, continue on without
+ -- returning actual result rows until we find
+ -- that next pivot, and return it.
+
+ IF row_counter < result_limit THEN
+ result_row.browse_entry := rec.id;
+ result_row.value := rec.value;
+
+ RETURN NEXT result_row;
+ ELSE
+ result_row.browse_entry := NULL;
+ result_row.authorities := NULL;
+ result_row.fields := NULL;
+ result_row.value := NULL;
+ result_row.sources := NULL;
+ result_row.accurate := NULL;
+ result_row.pivot_point := rec.id;
+
+ IF row_counter >= next_pivot_pos THEN
+ RETURN NEXT result_row;
+ RETURN;
+ END IF;
+ END IF;
+
+ IF count_up_from_zero THEN
+ row_number := row_number + 1;
+ ELSE
+ row_number := row_number - 1;
+ END IF;
+
+ -- row_counter is different from row_number.
+ -- It simply counts up from zero so that we know when
+ -- we've reached our limit.
+ row_counter := row_counter + 1;
+ END IF;
+ END LOOP;
+END;
+$p$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION metabib.browse(
+ search_field INT[],
+ browse_term TEXT,
+ context_org INT DEFAULT NULL,
+ context_loc_group INT DEFAULT NULL,
+ staff BOOL DEFAULT FALSE,
+ pivot_id BIGINT DEFAULT NULL,
+ result_limit INT DEFAULT 10
+) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
+DECLARE
+ core_query TEXT;
+ back_query TEXT;
+ forward_query TEXT;
+ pivot_sort_value TEXT;
+ pivot_sort_fallback TEXT;
+ context_locations INT[];
+ browse_superpage_size INT;
+ results_skipped INT := 0;
+ back_limit INT;
+ back_to_pivot INT;
+ forward_limit INT;
+ forward_to_pivot INT;
+BEGIN
+ -- First, find the pivot if we were given a browse term but not a pivot.
+ IF pivot_id IS NULL THEN
+ pivot_id := metabib.browse_pivot(search_field, browse_term);
+ END IF;
+
+ SELECT INTO pivot_sort_value, pivot_sort_fallback
+ sort_value, value FROM metabib.browse_entry WHERE id = pivot_id;
+
+ -- Bail if we couldn't find a pivot.
+ IF pivot_sort_value IS NULL THEN
+ RETURN;
+ END IF;
+
+ -- Transform the context_loc_group argument (if any) (logc at the
+ -- TPAC layer) into a form we'll be able to use.
+ IF context_loc_group IS NOT NULL THEN
+ SELECT INTO context_locations ARRAY_AGG(location)
+ FROM asset.copy_location_group_map
+ WHERE lgroup = context_loc_group;
+ END IF;
+
+ -- Get the configured size of browse superpages.
+ SELECT INTO browse_superpage_size value -- NULL ok
+ FROM config.global_flag
+ WHERE enabled AND name = 'opac.browse.holdings_visibility_test_limit';
+
+ -- First we're going to search backward from the pivot, then we're going
+ -- to search forward. In each direction, we need two limits. At the
+ -- lesser of the two limits, we delineate the edge of the result set
+ -- we're going to return. At the greater of the two limits, we find the
+ -- pivot value that would represent an offset from the current pivot
+ -- at a distance of one "page" in either direction, where a "page" is a
+ -- result set of the size specified in the "result_limit" argument.
+ --
+ -- The two limits in each direction make four derived values in total,
+ -- and we calculate them now.
+ back_limit := CEIL(result_limit::FLOAT / 2);
+ back_to_pivot := result_limit;
+ forward_limit := result_limit / 2;
+ forward_to_pivot := result_limit - 1;
+
+ -- This is the meat of the SQL query that finds browse entries. We'll
+ -- pass this to a function which uses it with a cursor, so that individual
+ -- rows may be fetched in a loop until some condition is satisfied, without
+ -- waiting for a result set of fixed size to be collected all at once.
+ core_query := '
+ SELECT
+ mbe.id,
+ mbe.value,
+ mbe.sort_value
+ FROM metabib.browse_entry mbe
+ WHERE EXISTS (SELECT 1 FROM metabib.browse_entry_def_map mbedm WHERE
+ mbedm.entry = mbe.id AND
+ mbedm.def = ANY(' || quote_literal(search_field) || ')
+ ) AND ';
+
+ -- This is the variant of the query for browsing backward.
+ back_query := core_query ||
+ ' mbe.sort_value <= ' || quote_literal(pivot_sort_value) ||
+ ' ORDER BY mbe.sort_value DESC, mbe.value DESC ';
+
+ -- This variant browses forward.
+ forward_query := core_query ||
+ ' mbe.sort_value > ' || quote_literal(pivot_sort_value) ||
+ ' ORDER BY mbe.sort_value, mbe.value ';
+
+ -- We now call the function which applies a cursor to the provided
+ -- queries, stopping at the appropriate limits and also giving us
+ -- the next page's pivot.
+ RETURN QUERY
+ SELECT * FROM metabib.staged_browse(
+ back_query, search_field, context_org, context_locations,
+ staff, browse_superpage_size, TRUE, back_limit, back_to_pivot
+ ) UNION
+ SELECT * FROM metabib.staged_browse(
+ forward_query, search_field, context_org, context_locations,
+ staff, browse_superpage_size, FALSE, forward_limit, forward_to_pivot
+ ) ORDER BY row_number DESC;
+
+END;
+$p$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION metabib.browse(
+ search_class TEXT,
+ browse_term TEXT,
+ context_org INT DEFAULT NULL,
+ context_loc_group INT DEFAULT NULL,
+ staff BOOL DEFAULT FALSE,
+ pivot_id BIGINT DEFAULT NULL,
+ result_limit INT DEFAULT 10
+) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
+BEGIN
+ RETURN QUERY SELECT * FROM metabib.browse(
+ (SELECT COALESCE(ARRAY_AGG(id), ARRAY[]::INT[])
+ FROM config.metabib_field WHERE field_class = search_class),
+ browse_term,
+ context_org,
+ context_loc_group,
+ staff,
+ pivot_id,
+ result_limit
+ );
+END;
+$p$ LANGUAGE PLPGSQL;
+
+UPDATE config.metabib_field
+SET
+ xpath = $$//mods32:mods/mods32:relatedItem[@type="series"]/mods32:titleInfo[@type="nfi"]$$,
+ browse_sort_xpath = $$*[local-name() != "nonSort"]$$,
+ browse_xpath = NULL
+WHERE
+ field_class = 'series' AND name = 'seriestitle' ;
+
+UPDATE config.metabib_field
+SET
+ xpath = $$//mods32:mods/mods32:titleInfo[mods32:title and not (@type)]$$,
+ browse_sort_xpath = $$*[local-name() != "nonSort"]$$,
+ browse_xpath = NULL,
+ browse_field = TRUE
+WHERE
+ field_class = 'title' AND name = 'proper' ;
+
+UPDATE config.metabib_field
+SET
+ xpath = $$//mods32:mods/mods32:titleInfo[mods32:title and (@type='alternative-nfi')]$$,
+ browse_sort_xpath = $$*[local-name() != "nonSort"]$$,
+ browse_xpath = NULL
+WHERE
+ field_class = 'title' AND name = 'alternative' ;
+
+UPDATE config.metabib_field
+SET
+ xpath = $$//mods32:mods/mods32:titleInfo[mods32:title and (@type='uniform-nfi')]$$,
+ browse_sort_xpath = $$*[local-name() != "nonSort"]$$,
+ browse_xpath = NULL
+WHERE
+ field_class = 'title' AND name = 'uniform' ;
+
+UPDATE config.metabib_field
+SET
+ xpath = $$//mods32:mods/mods32:titleInfo[mods32:title and (@type='translated-nfi')]$$,
+ browse_sort_xpath = $$*[local-name() != "nonSort"]$$,
+ browse_xpath = NULL
+WHERE
+ field_class = 'title' AND name = 'translated' ;
+
+-- This keeps extra terms like "creator" out of browse headings.
+UPDATE config.metabib_field
+ SET browse_xpath = $$//*[local-name()='namePart']$$ -- vim */
+ WHERE
+ browse_field AND
+ browse_xpath IS NULL AND
+ field_class = 'author';
+
+INSERT INTO config.org_unit_setting_type (
+ name, label, grp, description, datatype
+) VALUES (
+ 'opac.browse.pager_shortcuts',
+ 'Paging shortcut links for OPAC Browse',
+ 'opac',
+ 'The characters in this string, in order, will be used as shortcut links for quick paging in the OPAC browse interface. Any sequence surrounded by asterisks will be taken as a whole label, not split into individual labels at the character level, but only the first character will serve as the basis of the search.',
+ 'string'
+);
+
+
+-- NOTE: very IDs are still correct for perms and event_def data at merge.
+
+SELECT evergreen.upgrade_deps_block_check('0817', :eg_version);
+
+-- copy status
+
+INSERT INTO config.copy_status
+ (id, name, holdable, opac_visible, copy_active, restrict_copy_delete)
+ VALUES (16, oils_i18n_gettext(16, 'Long Overdue', 'ccs', 'name'), 'f', 'f', 'f', 't');
+
+-- checkin override perm
+
+INSERT INTO permission.perm_list (id, code, description) VALUES (
+ 549, -- VERIFY
+ 'COPY_STATUS_LONGOVERDUE.override',
+ oils_i18n_gettext(
+ 549, -- VERIFY
+ 'Allows the user to check-in long-overdue items, prompting ' ||
+ 'long-overdue check-in processing',
+ 'ppl',
+ 'code'
+ )
+), (
+ 550, -- VERIFY
+ 'SET_CIRC_LONG_OVERDUE',
+ oils_i18n_gettext(
+ 550, -- VERIFY
+ 'Allows the user to mark a circulation as long-overdue',
+ 'ppl',
+ 'code'
+ )
+);
+
+-- billing types
+
+INSERT INTO config.billing_type (id, owner, name) VALUES
+ (10, 1, oils_i18n_gettext(
+ 10, 'Long-Overdue Materials', 'cbt', 'name')),
+ (11, 1, oils_i18n_gettext(
+ 11, 'Long-Overdue Materials Processing Fee', 'cbt', 'name'));
+
+-- org settings
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, datatype, label, description) VALUES
+(
+ 'circ.longoverdue_immediately_available',
+ 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.longoverdue_immediately_available',
+ 'Long-Overdue Items Usable on Checkin',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.longoverdue_immediately_available',
+ 'Long-overdue items are usable on checkin instead of going "home" first',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.longoverdue_materials_processing_fee',
+ 'finance', 'currency',
+ oils_i18n_gettext(
+ 'circ.longoverdue_materials_processing_fee',
+ 'Long-Overdue Materials Processing Fee',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.longoverdue_materials_processing_fee',
+ 'Long-Overdue Materials Processing Fee',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.max_accept_return_of_longoverdue',
+ 'circ', 'interval',
+ oils_i18n_gettext(
+ 'circ.max_accept_return_of_longoverdue',
+ 'Long-Overdue Max Return Interval',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.max_accept_return_of_longoverdue',
+ 'Long-overdue check-in processing (voiding fees, re-instating ' ||
+ 'overdues, etc.) will not take place for items that have been ' ||
+ 'overdue for (or have last activity older than) this amount of time',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.restore_overdue_on_longoverdue_return',
+ 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.restore_overdue_on_longoverdue_return',
+ 'Restore Overdues on Long-Overdue Item Return',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.restore_overdue_on_longoverdue_return',
+ 'Restore Overdues on Long-Overdue Item Return',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.void_longoverdue_on_checkin',
+ 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.void_longoverdue_on_checkin',
+ 'Void Long-Overdue Item Billing When Returned',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.void_longoverdue_on_checkin',
+ 'Void Long-Overdue Item Billing When Returned',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.void_longoverdue_proc_fee_on_checkin',
+ 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.void_longoverdue_proc_fee_on_checkin',
+ 'Void Processing Fee on Long-Overdue Item Return',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.void_longoverdue_proc_fee_on_checkin',
+ 'Void Processing Fee on Long-Overdue Item Return',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.void_overdue_on_longoverdue',
+ 'finance', 'bool',
+ oils_i18n_gettext(
+ 'circ.void_overdue_on_longoverdue',
+ 'Void Overdue Fines When Items are Marked Long-Overdue',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.void_overdue_on_longoverdue',
+ 'Void Overdue Fines When Items are Marked Long-Overdue',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.longoverdue.xact_open_on_zero',
+ 'finance', 'bool',
+ oils_i18n_gettext(
+ 'circ.longoverdue.xact_open_on_zero',
+ 'Leave transaction open when long overdue balance equals zero',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.longoverdue.xact_open_on_zero',
+ 'Leave transaction open when long-overdue balance equals zero. ' ||
+ 'This leaves the lost copy on the patron record when it is paid',
+ 'coust',
+ 'description'
+ )
+), (
+ 'circ.longoverdue.use_last_activity_date_on_return',
+ 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.longoverdue.use_last_activity_date_on_return',
+ 'Long-Overdue Check-In Interval Uses Last Activity Date',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.longoverdue.use_last_activity_date_on_return',
+ 'Use the long-overdue last-activity date instead of the due_date to ' ||
+ 'determine whether the item has been checked out too long to ' ||
+ 'perform long-overdue check-in processing. If set, the system ' ||
+ 'will first check the last payment time, followed by the last ' ||
+ 'billing time, followed by the due date. See also ' ||
+ 'circ.max_accept_return_of_longoverdue',
+ 'coust',
+ 'description'
+ )
+);
+
+-- mark long-overdue reactor
+
+INSERT INTO action_trigger.reactor (module, description) VALUES
+( 'MarkItemLongOverdue',
+ oils_i18n_gettext(
+ 'MarkItemLongOverdue',
+ 'Marks a circulating item as long-overdue and applies configured ' ||
+ 'penalties. Also creates events for the longoverdue.auto hook',
+ 'atreact',
+ 'description'
+ )
+);
+
+INSERT INTO action_trigger.validator (module, description) VALUES (
+ 'PatronNotInCollections',
+ 'Event is valid if the linked patron is not in collections processing ' ||
+ 'at the context org unit'
+);
+
+-- VERIFY ID
+INSERT INTO action_trigger.event_definition
+ (id, active, owner, name, hook, validator, reactor, delay, delay_field)
+VALUES (
+ 49, FALSE, 1, '6 Month Overdue Mark Long-Overdue',
+ 'checkout.due', 'PatronNotInCollections',
+ 'MarkItemLongOverdue', '6 months', 'due_date'
+);
+
+-- VERIFY ID
+INSERT INTO action_trigger.event_params (event_def, param, value) VALUES
+ (49, 'editor', '''1''');
+
+-- new longoverdue and longervdue.auto hook.
+
+INSERT INTO action_trigger.hook (key,core_type,description) VALUES (
+ 'longoverdue',
+ 'circ',
+ 'Circulating Item marked long-overdue'
+);
+
+INSERT INTO action_trigger.hook (key,core_type,description) VALUES (
+ 'longoverdue.auto',
+ 'circ',
+ 'Circulating Item automatically marked long-overdue'
+);
+
+-- sample longoverdue.auto notification reactor
+
+-- VERIFY ID
+INSERT INTO action_trigger.event_definition
+ (id, active, owner, name, hook, validator, reactor, group_field, template)
+ VALUES (
+ 50, FALSE, 1, '6 Month Long Overdue Notice',
+ 'longoverdue.auto', 'NOOP_True', 'SendEmail', 'usr',
+$$
+[%- USE date -%]
+[%- user = target.0.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Overdue Items Marked Long Overdue
+
+Dear [% user.family_name %], [% user.first_given_name %]
+The following items are 6 months overdue and have been marked Long Overdue.
+
+[% FOR circ IN target %]
+ [%- copy_details = helpers.get_copy_bib_basics(circ.target_copy.id) -%]
+ Title: [% copy_details.title %], by [% copy_details.author %]
+ Call Number: [% circ.target_copy.call_number.label %]
+ Shelving Location: [% circ.target_copy.location.name %]
+ Barcode: [% circ.target_copy.barcode %]
+ Due: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+ Item Cost: [% helpers.get_copy_price(circ.target_copy) %]
+ Total Owed For Transaction: [% circ.billable_transaction.summary.balance_owed %]
+ Library: [% circ.circ_lib.name %]
+
+[% END %]
+$$);
+
+-- ENV for above
+
+-- VERIFY IDs
+INSERT INTO action_trigger.environment (event_def, path) VALUES
+ (50, 'target_copy.call_number'),
+ (50, 'usr'),
+ (50, 'billable_transaction.summary'),
+ (50, 'circ_lib.billing_address'),
+ (50, 'target_copy.location');
+
+
+--ROLLBACK;
+
+SELECT evergreen.upgrade_deps_block_check('0822', :eg_version);
+
+ALTER TABLE action.hold_request
+ ADD COLUMN behind_desk BOOLEAN NOT NULL DEFAULT FALSE;
+
+-- The value on the hold is the new arbiter of whether a
+-- hold should be held behind the desk and reported as such
+-- Update existing holds that would in the current regime
+-- be considered behind-the-desk holds to use the new column
+
+UPDATE action.hold_request ahr
+ SET behind_desk = TRUE
+ FROM actor.usr_setting aus
+ WHERE
+ ahr.cancel_time IS NULL AND
+ ahr.fulfillment_time IS NULL AND
+ aus.usr = ahr.usr AND
+ aus.name = 'circ.holds_behind_desk' AND
+ aus.value = 'true' AND
+ EXISTS (
+ SELECT 1
+ FROM actor.org_unit_ancestor_setting(
+ 'circ.holds.behind_desk_pickup_supported',
+ ahr.pickup_lib
+ )
+ WHERE value = 'true'
+ );
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0823', :eg_version);
+
+-- Track the requesting user
+ALTER TABLE staging.user_stage
+ ADD COLUMN requesting_usr INTEGER
+ REFERENCES actor.usr(id) ON DELETE SET NULL;
+
+-- add county column to staged address tables and
+-- drop state requirement to match actor.usr_address
+ALTER TABLE staging.mailing_address_stage
+ ADD COLUMN county TEXT,
+ ALTER COLUMN state DROP DEFAULT,
+ ALTER COLUMN state DROP NOT NULL;
+
+ALTER TABLE staging.billing_address_stage
+ ADD COLUMN county TEXT,
+ ALTER COLUMN state DROP DEFAULT,
+ ALTER COLUMN state DROP NOT NULL;
+
+-- stored procedure for deleting expired pending patrons
+CREATE OR REPLACE FUNCTION staging.purge_pending_users() RETURNS VOID AS $$
+DECLARE
+ org_id INT;
+ intvl TEXT;
+BEGIN
+ FOR org_id IN SELECT DISTINCT(home_ou) FROM staging.user_stage LOOP
+
+ SELECT INTO intvl value FROM
+ actor.org_unit_ancestor_setting(
+ 'opac.pending_user_expire_interval', org_id);
+
+ CONTINUE WHEN intvl IS NULL OR intvl ILIKE 'null';
+
+ -- de-JSON-ify the string
+ SELECT INTO intvl TRIM(BOTH '"' FROM intvl);
+
+ DELETE FROM staging.user_stage
+ WHERE home_ou = org_id AND row_date + intvl::INTERVAL < NOW();
+
+ END LOOP;
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, datatype, label, description)
+VALUES (
+ 'opac.allow_pending_user',
+ 'opac',
+ 'bool',
+ oils_i18n_gettext(
+ 'opac.allow_pending_user',
+ 'Allow Patron Self-Registration',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'opac.allow_pending_user',
+ 'Allow patrons to self-register, creating pending user accounts',
+ 'coust',
+ 'description'
+ )
+), (
+ 'opac.pending_user_expire_interval',
+ 'opac',
+ 'interval',
+ oils_i18n_gettext(
+ 'opac.pending_user_expire_interval',
+ 'Patron Self-Reg. Expire Interval',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'opac.pending_user_expire_interval',
+ 'If set, this is the amount of time a pending user account will ' ||
+ 'be allowed to sit in the database. After this time, the pending ' ||
+ 'user information will be purged',
+ 'coust',
+ 'description'
+ )
+), (
+ 'ui.patron.edit.aua.county.show',
+ 'gui',
+ 'bool',
+ oils_i18n_gettext(
+ 'ui.patron.edit.aua.county.require',
+ 'Show county field on patron registration',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.patron.edit.aua.county.require',
+ 'The county field will be shown on the patron registration screen',
+ 'coust',
+ 'description'
+ )
+);
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0824', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+ (grp, name, label, description, datatype, fm_class)
+VALUES (
+ 'vandelay',
+ 'vandelay.item.barcode.auto',
+ oils_i18n_gettext(
+ 'vandelay.item.barcode.auto',
+ 'Vandelay Generate Default Barcodes',
+ 'coust', 'label'),
+ oils_i18n_gettext(
+ 'vandelay.item.barcode.auto',
+ 'Auto-generate deault item barcodes when no item barcode is present',
+ 'coust', 'label'),
+ 'bool',
+ NULL
+), (
+ 'vandelay',
+ 'vandelay.item.barcode.prefix',
+ oils_i18n_gettext(
+ 'vandelay.item.barcode.prefix',
+ 'Vandelay Default Barcode Prefix',
+ 'coust', 'label'),
+ oils_i18n_gettext(
+ 'vandelay.item.barcode.prefix',
+ 'Apply this prefix to any auto-generated item barcodes',
+ 'coust', 'label'),
+ 'string',
+ NULL
+), (
+ 'vandelay',
+ 'vandelay.item.call_number.auto',
+ oils_i18n_gettext(
+ 'vandelay.item.call_number.auto',
+ 'Vandelay Generate Default Call Numbers',
+ 'coust', 'label'),
+ oils_i18n_gettext(
+ 'vandelay.item.call_number.auto',
+ 'Auto-generate default item call numbers when no item call number is present',
+ 'coust', 'label'),
+ 'bool',
+ NULL
+), (
+ 'vandelay',
+ 'vandelay.item.call_number.prefix',
+ oils_i18n_gettext(
+ 'vandelay.item.call_number.prefix',
+ 'Vandelay Default Call Number Prefix',
+ 'coust', 'label'),
+ oils_i18n_gettext(
+ 'vandelay.item.call_number.prefix',
+ 'Apply this prefix to any auto-generated item call numbers',
+ 'coust', 'label'),
+ 'string',
+ NULL
+), (
+ 'vandelay',
+ 'vandelay.item.copy_location.default',
+ oils_i18n_gettext(
+ 'vandelay.item.copy_location.default',
+ 'Vandelay Default Copy Location',
+ 'coust', 'label'),
+ oils_i18n_gettext(
+ 'vandelay.item.copy_location.default',
+ 'Default copy location value for imported items',
+ 'coust', 'label'),
+ 'link',
+ 'acpl'
+), (
+ 'vandelay',
+ 'vandelay.item.circ_modifier.default',
+ oils_i18n_gettext(
+ 'vandelay.item.circ_modifier.default',
+ 'Vandelay Default Circulation Modifier',
+ 'coust', 'label'),
+ oils_i18n_gettext(
+ 'vandelay.item.circ_modifier.default',
+ 'Default circulation modifier value for imported items',
+ 'coust', 'label'),
+ 'link',
+ 'ccm'
+);
+
+
+CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
+DECLARE
+
+ owning_lib TEXT;
+ circ_lib TEXT;
+ call_number TEXT;
+ copy_number TEXT;
+ status TEXT;
+ location TEXT;
+ circulate TEXT;
+ deposit TEXT;
+ deposit_amount TEXT;
+ ref TEXT;
+ holdable TEXT;
+ price TEXT;
+ barcode TEXT;
+ circ_modifier TEXT;
+ circ_as_type TEXT;
+ alert_message TEXT;
+ opac_visible TEXT;
+ pub_note TEXT;
+ priv_note TEXT;
+ internal_id TEXT;
+
+ attr_def RECORD;
+ tmp_attr_set RECORD;
+ attr_set vandelay.import_item%ROWTYPE;
+
+ xpath TEXT;
+ tmp_str TEXT;
+
+BEGIN
+
+ SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
+
+ IF FOUND THEN
+
+ attr_set.definition := attr_def.id;
+
+ -- Build the combined XPath
+
+ owning_lib :=
+ CASE
+ WHEN attr_def.owning_lib IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib
+ END;
+
+ circ_lib :=
+ CASE
+ WHEN attr_def.circ_lib IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib
+ END;
+
+ call_number :=
+ CASE
+ WHEN attr_def.call_number IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number
+ END;
+
+ copy_number :=
+ CASE
+ WHEN attr_def.copy_number IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number
+ END;
+
+ status :=
+ CASE
+ WHEN attr_def.status IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status
+ END;
+
+ location :=
+ CASE
+ WHEN attr_def.location IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location
+ END;
+
+ circulate :=
+ CASE
+ WHEN attr_def.circulate IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate
+ END;
+
+ deposit :=
+ CASE
+ WHEN attr_def.deposit IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit
+ END;
+
+ deposit_amount :=
+ CASE
+ WHEN attr_def.deposit_amount IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount
+ END;
+
+ ref :=
+ CASE
+ WHEN attr_def.ref IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref
+ END;
+
+ holdable :=
+ CASE
+ WHEN attr_def.holdable IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable
+ END;
+
+ price :=
+ CASE
+ WHEN attr_def.price IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price
+ END;
+
+ barcode :=
+ CASE
+ WHEN attr_def.barcode IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode
+ END;
+
+ circ_modifier :=
+ CASE
+ WHEN attr_def.circ_modifier IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier
+ END;
+
+ circ_as_type :=
+ CASE
+ WHEN attr_def.circ_as_type IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type
+ END;
+
+ alert_message :=
+ CASE
+ WHEN attr_def.alert_message IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message
+ END;
+
+ opac_visible :=
+ CASE
+ WHEN attr_def.opac_visible IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible
+ END;
+
+ pub_note :=
+ CASE
+ WHEN attr_def.pub_note IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note
+ END;
+ priv_note :=
+ CASE
+ WHEN attr_def.priv_note IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note
+ END;
+
+ internal_id :=
+ CASE
+ WHEN attr_def.internal_id IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.internal_id ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.internal_id || '"]'
+ ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.internal_id
+ END;
+
+
+
+ xpath :=
+ owning_lib || '|' ||
+ circ_lib || '|' ||
+ call_number || '|' ||
+ copy_number || '|' ||
+ status || '|' ||
+ location || '|' ||
+ circulate || '|' ||
+ deposit || '|' ||
+ deposit_amount || '|' ||
+ ref || '|' ||
+ holdable || '|' ||
+ price || '|' ||
+ barcode || '|' ||
+ circ_modifier || '|' ||
+ circ_as_type || '|' ||
+ alert_message || '|' ||
+ pub_note || '|' ||
+ priv_note || '|' ||
+ internal_id || '|' ||
+ opac_visible;
+
+ FOR tmp_attr_set IN
+ SELECT *
+ FROM oils_xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id )
+ AS t( id INT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
+ dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
+ circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, internal_id TEXT, opac_vis TEXT )
+ LOOP
+
+ attr_set.import_error := NULL;
+ attr_set.error_detail := NULL;
+ attr_set.deposit_amount := NULL;
+ attr_set.copy_number := NULL;
+ attr_set.price := NULL;
+ attr_set.circ_modifier := NULL;
+ attr_set.location := NULL;
+ attr_set.barcode := NULL;
+ attr_set.call_number := NULL;
+
+ IF tmp_attr_set.pr != '' THEN
+ tmp_str = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
+ IF tmp_str = '' THEN
+ attr_set.import_error := 'import.item.invalid.price';
+ attr_set.error_detail := tmp_attr_set.pr; -- original value
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ attr_set.price := tmp_str::NUMERIC(8,2);
+ END IF;
+
+ IF tmp_attr_set.dep_amount != '' THEN
+ tmp_str = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
+ IF tmp_str = '' THEN
+ attr_set.import_error := 'import.item.invalid.deposit_amount';
+ attr_set.error_detail := tmp_attr_set.dep_amount;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ attr_set.deposit_amount := tmp_str::NUMERIC(8,2);
+ END IF;
+
+ IF tmp_attr_set.cnum != '' THEN
+ tmp_str = REGEXP_REPLACE(tmp_attr_set.cnum, E'[^0-9]', '', 'g');
+ IF tmp_str = '' THEN
+ attr_set.import_error := 'import.item.invalid.copy_number';
+ attr_set.error_detail := tmp_attr_set.cnum;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ attr_set.copy_number := tmp_str::INT;
+ END IF;
+
+ IF tmp_attr_set.ol != '' THEN
+ SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.owning_lib';
+ attr_set.error_detail := tmp_attr_set.ol;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF tmp_attr_set.clib != '' THEN
+ SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_lib';
+ attr_set.error_detail := tmp_attr_set.clib;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF tmp_attr_set.cs != '' THEN
+ SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.status';
+ attr_set.error_detail := tmp_attr_set.cs;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF COALESCE(tmp_attr_set.circ_mod, '') = '' THEN
+
+ -- no circ mod defined, see if we should apply a default
+ SELECT INTO attr_set.circ_modifier TRIM(BOTH '"' FROM value)
+ FROM actor.org_unit_ancestor_setting(
+ 'vandelay.item.circ_modifier.default',
+ attr_set.owning_lib
+ );
+
+ -- make sure the value from the org setting is still valid
+ PERFORM 1 FROM config.circ_modifier WHERE code = attr_set.circ_modifier;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_modifier';
+ attr_set.error_detail := tmp_attr_set.circ_mod;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+
+ ELSE
+
+ SELECT code INTO attr_set.circ_modifier FROM config.circ_modifier WHERE code = tmp_attr_set.circ_mod;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_modifier';
+ attr_set.error_detail := tmp_attr_set.circ_mod;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF tmp_attr_set.circ_as != '' THEN
+ SELECT code INTO attr_set.circ_as_type FROM config.coded_value_map WHERE ctype = 'item_type' AND code = tmp_attr_set.circ_as;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_as_type';
+ attr_set.error_detail := tmp_attr_set.circ_as;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF COALESCE(tmp_attr_set.cl, '') = '' THEN
+ -- no location specified, see if we should apply a default
+
+ SELECT INTO attr_set.location TRIM(BOTH '"' FROM value)
+ FROM actor.org_unit_ancestor_setting(
+ 'vandelay.item.copy_location.default',
+ attr_set.owning_lib
+ );
+
+ -- make sure the value from the org setting is still valid
+ PERFORM 1 FROM asset.copy_location WHERE id = attr_set.location;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.location';
+ attr_set.error_detail := tmp_attr_set.cs;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ ELSE
+
+ -- search up the org unit tree for a matching copy location
+ WITH RECURSIVE anscestor_depth AS (
+ SELECT ou.id,
+ out.depth AS depth,
+ ou.parent_ou
+ FROM actor.org_unit ou
+ JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
+ WHERE ou.id = COALESCE(attr_set.owning_lib, attr_set.circ_lib)
+ UNION ALL
+ SELECT ou.id,
+ out.depth,
+ ou.parent_ou
+ FROM actor.org_unit ou
+ JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
+ JOIN anscestor_depth ot ON (ot.parent_ou = ou.id)
+ ) SELECT cpl.id INTO attr_set.location
+ FROM anscestor_depth a
+ JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id)
+ WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl)
+ ORDER BY a.depth DESC
+ LIMIT 1;
+
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.location';
+ attr_set.error_detail := tmp_attr_set.cs;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ attr_set.circulate :=
+ LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
+
+ attr_set.deposit :=
+ LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
+
+ attr_set.holdable :=
+ LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
+
+ attr_set.opac_visible :=
+ LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
+
+ attr_set.ref :=
+ LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
+
+ attr_set.call_number := tmp_attr_set.cn; -- TEXT
+ attr_set.barcode := tmp_attr_set.bc; -- TEXT,
+ attr_set.alert_message := tmp_attr_set.amessage; -- TEXT,
+ attr_set.pub_note := tmp_attr_set.note; -- TEXT,
+ attr_set.priv_note := tmp_attr_set.pnote; -- TEXT,
+ attr_set.alert_message := tmp_attr_set.amessage; -- TEXT,
+ attr_set.internal_id := tmp_attr_set.internal_id::BIGINT;
+
+ RETURN NEXT attr_set;
+
+ END LOOP;
+
+ END IF;
+
+ RETURN;
+
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+SELECT evergreen.upgrade_deps_block_check('0826', :eg_version);
+
+INSERT INTO permission.perm_list ( id, code, description ) VALUES (
+ 551,
+ 'ADMIN_SERVER_ADDON_FOR_WORKSTATION',
+ oils_i18n_gettext(
+ 551,
+ 'Allows a user to specify which Server Add-ons get invoked at the current workstation',
+ 'ppl',
+ 'description'
+ )
+);
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0828', :eg_version);
+
+INSERT into config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+VALUES (
+ 'opac.holds.org_unit_not_pickup_lib',
+ 'opac',
+ oils_i18n_gettext('opac.holds.org_unit_not_pickup_lib',
+ 'OPAC: Org Unit is not a hold pickup library',
+ 'coust', 'label'),
+ oils_i18n_gettext('opac.holds.org_unit_not_pickup_lib',
+ 'If set, this org unit will not be offered to the patron as an '||
+ 'option for a hold pickup location. This setting has no affect '||
+ 'on searching or hold targeting',
+ 'coust', 'description'),
+ 'bool'
+);
+
+
+--
+-- Adds a setting for selecting the number of items per page of a my list.
+--
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0829', :eg_version);
+
+INSERT INTO config.usr_setting_type (name,opac_visible,label,description,datatype)
+ VALUES (
+ 'opac.list_items_per_page',
+ TRUE,
+ oils_i18n_gettext(
+ 'opac.list_items_per_page',
+ 'List Items per Page',
+ 'cust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'opac.list_items_per_page',
+ 'A number designating the amount of list items displayed per page of a selected list.',
+ 'cust',
+ 'description'
+ ),
+ 'string'
+ );
+
+--
+-- Adds a setting for selecting the number of lists per page for my list.
+--
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0830', :eg_version);
+
+INSERT INTO config.usr_setting_type (name,opac_visible,label,description,datatype)
+ VALUES (
+ 'opac.lists_per_page',
+ TRUE,
+ oils_i18n_gettext(
+ 'opac.lists_per_page',
+ 'Lists per Page',
+ 'cust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'opac.lists_per_page',
+ 'A number designating the amount of lists displayed per page.',
+ 'cust',
+ 'description'
+ ),
+ 'string'
+ );
+
+
+SELECT evergreen.upgrade_deps_block_check('0831', :eg_version);
+
+-- TODO: check for penalty ID collision before master merge; affects
+-- config.standing_penalty and actor.calculate_system_penalties
+
+INSERT INTO config.standing_penalty
+ (id, name, label, block_list, staff_alert)
+VALUES (
+ 35,
+ 'PATRON_EXCEEDS_LONGOVERDUE_COUNT',
+ oils_i18n_gettext(
+ 35,
+ 'Patron Exceeds Max Long-Overdue Threshold',
+ 'csp',
+ 'label'
+ ),
+ 'CIRC|FULFILL|HOLD|CAPTURE|RENEW',
+ TRUE
+);
+
+
+CREATE OR REPLACE FUNCTION actor.calculate_system_penalties( match_user INT, context_org INT ) RETURNS SETOF actor.usr_standing_penalty AS $func$
+DECLARE
+ user_object actor.usr%ROWTYPE;
+ new_sp_row actor.usr_standing_penalty%ROWTYPE;
+ existing_sp_row actor.usr_standing_penalty%ROWTYPE;
+ collections_fines permission.grp_penalty_threshold%ROWTYPE;
+ max_fines permission.grp_penalty_threshold%ROWTYPE;
+ max_overdue permission.grp_penalty_threshold%ROWTYPE;
+ max_items_out permission.grp_penalty_threshold%ROWTYPE;
+ max_lost permission.grp_penalty_threshold%ROWTYPE;
+ max_longoverdue permission.grp_penalty_threshold%ROWTYPE;
+ tmp_grp INT;
+ items_overdue INT;
+ items_out INT;
+ items_lost INT;
+ items_longoverdue INT;
+ context_org_list INT[];
+ current_fines NUMERIC(8,2) := 0.0;
+ tmp_fines NUMERIC(8,2);
+ tmp_groc RECORD;
+ tmp_circ RECORD;
+ tmp_org actor.org_unit%ROWTYPE;
+ tmp_penalty config.standing_penalty%ROWTYPE;
+ tmp_depth INTEGER;
+BEGIN
+ SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+
+ -- Max fines
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has a high fine balance
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 1 AND org_unit = tmp_org.id;
+
+ IF max_fines.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_fines.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 1;
+
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+ SELECT SUM(f.balance_owed) INTO current_fines
+ FROM money.materialized_billable_xact_summary f
+ JOIN (
+ SELECT r.id
+ FROM booking.reservation r
+ WHERE r.usr = match_user
+ AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+ AND xact_finish IS NULL
+ UNION ALL
+ SELECT g.id
+ FROM money.grocery g
+ WHERE g.usr = match_user
+ AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+ AND xact_finish IS NULL
+ UNION ALL
+ SELECT circ.id
+ FROM action.circulation circ
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND xact_finish IS NULL ) l USING (id);
+
+ IF current_fines >= max_fines.threshold THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_fines.org_unit;
+ new_sp_row.standing_penalty := 1;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for max overdue
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many overdue items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+
+ SELECT * INTO max_overdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 2 AND org_unit = tmp_org.id;
+
+ IF max_overdue.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_overdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_overdue.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_overdue.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 2;
+
+ SELECT INTO items_overdue COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_overdue.org_unit ) fp ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND circ.due_date < NOW()
+ AND (circ.stop_fines = 'MAXFINES' OR circ.stop_fines IS NULL);
+
+ IF items_overdue >= max_overdue.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_overdue.org_unit;
+ new_sp_row.standing_penalty := 2;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for max out
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many checked out items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_items_out FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 3 AND org_unit = tmp_org.id;
+
+ IF max_items_out.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_items_out.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+
+ -- Fail if the user has too many items checked out
+ IF max_items_out.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_items_out.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 3;
+
+ SELECT INTO items_out COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines IN (
+ SELECT 'MAXFINES'::TEXT
+ UNION ALL
+ SELECT 'LONGOVERDUE'::TEXT
+ UNION ALL
+ SELECT 'LOST'::TEXT
+ WHERE 'true' ILIKE
+ (
+ SELECT CASE
+ WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.tally_lost', circ.circ_lib)) ILIKE 'true' THEN 'true'
+ ELSE 'false'
+ END
+ )
+ UNION ALL
+ SELECT 'CLAIMSRETURNED'::TEXT
+ WHERE 'false' ILIKE
+ (
+ SELECT CASE
+ WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.do_not_tally_claims_returned', circ.circ_lib)) ILIKE 'true' THEN 'true'
+ ELSE 'false'
+ END
+ )
+ ) OR circ.stop_fines IS NULL)
+ AND xact_finish IS NULL;
+
+ IF items_out >= max_items_out.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_items_out.org_unit;
+ new_sp_row.standing_penalty := 3;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for max lost
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many lost items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+
+ SELECT * INTO max_lost FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 5 AND org_unit = tmp_org.id;
+
+ IF max_lost.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_lost.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_lost.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_lost.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 5;
+
+ SELECT INTO items_lost COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_lost.org_unit ) fp ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines = 'LOST')
+ AND xact_finish IS NULL;
+
+ IF items_lost >= max_lost.threshold::INT AND 0 < max_lost.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_lost.org_unit;
+ new_sp_row.standing_penalty := 5;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for max longoverdue
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has too many longoverdue items
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+
+ SELECT * INTO max_longoverdue
+ FROM permission.grp_penalty_threshold
+ WHERE grp = tmp_grp AND
+ penalty = 35 AND
+ org_unit = tmp_org.id;
+
+ IF max_longoverdue.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp
+ FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_longoverdue.threshold IS NOT NULL
+ OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_longoverdue.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_longoverdue.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 35;
+
+ SELECT INTO items_longoverdue COUNT(*)
+ FROM action.circulation circ
+ JOIN actor.org_unit_full_path( max_longoverdue.org_unit ) fp
+ ON (circ.circ_lib = fp.id)
+ WHERE circ.usr = match_user
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines = 'LONGOVERDUE')
+ AND xact_finish IS NULL;
+
+ IF items_longoverdue >= max_longoverdue.threshold::INT
+ AND 0 < max_longoverdue.threshold::INT THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_longoverdue.org_unit;
+ new_sp_row.standing_penalty := 35;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+
+ -- Start over for collections warning
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Fail if the user has a collections-level fine balance
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 4 AND org_unit = tmp_org.id;
+
+ IF max_fines.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL THEN
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_fines.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 4;
+
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+ SELECT SUM(f.balance_owed) INTO current_fines
+ FROM money.materialized_billable_xact_summary f
+ JOIN (
+ SELECT r.id
+ FROM booking.reservation r
+ WHERE r.usr = match_user
+ AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+ AND r.xact_finish IS NULL
+ UNION ALL
+ SELECT g.id
+ FROM money.grocery g
+ WHERE g.usr = match_user
+ AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+ AND g.xact_finish IS NULL
+ UNION ALL
+ SELECT circ.id
+ FROM action.circulation circ
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND circ.xact_finish IS NULL ) l USING (id);
+
+ IF current_fines >= max_fines.threshold THEN
+ new_sp_row.usr := match_user;
+ new_sp_row.org_unit := max_fines.org_unit;
+ new_sp_row.standing_penalty := 4;
+ RETURN NEXT new_sp_row;
+ END IF;
+ END IF;
+
+ -- Start over for in collections
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+ -- Remove the in-collections penalty if the user has paid down enough
+ -- This penalty is different, because this code is not responsible for creating
+ -- new in-collections penalties, only for removing them
+ LOOP
+ tmp_grp := user_object.profile;
+ LOOP
+ SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 30 AND org_unit = tmp_org.id;
+
+ IF max_fines.threshold IS NULL THEN
+ SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+ ELSE
+ EXIT;
+ END IF;
+
+ IF tmp_grp IS NULL THEN
+ EXIT;
+ END IF;
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+ END LOOP;
+
+ IF max_fines.threshold IS NOT NULL THEN
+
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+ -- first, see if the user had paid down to the threshold
+ SELECT SUM(f.balance_owed) INTO current_fines
+ FROM money.materialized_billable_xact_summary f
+ JOIN (
+ SELECT r.id
+ FROM booking.reservation r
+ WHERE r.usr = match_user
+ AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+ AND r.xact_finish IS NULL
+ UNION ALL
+ SELECT g.id
+ FROM money.grocery g
+ WHERE g.usr = match_user
+ AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+ AND g.xact_finish IS NULL
+ UNION ALL
+ SELECT circ.id
+ FROM action.circulation circ
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND circ.xact_finish IS NULL ) l USING (id);
+
+ IF current_fines IS NULL OR current_fines <= max_fines.threshold THEN
+ -- patron has paid down enough
+
+ SELECT INTO tmp_penalty * FROM config.standing_penalty WHERE id = 30;
+
+ IF tmp_penalty.org_depth IS NOT NULL THEN
+
+ -- since this code is not responsible for applying the penalty, it can't
+ -- guarantee the current context org will match the org at which the penalty
+ --- was applied. search up the org tree until we hit the configured penalty depth
+ SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+ SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+
+ WHILE tmp_depth >= tmp_penalty.org_depth LOOP
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = tmp_org.id
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 30;
+
+ IF tmp_org.parent_ou IS NULL THEN
+ EXIT;
+ END IF;
+
+ SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+ SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+ END LOOP;
+
+ ELSE
+
+ -- no penalty depth is defined, look for exact matches
+
+ RETURN QUERY
+ SELECT *
+ FROM actor.usr_standing_penalty
+ WHERE usr = match_user
+ AND org_unit = max_fines.org_unit
+ AND (stop_date IS NULL or stop_date > NOW())
+ AND standing_penalty = 30;
+ END IF;
+
+ END IF;
+
+ END IF;
+
+ RETURN;
+END;
+$func$ LANGUAGE plpgsql;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0832', :eg_version);
+
+ALTER TABLE serial.subscription_note
+ ADD COLUMN alert BOOL NOT NULL DEFAULT FALSE;
+
+ALTER TABLE serial.distribution_note
+ ADD COLUMN alert BOOL NOT NULL DEFAULT FALSE;
+
+ALTER TABLE serial.item_note
+ ADD COLUMN alert BOOL NOT NULL DEFAULT FALSE;
+
+
+SELECT evergreen.upgrade_deps_block_check('0833', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, datatype, label, description)
+VALUES (
+ 'opac.self_register.timeout',
+ 'opac',
+ 'integer',
+ oils_i18n_gettext(
+ 'opac.self_register.timeout',
+ 'Patron Self-Reg. Display Timeout',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'opac.self_register.timeout',
+ 'Number of seconds to wait before reloading the patron self-'||
+ 'registration interface to clear sensitive data',
+ 'coust',
+ 'description'
+ )
+);
+
+
+SELECT evergreen.upgrade_deps_block_check('0834', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, datatype, label, description)
+VALUES (
+ 'ui.circ.items_out.longoverdue', 'gui', 'integer',
+ oils_i18n_gettext(
+ 'ui.circ.items_out.longoverdue',
+ 'Items Out Long-Overdue display setting',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.circ.items_out.longoverdue',
+'Value is a numeric code, describing which list the circulation '||
+'should appear while checked out and whether the circulation should '||
+'continue to appear in the bottom list, when checked in with '||
+'oustanding fines. '||
+'1 = top list, bottom list. 2 = bottom list, bottom list. ' ||
+'5 = top list, do not display. 6 = bottom list, do not display.',
+ 'coust',
+ 'description'
+ )
+), (
+ 'ui.circ.items_out.lost', 'gui', 'integer',
+ oils_i18n_gettext(
+ 'ui.circ.items_out.lost',
+ 'Items Out Lost display setting',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.circ.items_out.lost',
+'Value is a numeric code, describing which list the circulation '||
+'should appear while checked out and whether the circulation should '||
+'continue to appear in the bottom list, when checked in with '||
+'oustanding fines. '||
+'1 = top list, bottom list. 2 = bottom list, bottom list. ' ||
+'5 = top list, do not display. 6 = bottom list, do not display.',
+ 'coust',
+ 'description'
+ )
+), (
+ 'ui.circ.items_out.claimsreturned', 'gui', 'integer',
+ oils_i18n_gettext(
+ 'ui.circ.items_out.claimsreturned',
+ 'Items Out Claims Returned display setting',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.circ.items_out.claimsreturned',
+'Value is a numeric code, describing which list the circulation '||
+'should appear while checked out and whether the circulation should '||
+'continue to appear in the bottom list, when checked in with '||
+'oustanding fines. '||
+'1 = top list, bottom list. 2 = bottom list, bottom list. ' ||
+'5 = top list, do not display. 6 = bottom list, do not display.',
+ 'coust',
+ 'description'
+ )
+);
+
+
+SELECT evergreen.upgrade_deps_block_check('0835', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+ (grp, name, datatype, label, description)
+VALUES (
+ 'finance',
+ 'circ.disable_patron_credit',
+ 'bool',
+ oils_i18n_gettext(
+ 'circ.disable_patron_credit',
+ 'Disable Patron Credit',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.disable_patron_credit',
+ 'Do not allow patrons to accrue credit or pay fines/fees with accrued credit',
+ 'coust',
+ 'description'
+ )
+);
+
+
+SELECT evergreen.upgrade_deps_block_check('0836', :eg_version);
+
+CREATE TABLE config.floating_group (
+ id SERIAL PRIMARY KEY,
+ name TEXT UNIQUE NOT NULL,
+ manual BOOL NOT NULL DEFAULT FALSE
+ );
+
+CREATE TABLE config.floating_group_member (
+ id SERIAL PRIMARY KEY,
+ floating_group INT NOT NULL REFERENCES config.floating_group (id),
+ org_unit INT NOT NULL REFERENCES actor.org_unit (id),
+ stop_depth INT NOT NULL DEFAULT 0,
+ max_depth INT,
+ exclude BOOL NOT NULL DEFAULT FALSE
+ );
+
+CREATE OR REPLACE FUNCTION evergreen.can_float( copy_floating_group integer, from_ou integer, to_ou integer ) RETURNS BOOL AS $f$
+DECLARE
+ float_member config.floating_group_member%ROWTYPE;
+ shared_ou_depth INT;
+ to_ou_depth INT;
+BEGIN
+ -- Grab the shared OU depth. If this is less than the stop depth later we ignore the entry.
+ SELECT INTO shared_ou_depth max(depth) FROM actor.org_unit_common_ancestors( from_ou, to_ou ) aou JOIN actor.org_unit_type aout ON aou.ou_type = aout.id;
+ -- Grab the to ou depth. If this is greater than max depth we ignore the entry.
+ SELECT INTO to_ou_depth depth FROM actor.org_unit aou JOIN actor.org_unit_type aout ON aou.ou_type = aout.id WHERE aou.id = to_ou;
+ -- Grab float members that apply. We don't care what we get beyond wanting excluded ones first.
+ SELECT INTO float_member *
+ FROM
+ config.floating_group_member cfgm
+ JOIN actor.org_unit aou ON cfgm.org_unit = aou.id
+ JOIN actor.org_unit_type aout ON aou.ou_type = aout.id
+ WHERE
+ cfgm.floating_group = copy_floating_group
+ AND to_ou IN (SELECT id FROM actor.org_unit_descendants(aou.id))
+ AND cfgm.stop_depth <= shared_ou_depth
+ AND (cfgm.max_depth IS NULL OR to_ou_depth <= max_depth)
+ ORDER BY
+ exclude DESC;
+ -- If we found something then we want to return the opposite of the exclude flag
+ IF FOUND THEN
+ RETURN NOT float_member.exclude;
+ END IF;
+ -- Otherwise no floating.
+ RETURN false;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+INSERT INTO config.floating_group(name) VALUES ('Everywhere');
+INSERT INTO config.floating_group_member(floating_group, org_unit) VALUES (1, 1);
+
+-- We need to drop these before we can update asset.copy
+DROP VIEW auditor.asset_copy_lifecycle;
+DROP VIEW auditor.serial_unit_lifecycle;
+
+-- Update the appropriate auditor tables
+ALTER TABLE auditor.asset_copy_history
+ ALTER COLUMN floating DROP DEFAULT,
+ ALTER COLUMN floating DROP NOT NULL,
+ ALTER COLUMN floating TYPE int USING CASE WHEN floating THEN 1 ELSE NULL END;
+ALTER TABLE auditor.serial_unit_history
+ ALTER COLUMN floating DROP DEFAULT,
+ ALTER COLUMN floating DROP NOT NULL,
+ ALTER COLUMN floating TYPE int USING CASE WHEN floating THEN 1 ELSE NULL END;
+
+-- Update asset.copy itself (does not appear to trigger update triggers!)
+ALTER TABLE asset.copy
+ ALTER COLUMN floating DROP DEFAULT,
+ ALTER COLUMN floating DROP NOT NULL,
+ ALTER COLUMN floating TYPE int USING CASE WHEN floating THEN 1 ELSE NULL END;
+
+ALTER TABLE asset.copy ADD CONSTRAINT asset_copy_floating_fkey FOREIGN KEY (floating) REFERENCES config.floating_group (id) DEFERRABLE INITIALLY DEFERRED;
+
+-- Update asset.copy_template too
+ALTER TABLE asset.copy_template
+ ALTER COLUMN floating TYPE int USING CASE WHEN floating THEN 1 ELSE NULL END;
+ALTER TABLE asset.copy_template ADD CONSTRAINT asset_copy_template_floating_fkey FOREIGN KEY (floating) REFERENCES config.floating_group (id) DEFERRABLE INITIALLY DEFERRED;
+
+INSERT INTO permission.perm_list( code, description) VALUES
+('ADMIN_FLOAT_GROUPS', 'Allows administration of floating groups');
+
+-- And lets just update all auditors to re-create those lifecycle views
+SELECT auditor.update_auditors();
+
+-- Evergreen DB patch 0837.schema.browse-auth-linking.plus-joiner.sql
+--
+-- In this upgrade script we complete inter-subfield joiner support, so that
+-- subject components can be separated by " -- ", for instance. That's the
+-- easy part.
+--
+-- We also add the ability to browse by in-use authority main entries and find
+-- bibs that use unauthorized versions of the authority's value, by string matching.
+--
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0837', :eg_version);
+
+ALTER TABLE config.metabib_field ADD COLUMN joiner TEXT;
+UPDATE config.metabib_field SET joiner = ' -- ' WHERE field_class = 'subject' AND name NOT IN ('name', 'complete');
+
+-- To avoid problems with altering a table column after doing an
+-- update.
+ALTER TABLE authority.control_set_authority_field DISABLE TRIGGER ALL;
+
+ALTER TABLE authority.control_set_authority_field ADD COLUMN joiner TEXT;
+UPDATE authority.control_set_authority_field SET joiner = ' -- ' WHERE tag LIKE ANY (ARRAY['_4_','_5_','_8_']);
+
+ALTER TABLE authority.control_set_authority_field ENABLE TRIGGER ALL;
+
+-- Seed data will be generated from class <-> axis mapping
+CREATE TABLE authority.control_set_bib_field_metabib_field_map (
+ id SERIAL PRIMARY KEY,
+ bib_field INT NOT NULL REFERENCES authority.control_set_bib_field (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ metabib_field INT NOT NULL REFERENCES config.metabib_field (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ CONSTRAINT a_bf_mf_map_once UNIQUE (bib_field, metabib_field)
+);
+
+CREATE VIEW authority.control_set_auth_field_metabib_field_map_main AS
+ SELECT DISTINCT b.authority_field, m.metabib_field
+ FROM authority.control_set_bib_field_metabib_field_map m JOIN authority.control_set_bib_field b ON (b.id = m.bib_field);
+COMMENT ON VIEW authority.control_set_auth_field_metabib_field_map_main IS $$metabib fields for main entry auth fields$$;
+
+CREATE VIEW authority.control_set_auth_field_metabib_field_map_refs_only AS
+ SELECT DISTINCT a.id AS authority_field, m.metabib_field
+ FROM authority.control_set_authority_field a
+ JOIN authority.control_set_authority_field ame ON (a.main_entry = ame.id)
+ JOIN authority.control_set_bib_field b ON (b.authority_field = ame.id)
+ JOIN authority.control_set_bib_field_metabib_field_map mf ON (mf.bib_field = b.id)
+ JOIN authority.control_set_auth_field_metabib_field_map_main m ON (ame.id = m.authority_field);
+COMMENT ON VIEW authority.control_set_auth_field_metabib_field_map_refs_only IS $$metabib fields for NON-main entry auth fields$$;
+
+CREATE VIEW authority.control_set_auth_field_metabib_field_map_refs AS
+ SELECT * FROM authority.control_set_auth_field_metabib_field_map_main
+ UNION
+ SELECT * FROM authority.control_set_auth_field_metabib_field_map_refs_only;
+COMMENT ON VIEW authority.control_set_auth_field_metabib_field_map_refs IS $$metabib fields for all auth fields$$;
+
+
+-- blind refs only is probably what we want for lookup in bib/auth browse
+CREATE VIEW authority.control_set_auth_field_metabib_field_map_blind_refs_only AS
+ SELECT r.*
+ FROM authority.control_set_auth_field_metabib_field_map_refs_only r
+ JOIN authority.control_set_authority_field a ON (r.authority_field = a.id)
+ WHERE linking_subfield IS NULL;
+COMMENT ON VIEW authority.control_set_auth_field_metabib_field_map_blind_refs_only IS $$metabib fields for NON-main entry auth fields that can't be linked to other records$$; -- '
+
+CREATE VIEW authority.control_set_auth_field_metabib_field_map_blind_refs AS
+ SELECT r.*
+ FROM authority.control_set_auth_field_metabib_field_map_refs r
+ JOIN authority.control_set_authority_field a ON (r.authority_field = a.id)
+ WHERE linking_subfield IS NULL;
+COMMENT ON VIEW authority.control_set_auth_field_metabib_field_map_blind_refs IS $$metabib fields for all auth fields that can't be linked to other records$$; -- '
+
+CREATE VIEW authority.control_set_auth_field_metabib_field_map_blind_main AS
+ SELECT r.*
+ FROM authority.control_set_auth_field_metabib_field_map_main r
+ JOIN authority.control_set_authority_field a ON (r.authority_field = a.id)
+ WHERE linking_subfield IS NULL;
+COMMENT ON VIEW authority.control_set_auth_field_metabib_field_map_blind_main IS $$metabib fields for main entry auth fields that can't be linked to other records$$; -- '
+
+CREATE OR REPLACE FUNCTION authority.normalize_heading( marcxml TEXT, no_thesaurus BOOL ) RETURNS TEXT AS $func$
+DECLARE
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ sf_node TEXT;
+ tag_node TEXT;
+ thes_code TEXT;
+ cset INT;
+ heading_text TEXT;
+ tmp_text TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT;
+BEGIN
+ SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+ IF cset IS NULL THEN
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]))
+ LIMIT 1;
+ END IF;
+
+ thes_code := vandelay.marc21_extract_fixed_field(marcxml,'Subj');
+ IF thes_code IS NULL THEN
+ thes_code := '|';
+ ELSIF thes_code = 'z' THEN
+ thes_code := COALESCE( oils_xpath_string('//*[@tag="040"]/*[@code="f"][1]', marcxml), '' );
+ END IF;
+
+ heading_text := '';
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset AND main_entry IS NULL LOOP
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+ first_sf := TRUE;
+
+ FOR tag_node IN SELECT unnest(oils_xpath('//*[@tag="'||tag_used||'"]',marcxml)) LOOP
+ FOR sf_node IN SELECT unnest(oils_xpath('./*[contains("'||acsaf.sf_list||'", at code)]',tag_node)) LOOP
+
+ tmp_text := oils_xpath_string('.', sf_node);
+ sf := oils_xpath_string('./@code', sf_node);
+
+ IF first_sf AND tmp_text IS NOT NULL AND nfi_used IS NOT NULL THEN
+
+ tmp_text := SUBSTRING(
+ tmp_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('./@ind'||nfi_used, tag_node),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ END IF;
+
+ first_sf := FALSE;
+
+ IF tmp_text IS NOT NULL AND tmp_text <> '' THEN
+ heading_text := heading_text || E'\u2021' || sf || ' ' || tmp_text;
+ END IF;
+ END LOOP;
+
+ EXIT WHEN heading_text <> '';
+ END LOOP;
+
+ EXIT WHEN heading_text <> '';
+ END LOOP;
+
+ IF heading_text <> '' THEN
+ IF no_thesaurus IS TRUE THEN
+ heading_text := tag_used || ' ' || public.naco_normalize(heading_text);
+ ELSE
+ heading_text := tag_used || '_' || COALESCE(nfi_used,'-') || '_' || thes_code || ' ' || public.naco_normalize(heading_text);
+ END IF;
+ ELSE
+ heading_text := 'NOHEADING_' || thes_code || ' ' || MD5(marcxml);
+ END IF;
+
+ RETURN heading_text;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION authority.simple_heading_set( marcxml TEXT ) RETURNS SETOF authority.simple_heading AS $func$
+DECLARE
+ res authority.simple_heading%ROWTYPE;
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ cset INT;
+ heading_text TEXT;
+ joiner_text TEXT;
+ sort_text TEXT;
+ tmp_text TEXT;
+ tmp_xml TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT;
+BEGIN
+
+ SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+ IF cset IS NULL THEN
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]))
+ LIMIT 1;
+ END IF;
+
+ res.record := auth_id;
+
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset LOOP
+
+ res.atag := acsaf.id;
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+ joiner_text := COALESCE(acsaf.joiner, ' ');
+
+ FOR tmp_xml IN SELECT UNNEST(XPATH('//*[@tag="'||tag_used||'"]', marcxml::XML)) LOOP
+
+ heading_text := COALESCE(
+ oils_xpath_string('./*[contains("'||acsaf.sf_list||'", at code)]', tmp_xml::TEXT, joiner_text),
+ ''
+ );
+
+ IF nfi_used IS NOT NULL THEN
+
+ sort_text := SUBSTRING(
+ heading_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('./@ind'||nfi_used, tmp_xml::TEXT),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ ELSE
+ sort_text := heading_text;
+ END IF;
+
+ IF heading_text IS NOT NULL AND heading_text <> '' THEN
+ res.value := heading_text;
+ res.sort_value := public.naco_normalize(sort_text);
+ res.index_vector = to_tsvector('keyword'::regconfig, res.sort_value);
+ RETURN NEXT res;
+ END IF;
+
+ END LOOP;
+
+ END LOOP;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+CREATE TABLE metabib.browse_entry_simple_heading_map (
+ id BIGSERIAL PRIMARY KEY,
+ entry BIGINT REFERENCES metabib.browse_entry (id),
+ simple_heading BIGINT REFERENCES authority.simple_heading (id) ON DELETE CASCADE
+);
+CREATE INDEX browse_entry_sh_map_entry_idx ON metabib.browse_entry_simple_heading_map (entry);
+CREATE INDEX browse_entry_sh_map_sh_idx ON metabib.browse_entry_simple_heading_map (simple_heading);
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) 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;
+ 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;
+BEGIN
+
+ -- Start out with no field-use bools set
+ output_row.browse_field = FALSE;
+ output_row.facet_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 ORDER BY format LOOP
+
+ 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()',
+ REGEXP_REPLACE(
+ REGEXP_REPLACE( -- This escapes all &s not followed by "amp;". Data ise returned from oils_xpath (above) in UTF-8, not entity encoded
+ REGEXP_REPLACE( -- This escapes embeded <s
+ xml_node,
+ $re$(>[^<]+)(<)([^>]+<)$re$,
+ E'\\1<\\3',
+ 'g'
+ ),
+ '&(?!amp;)',
+ '&',
+ 'g'
+ ),
+ E'\\s+',
+ ' ',
+ 'g'
+ )
+ ), ' '), ''),
+ 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;
+ RETURN NEXT output_row;
+ output_row.browse_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;
+
+ 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.autosuggest_prepare_tsquery(orig TEXT) RETURNS TEXT[] AS
+$$
+DECLARE
+ orig_ended_in_space BOOLEAN;
+ result RECORD;
+ plain TEXT;
+ normalized TEXT;
+BEGIN
+ orig_ended_in_space := orig ~ E'\\s$';
+
+ orig := ARRAY_TO_STRING(
+ evergreen.regexp_split_to_array(orig, E'\\W+'), ' '
+ );
+
+ normalized := public.naco_normalize(orig); -- also trim()s
+ plain := trim(orig);
+
+ IF NOT orig_ended_in_space THEN
+ plain := plain || ':*';
+ normalized := normalized || ':*';
+ END IF;
+
+ plain := ARRAY_TO_STRING(
+ evergreen.regexp_split_to_array(plain, E'\\s+'), ' & '
+ );
+ normalized := ARRAY_TO_STRING(
+ evergreen.regexp_split_to_array(normalized, E'\\s+'), ' & '
+ );
+
+ RETURN ARRAY[normalized, plain];
+END;
+$$ LANGUAGE PLPGSQL;
+
+ALTER TYPE metabib.flat_browse_entry_appearance ADD ATTRIBUTE sees TEXT;
+ALTER TYPE metabib.flat_browse_entry_appearance ADD ATTRIBUTE asources INT;
+ALTER TYPE metabib.flat_browse_entry_appearance ADD ATTRIBUTE aaccurate TEXT;
+
+CREATE OR REPLACE FUNCTION metabib.browse_bib_pivot(
+ INT[],
+ TEXT
+) RETURNS BIGINT AS $p$
+ SELECT mbe.id
+ FROM metabib.browse_entry mbe
+ JOIN metabib.browse_entry_def_map mbedm ON (
+ mbedm.entry = mbe.id
+ AND mbedm.def = ANY($1)
+ )
+ WHERE mbe.sort_value >= public.naco_normalize($2)
+ ORDER BY mbe.sort_value, mbe.value LIMIT 1;
+$p$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION metabib.browse_authority_pivot(
+ INT[],
+ TEXT
+) RETURNS BIGINT AS $p$
+ SELECT mbe.id
+ FROM metabib.browse_entry mbe
+ JOIN metabib.browse_entry_simple_heading_map mbeshm ON ( mbeshm.entry = mbe.id )
+ JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
+ JOIN authority.control_set_auth_field_metabib_field_map_refs map ON (
+ ash.atag = map.authority_field
+ AND map.metabib_field = ANY($1)
+ )
+ WHERE mbe.sort_value >= public.naco_normalize($2)
+ ORDER BY mbe.sort_value, mbe.value LIMIT 1;
+$p$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION metabib.browse_authority_refs_pivot(
+ INT[],
+ TEXT
+) RETURNS BIGINT AS $p$
+ SELECT mbe.id
+ FROM metabib.browse_entry mbe
+ JOIN metabib.browse_entry_simple_heading_map mbeshm ON ( mbeshm.entry = mbe.id )
+ JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
+ JOIN authority.control_set_auth_field_metabib_field_map_refs_only map ON (
+ ash.atag = map.authority_field
+ AND map.metabib_field = ANY($1)
+ )
+ WHERE mbe.sort_value >= public.naco_normalize($2)
+ ORDER BY mbe.sort_value, mbe.value LIMIT 1;
+$p$ LANGUAGE SQL;
+
+-- The drop is necessary because the language change from PLPGSQL to SQL
+-- carries with it name changes to the parameters
+DROP FUNCTION metabib.browse_pivot(INT[], TEXT);
+CREATE FUNCTION metabib.browse_pivot(
+ INT[],
+ TEXT
+) RETURNS BIGINT AS $p$
+ SELECT id FROM metabib.browse_entry
+ WHERE id IN (
+ metabib.browse_bib_pivot($1, $2),
+ metabib.browse_authority_refs_pivot($1,$2) -- only look in 4xx, 5xx, 7xx of authority
+ )
+ ORDER BY sort_value, value LIMIT 1;
+$p$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION metabib.staged_browse(
+ query TEXT,
+ fields INT[],
+ context_org INT,
+ context_locations INT[],
+ staff BOOL,
+ browse_superpage_size INT,
+ count_up_from_zero BOOL, -- if false, count down from -1
+ result_limit INT,
+ next_pivot_pos INT
+) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
+DECLARE
+ curs REFCURSOR;
+ rec RECORD;
+ qpfts_query TEXT;
+ aqpfts_query TEXT;
+ afields INT[];
+ bfields INT[];
+ result_row metabib.flat_browse_entry_appearance%ROWTYPE;
+ results_skipped INT := 0;
+ row_counter INT := 0;
+ row_number INT;
+ slice_start INT;
+ slice_end INT;
+ full_end INT;
+ all_records BIGINT[];
+ all_brecords BIGINT[];
+ all_arecords BIGINT[];
+ superpage_of_records BIGINT[];
+ superpage_size INT;
+BEGIN
+ IF count_up_from_zero THEN
+ row_number := 0;
+ ELSE
+ row_number := -1;
+ END IF;
+
+ OPEN curs FOR EXECUTE query;
+
+ LOOP
+ FETCH curs INTO rec;
+ IF NOT FOUND THEN
+ IF result_row.pivot_point IS NOT NULL THEN
+ RETURN NEXT result_row;
+ END IF;
+ RETURN;
+ END IF;
+
+
+ -- Gather aggregate data based on the MBE row we're looking at now, authority axis
+ SELECT INTO all_arecords, result_row.sees, afields
+ ARRAY_AGG(DISTINCT abl.bib), -- bibs to check for visibility
+ ARRAY_TO_STRING(ARRAY_AGG(DISTINCT aal.source), $$,$$), -- authority record ids
+ ARRAY_AGG(DISTINCT map.metabib_field) -- authority-tag-linked CMF rows
+
+ FROM metabib.browse_entry_simple_heading_map mbeshm
+ JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
+ JOIN authority.authority_linking aal ON ( ash.record = aal.source )
+ JOIN authority.bib_linking abl ON ( aal.target = abl.authority )
+ JOIN authority.control_set_auth_field_metabib_field_map_refs map ON (
+ ash.atag = map.authority_field
+ AND map.metabib_field = ANY(fields)
+ )
+ WHERE mbeshm.entry = rec.id;
+
+
+ -- Gather aggregate data based on the MBE row we're looking at now, bib axis
+ SELECT INTO all_brecords, result_row.authorities, bfields
+ ARRAY_AGG(DISTINCT source),
+ ARRAY_TO_STRING(ARRAY_AGG(DISTINCT authority), $$,$$),
+ ARRAY_AGG(DISTINCT def)
+ FROM metabib.browse_entry_def_map
+ WHERE entry = rec.id
+ AND def = ANY(fields);
+
+ SELECT INTO result_row.fields ARRAY_TO_STRING(ARRAY_AGG(DISTINCT x), $$,$$) FROM UNNEST(afields || bfields) x;
+
+ result_row.sources := 0;
+ result_row.asources := 0;
+
+ -- Bib-linked vis checking
+ IF ARRAY_UPPER(all_brecords,1) IS NOT NULL THEN
+
+ full_end := ARRAY_LENGTH(all_brecords, 1);
+ superpage_size := COALESCE(browse_superpage_size, full_end);
+ slice_start := 1;
+ slice_end := superpage_size;
+
+ WHILE result_row.sources = 0 AND slice_start <= full_end LOOP
+ superpage_of_records := all_brecords[slice_start:slice_end];
+ qpfts_query :=
+ 'SELECT NULL::BIGINT AS id, ARRAY[r] AS records, ' ||
+ '1::INT AS rel FROM (SELECT UNNEST(' ||
+ quote_literal(superpage_of_records) || '::BIGINT[]) AS r) rr';
+
+ -- We use search.query_parser_fts() for visibility testing.
+ -- We're calling it once per browse-superpage worth of records
+ -- out of the set of records related to a given mbe, until we've
+ -- either exhausted that set of records or found at least 1
+ -- visible record.
+
+ SELECT INTO result_row.sources visible
+ FROM search.query_parser_fts(
+ context_org, NULL, qpfts_query, NULL,
+ context_locations, 0, NULL, NULL, FALSE, staff, FALSE
+ ) qpfts
+ WHERE qpfts.rel IS NULL;
+
+ slice_start := slice_start + superpage_size;
+ slice_end := slice_end + superpage_size;
+ END LOOP;
+
+ -- Accurate? Well, probably.
+ result_row.accurate := browse_superpage_size IS NULL OR
+ browse_superpage_size >= full_end;
+
+ END IF;
+
+ -- Authority-linked vis checking
+ IF ARRAY_UPPER(all_arecords,1) IS NOT NULL THEN
+
+ full_end := ARRAY_LENGTH(all_arecords, 1);
+ superpage_size := COALESCE(browse_superpage_size, full_end);
+ slice_start := 1;
+ slice_end := superpage_size;
+
+ WHILE result_row.asources = 0 AND slice_start <= full_end LOOP
+ superpage_of_records := all_arecords[slice_start:slice_end];
+ qpfts_query :=
+ 'SELECT NULL::BIGINT AS id, ARRAY[r] AS records, ' ||
+ '1::INT AS rel FROM (SELECT UNNEST(' ||
+ quote_literal(superpage_of_records) || '::BIGINT[]) AS r) rr';
+
+ -- We use search.query_parser_fts() for visibility testing.
+ -- We're calling it once per browse-superpage worth of records
+ -- out of the set of records related to a given mbe, via
+ -- authority until we've either exhausted that set of records
+ -- or found at least 1 visible record.
+
+ SELECT INTO result_row.asources visible
+ FROM search.query_parser_fts(
+ context_org, NULL, qpfts_query, NULL,
+ context_locations, 0, NULL, NULL, FALSE, staff, FALSE
+ ) qpfts
+ WHERE qpfts.rel IS NULL;
+
+ slice_start := slice_start + superpage_size;
+ slice_end := slice_end + superpage_size;
+ END LOOP;
+
+
+ -- Accurate? Well, probably.
+ result_row.aaccurate := browse_superpage_size IS NULL OR
+ browse_superpage_size >= full_end;
+
+ END IF;
+
+ IF result_row.sources > 0 OR result_row.asources > 0 THEN
+
+ -- The function that calls this function needs row_number in order
+ -- to correctly order results from two different runs of this
+ -- functions.
+ result_row.row_number := row_number;
+
+ -- Now, if row_counter is still less than limit, return a row. If
+ -- not, but it is less than next_pivot_pos, continue on without
+ -- returning actual result rows until we find
+ -- that next pivot, and return it.
+
+ IF row_counter < result_limit THEN
+ result_row.browse_entry := rec.id;
+ result_row.value := rec.value;
+
+ RETURN NEXT result_row;
+ ELSE
+ result_row.browse_entry := NULL;
+ result_row.authorities := NULL;
+ result_row.fields := NULL;
+ result_row.value := NULL;
+ result_row.sources := NULL;
+ result_row.sees := NULL;
+ result_row.accurate := NULL;
+ result_row.aaccurate := NULL;
+ result_row.pivot_point := rec.id;
+
+ IF row_counter >= next_pivot_pos THEN
+ RETURN NEXT result_row;
+ RETURN;
+ END IF;
+ END IF;
+
+ IF count_up_from_zero THEN
+ row_number := row_number + 1;
+ ELSE
+ row_number := row_number - 1;
+ END IF;
+
+ -- row_counter is different from row_number.
+ -- It simply counts up from zero so that we know when
+ -- we've reached our limit.
+ row_counter := row_counter + 1;
+ END IF;
+ END LOOP;
+END;
+$p$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION metabib.browse(
+ search_field INT[],
+ browse_term TEXT,
+ context_org INT DEFAULT NULL,
+ context_loc_group INT DEFAULT NULL,
+ staff BOOL DEFAULT FALSE,
+ pivot_id BIGINT DEFAULT NULL,
+ result_limit INT DEFAULT 10
+) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
+DECLARE
+ core_query TEXT;
+ back_query TEXT;
+ forward_query TEXT;
+ pivot_sort_value TEXT;
+ pivot_sort_fallback TEXT;
+ context_locations INT[];
+ browse_superpage_size INT;
+ results_skipped INT := 0;
+ back_limit INT;
+ back_to_pivot INT;
+ forward_limit INT;
+ forward_to_pivot INT;
+BEGIN
+ -- First, find the pivot if we were given a browse term but not a pivot.
+ IF pivot_id IS NULL THEN
+ pivot_id := metabib.browse_pivot(search_field, browse_term);
+ END IF;
+
+ SELECT INTO pivot_sort_value, pivot_sort_fallback
+ sort_value, value FROM metabib.browse_entry WHERE id = pivot_id;
+
+ -- Bail if we couldn't find a pivot.
+ IF pivot_sort_value IS NULL THEN
+ RETURN;
+ END IF;
+
+ -- Transform the context_loc_group argument (if any) (logc at the
+ -- TPAC layer) into a form we'll be able to use.
+ IF context_loc_group IS NOT NULL THEN
+ SELECT INTO context_locations ARRAY_AGG(location)
+ FROM asset.copy_location_group_map
+ WHERE lgroup = context_loc_group;
+ END IF;
+
+ -- Get the configured size of browse superpages.
+ SELECT INTO browse_superpage_size value -- NULL ok
+ FROM config.global_flag
+ WHERE enabled AND name = 'opac.browse.holdings_visibility_test_limit';
+
+ -- First we're going to search backward from the pivot, then we're going
+ -- to search forward. In each direction, we need two limits. At the
+ -- lesser of the two limits, we delineate the edge of the result set
+ -- we're going to return. At the greater of the two limits, we find the
+ -- pivot value that would represent an offset from the current pivot
+ -- at a distance of one "page" in either direction, where a "page" is a
+ -- result set of the size specified in the "result_limit" argument.
+ --
+ -- The two limits in each direction make four derived values in total,
+ -- and we calculate them now.
+ back_limit := CEIL(result_limit::FLOAT / 2);
+ back_to_pivot := result_limit;
+ forward_limit := result_limit / 2;
+ forward_to_pivot := result_limit - 1;
+
+ -- This is the meat of the SQL query that finds browse entries. We'll
+ -- pass this to a function which uses it with a cursor, so that individual
+ -- rows may be fetched in a loop until some condition is satisfied, without
+ -- waiting for a result set of fixed size to be collected all at once.
+ core_query := '
+SELECT mbe.id,
+ mbe.value,
+ mbe.sort_value
+ FROM metabib.browse_entry mbe
+ WHERE (
+ EXISTS ( -- are there any bibs using this mbe via the requested fields?
+ SELECT 1
+ FROM metabib.browse_entry_def_map mbedm
+ WHERE mbedm.entry = mbe.id AND mbedm.def = ANY(' || quote_literal(search_field) || ')
+ LIMIT 1
+ ) OR EXISTS ( -- are there any authorities using this mbe via the requested fields?
+ SELECT 1
+ FROM metabib.browse_entry_simple_heading_map mbeshm
+ JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
+ JOIN authority.control_set_auth_field_metabib_field_map_refs map ON (
+ ash.atag = map.authority_field
+ AND map.metabib_field = ANY(' || quote_literal(search_field) || ')
+ )
+ WHERE mbeshm.entry = mbe.id
+ )
+ ) AND ';
+
+ -- This is the variant of the query for browsing backward.
+ back_query := core_query ||
+ ' mbe.sort_value <= ' || quote_literal(pivot_sort_value) ||
+ ' ORDER BY mbe.sort_value DESC, mbe.value DESC ';
+
+ -- This variant browses forward.
+ forward_query := core_query ||
+ ' mbe.sort_value > ' || quote_literal(pivot_sort_value) ||
+ ' ORDER BY mbe.sort_value, mbe.value ';
+
+ -- We now call the function which applies a cursor to the provided
+ -- queries, stopping at the appropriate limits and also giving us
+ -- the next page's pivot.
+ RETURN QUERY
+ SELECT * FROM metabib.staged_browse(
+ back_query, search_field, context_org, context_locations,
+ staff, browse_superpage_size, TRUE, back_limit, back_to_pivot
+ ) UNION
+ SELECT * FROM metabib.staged_browse(
+ forward_query, search_field, context_org, context_locations,
+ staff, browse_superpage_size, FALSE, forward_limit, forward_to_pivot
+ ) ORDER BY row_number DESC;
+
+END;
+$p$ LANGUAGE PLPGSQL;
+
+-- No 4XX inter-authority linking
+UPDATE authority.control_set_authority_field SET linking_subfield = NULL;
+UPDATE authority.control_set_authority_field SET linking_subfield = '0' WHERE tag LIKE ANY (ARRAY['5%','7%']);
+
+-- Map between authority controlled bib fields and stock indexing metabib fields
+INSERT INTO authority.control_set_bib_field_metabib_field_map (bib_field, metabib_field)
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '100' AND m.name = 'personal'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '110' AND m.name = 'corporate'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '111' AND m.name = 'conference'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '130' AND m.name = 'uniform'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '148' AND m.name = 'temporal'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '150' AND m.name = 'topic'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '151' AND m.name = 'geographic'
+
+ UNION
+
+ SELECT DISTINCT b.id AS bib_field, m.id AS metabib_field
+ FROM authority.control_set_bib_field b JOIN authority.control_set_authority_field a ON (b.authority_field = a.id), config.metabib_field m
+ WHERE a.tag = '155' AND m.name = 'genre' -- Just in case...
+;
+
+CREATE OR REPLACE FUNCTION authority.indexing_ingest_or_delete () RETURNS TRIGGER AS $func$
+DECLARE
+ ashs authority.simple_heading%ROWTYPE;
+ mbe_row metabib.browse_entry%ROWTYPE;
+ mbe_id BIGINT;
+ ash_id BIGINT;
+BEGIN
+
+ IF NEW.deleted IS TRUE THEN -- If this authority is deleted
+ DELETE FROM authority.bib_linking WHERE authority = NEW.id; -- Avoid updating fields in bibs that are no longer visible
+ DELETE FROM authority.full_rec WHERE record = NEW.id; -- Avoid validating fields against deleted authority records
+ DELETE FROM authority.simple_heading WHERE record = NEW.id;
+ -- Should remove matching $0 from controlled fields at the same time?
+
+ -- XXX What do we about the actual linking subfields present in
+ -- authority records that target this one when this happens?
+ DELETE FROM authority.authority_linking
+ WHERE source = NEW.id OR target = NEW.id;
+
+ RETURN NEW; -- and we're done
+ END IF;
+
+ IF TG_OP = 'UPDATE' THEN -- re-ingest?
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled;
+
+ IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
+ RETURN NEW;
+ END IF;
+
+ -- Propagate these updates to any linked bib records
+ PERFORM authority.propagate_changes(NEW.id) FROM authority.record_entry WHERE id = NEW.id;
+
+ DELETE FROM authority.simple_heading WHERE record = NEW.id;
+ DELETE FROM authority.authority_linking WHERE source = NEW.id;
+ END IF;
+
+ INSERT INTO authority.authority_linking (source, target, field)
+ SELECT source, target, field FROM authority.calculate_authority_linking(
+ NEW.id, NEW.control_set, NEW.marc::XML
+ );
+
+ FOR ashs IN SELECT * FROM authority.simple_heading_set(NEW.marc) LOOP
+
+ INSERT INTO authority.simple_heading (record,atag,value,sort_value)
+ VALUES (ashs.record, ashs.atag, ashs.value, ashs.sort_value);
+ ash_id := CURRVAL('authority.simple_heading_id_seq'::REGCLASS);
+
+ SELECT INTO mbe_row * FROM metabib.browse_entry
+ WHERE value = ashs.value AND sort_value = ashs.sort_value;
+
+ IF FOUND THEN
+ mbe_id := mbe_row.id;
+ ELSE
+ INSERT INTO metabib.browse_entry
+ ( value, sort_value ) VALUES
+ ( ashs.value, ashs.sort_value );
+
+ mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
+ END IF;
+
+ INSERT INTO metabib.browse_entry_simple_heading_map (entry,simple_heading) VALUES (mbe_id,ash_id);
+
+ END LOOP;
+
+ -- Flatten and insert the afr data
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_full_rec' AND enabled;
+ IF NOT FOUND THEN
+ PERFORM authority.reingest_authority_full_rec(NEW.id);
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_rec_descriptor' AND enabled;
+ IF NOT FOUND THEN
+ PERFORM authority.reingest_authority_rec_descriptor(NEW.id);
+ END IF;
+ END IF;
+
+ RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0838', :eg_version);
+
+DELETE FROM config.metabib_field_index_norm_map
+ WHERE field = 25 AND norm IN (
+ SELECT id
+ FROM config.index_normalizer
+ WHERE func IN ('search_normalize','split_date_range')
+ );
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0839', :eg_version);
+
+UPDATE config.metabib_field
+SET
+ xpath = $$//mods32:mods/mods32:titleInfo[mods32:title and starts-with(@type,'alternative')]$$,
+ browse_sort_xpath = $$*[local-name() != "nonSort"]$$,
+ browse_xpath = NULL
+WHERE
+ field_class = 'title' AND name = 'alternative' ;
+
+
+SELECT evergreen.upgrade_deps_block_check('0840', :eg_version);
+
+INSERT INTO config.usr_setting_type (name,grp,opac_visible,label,description,datatype) VALUES (
+ 'ui.grid_columns.conify.config.circ_matrix_matchpoint',
+ 'gui',
+ FALSE,
+ oils_i18n_gettext(
+ 'ui.grid_columns.conify.config.circ_matrix_matchpoint',
+ 'Circulation Policy Configuration',
+ 'cust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'ui.grid_columns.conify.config.circ_matrix_matchpoint',
+ 'Circulation Policy Configuration Column Settings',
+ 'cust',
+ 'description'
+ ),
+ 'string'
+);
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0841', :eg_version);
+
+ALTER TABLE config.metabib_field_ts_map DROP CONSTRAINT metabib_field_ts_map_metabib_field_fkey;
+ALTER TABLE config.metabib_search_alias DROP CONSTRAINT metabib_search_alias_field_fkey;
+ALTER TABLE config.z3950_index_field_map DROP CONSTRAINT z3950_index_field_map_metabib_field_fkey;
+ALTER TABLE metabib.browse_entry_def_map DROP CONSTRAINT browse_entry_def_map_def_fkey;
+
+ALTER TABLE config.metabib_field_ts_map ADD CONSTRAINT metabib_field_ts_map_metabib_field_fkey FOREIGN KEY (metabib_field) REFERENCES config.metabib_field(id) DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE config.metabib_search_alias ADD CONSTRAINT metabib_search_alias_field_fkey FOREIGN KEY (field) REFERENCES config.metabib_field(id) DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE config.z3950_index_field_map ADD CONSTRAINT z3950_index_field_map_metabib_field_fkey FOREIGN KEY (metabib_field) REFERENCES config.metabib_field(id) DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE metabib.browse_entry_def_map ADD CONSTRAINT browse_entry_def_map_def_fkey FOREIGN KEY (def) REFERENCES config.metabib_field(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+DROP FUNCTION IF EXISTS config.modify_metabib_field(source INT, target INT);
+CREATE FUNCTION config.modify_metabib_field(v_source INT, target INT) RETURNS INT AS $func$
+DECLARE
+ f_class TEXT;
+ check_id INT;
+ target_id INT;
+BEGIN
+ SELECT field_class INTO f_class FROM config.metabib_field WHERE id = v_source;
+ IF NOT FOUND THEN
+ RETURN 0;
+ END IF;
+ IF target IS NULL THEN
+ target_id = v_source + 1000;
+ ELSE
+ target_id = target;
+ END IF;
+ SELECT id FROM config.metabib_field INTO check_id WHERE id = target_id;
+ IF FOUND THEN
+ RAISE NOTICE 'Cannot bump config.metabib_field.id from % to %; the target ID already exists.', v_source, target_id;
+ RETURN 0;
+ END IF;
+ UPDATE config.metabib_field SET id = target_id WHERE id = v_source;
+ EXECUTE ' UPDATE metabib.' || f_class || '_field_entry SET field = ' || target_id || ' WHERE field = ' || v_source;
+ UPDATE config.metabib_field_ts_map SET metabib_field = target_id WHERE metabib_field = v_source;
+ UPDATE config.metabib_field_index_norm_map SET field = target_id WHERE field = v_source;
+ UPDATE search.relevance_adjustment SET field = target_id WHERE field = v_source;
+ UPDATE config.metabib_search_alias SET field = target_id WHERE field = v_source;
+ UPDATE config.z3950_index_field_map SET metabib_field = target_id WHERE metabib_field = v_source;
+ UPDATE metabib.browse_entry_def_map SET def = target_id WHERE def = v_source;
+ RETURN 1;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+SELECT config.modify_metabib_field(id, NULL)
+ FROM config.metabib_field
+ WHERE id > 30;
+
+SELECT SETVAL('config.metabib_field_id_seq', GREATEST(1000, (SELECT MAX(id) FROM config.metabib_field)));
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0842', :eg_version);
+
+-- this upgrade is only for people coming from 2_3, and is a NO-OP for those on 2_4
+ALTER TABLE config.metabib_field_ts_map DROP CONSTRAINT metabib_field_ts_map_metabib_field_fkey;
+
+ALTER TABLE config.metabib_field_ts_map ADD CONSTRAINT metabib_field_ts_map_metabib_field_fkey FOREIGN KEY (metabib_field) REFERENCES config.metabib_field(id) ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0843', :eg_version);
+
+-- this upgrade file serves 2 purposes:
+-- 1) add ON UPDATE CASCADE for those upgrading 2_5/master
+-- 2) alter config.z3950_index_field_map for those upgrading from 2_4 and previous (other lines
+-- are no-ops in this case)
+ALTER TABLE config.metabib_search_alias DROP CONSTRAINT metabib_search_alias_field_fkey;
+ALTER TABLE config.z3950_index_field_map DROP CONSTRAINT z3950_index_field_map_metabib_field_fkey;
+ALTER TABLE metabib.browse_entry_def_map DROP CONSTRAINT browse_entry_def_map_def_fkey;
+
+ALTER TABLE config.metabib_search_alias ADD CONSTRAINT metabib_search_alias_field_fkey FOREIGN KEY (field) REFERENCES config.metabib_field(id) ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE config.z3950_index_field_map ADD CONSTRAINT z3950_index_field_map_metabib_field_fkey FOREIGN KEY (metabib_field) REFERENCES config.metabib_field(id) ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE metabib.browse_entry_def_map ADD CONSTRAINT browse_entry_def_map_def_fkey FOREIGN KEY (def) REFERENCES config.metabib_field(id) ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0844', :eg_version);
+
+-- 953.data.MODS32-xsl.sql
+UPDATE config.xml_transform SET xslt=$$<?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:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@ind2>0">
+ <nonSort>
+ <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleBrowseChop, at 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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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', at 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, at ind1)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind1)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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, at ind2)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at 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>
+ </xsl:for-each>
+ <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdn</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="nameABCDQ">
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="punctuation">
+ <xsl:text>:,;/ </xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <xsl:call-template name="termsOfAddress"></xsl:call-template>
+ <xsl:call-template name="nameDate"></xsl:call-template>
+ </xsl:template>
+ <xsl:template name="nameACDEQ">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">acdeq</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:template>
+ <xsl:template name="constituentOrRelatedType">
+ <xsl:if test="@ind2=2">
+ <xsl:attribute name="type">constituent</xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="relatedTitle">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedTitle76X-78X">
+ <xsl:for-each select="marc:subfield[@code='t']">
+ <titleInfo>
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='p']">
+ <titleInfo type="abbreviated">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ <xsl:for-each select="marc:subfield[@code='s']">
+ <titleInfo type="uniform">
+ <title>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </title>
+ <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+ <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+ </xsl:if>
+ </titleInfo>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="relatedOriginInfo">
+ <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
+ <originInfo>
+ <xsl:if test="@tag=775">
+ <xsl:for-each select="marc:subfield[@code='f']">
+ <place>
+ <placeTerm>
+ <xsl:attribute name="type">code</xsl:attribute>
+ <xsl:attribute name="authority">marcgac</xsl:attribute>
+ <xsl:value-of select="."></xsl:value-of>
+ </placeTerm>
+ </place>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <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:template>
+ <xsl:template name="relatedLanguage">
+ <xsl:for-each select="marc:subfield[@code='e']">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString">
+ <xsl:value-of select="."></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="nameDate">
+ <xsl:for-each select="marc:subfield[@code='d']">
+ <namePart type="date">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."></xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="subjectAuthority">
+ <xsl:if test="@ind2!=4">
+ <xsl:if test="@ind2!=' '">
+ <xsl:if test="@ind2!=8">
+ <xsl:if test="@ind2!=9">
+ <xsl:attribute name="authority">
+ <xsl:choose>
+ <xsl:when test="@ind2=0">lcsh</xsl:when>
+ <xsl:when test="@ind2=1">lcshac</xsl:when>
+ <xsl:when test="@ind2=2">mesh</xsl:when>
+ <!-- 1/04 fix -->
+ <xsl:when test="@ind2=3">nal</xsl:when>
+ <xsl:when test="@ind2=5">csh</xsl:when>
+ <xsl:when test="@ind2=6">rvm</xsl:when>
+ <xsl:when test="@ind2=7">
+ <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:if>
+ </xsl:if>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="subjectAnyOrder">
+ <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
+ <xsl:choose>
+ <xsl:when test="@code='v'">
+ <xsl:call-template name="subjectGenre"></xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@code='x'">
+ <xsl:call-template name="subjectTopic"></xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@code='y'">
+ <xsl:call-template name="subjectTemporalY"></xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@code='z'">
+ <xsl:call-template name="subjectGeographicZ"></xsl:call-template>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="specialSubfieldSelect">
+ <xsl:param name="anyCodes"></xsl:param>
+ <xsl:param name="axis"></xsl:param>
+ <xsl:param name="beforeCodes"></xsl:param>
+ <xsl:param name="afterCodes"></xsl:param>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="contains($anyCodes, @code) or (contains($beforeCodes, at code) and following-sibling::marc:subfield[@code=$axis]) or (contains($afterCodes, at code) and preceding-sibling::marc:subfield[@code=$axis])">
+ <xsl:value-of select="text()"></xsl:value-of>
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+ </xsl:template>
+
+ <!-- 3.2 change tmee 6xx $v genre -->
+ <xsl:template match="marc:datafield[@tag=600]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <name type="personal">
+ <xsl:call-template name="uri" />
+ <namePart>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">aq</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="affiliation"></xsl:call-template>
+ <xsl:call-template name="role"></xsl:call-template>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=610]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <name type="corporate">
+ <xsl:call-template name="uri" />
+ <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:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">cdnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ <xsl:call-template name="role"></xsl:call-template>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=611]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <name type="conference">
+ <xsl:call-template name="uri" />
+ <namePart>
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ <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>
+ </name>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=630]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <xsl:variable name="titleChop">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">adfhklor</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="@ind1>0">
+ <nonSort>
+ <xsl:value-of select="substring($titleChop,1, at ind1)"/>
+ </nonSort>
+ <title>
+ <xsl:value-of select="substring($titleChop, at ind1+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>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=650]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <topic>
+ <xsl:call-template name="uri" />
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">abcd</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </topic>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=651]">
+ <subject>
+ <xsl:call-template name="subjectAuthority"></xsl:call-template>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <geographic>
+ <xsl:call-template name="uri" />
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="."></xsl:with-param>
+ </xsl:call-template>
+ </geographic>
+ </xsl:for-each>
+ <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=653]">
+ <subject>
+ <xsl:for-each select="marc:subfield[@code='a']">
+ <topic>
+ <xsl:call-template name="uri" />
+ <xsl:value-of select="."></xsl:value-of>
+ </topic>
+ </xsl:for-each>
+ </subject>
+ </xsl:template>
+ <xsl:template match="marc:datafield[@tag=656]">
+ <subject>
+ <xsl:if test="marc:subfield[@code=2]">
+ <xsl:attribute name="authority">
+ <xsl:value-of select="marc:subfield[@code=2]"></xsl:value-of>
+ </xsl:attribute>
+ </xsl:if>
+ <occupation>
+ <xsl:call-template name="uri" />
+ <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>
+ </occupation>
+ </subject>
+ </xsl:template>
+ <xsl:template name="termsOfAddress">
+ <xsl:if test="marc:subfield[@code='b' or @code='c']">
+ <namePart type="termsOfAddress">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">bc</xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </namePart>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="displayLabel">
+ <xsl:if test="marc:subfield[@code='i']">
+ <xsl:attribute name="displayLabel">
+ <xsl:value-of select="marc:subfield[@code='i']"></xsl:value-of>
+ </xsl:attribute>
+ </xsl:if>
+ <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:template>
+ <xsl:template name="isInvalid">
+ <xsl:param name="type"/>
+ <xsl:if test="marc:subfield[@code='z'] or marc:subfield[@code='y']">
+ <identifier>
+ <xsl:attribute name="type">
+ <xsl:value-of select="$type"/>
+ </xsl:attribute>
+ <xsl:attribute name="invalid">
+ <xsl:text>yes</xsl:text>
+ </xsl:attribute>
+ <xsl:if test="marc:subfield[@code='z']">
+ <xsl:value-of select="marc:subfield[@code='z']"/>
+ </xsl:if>
+ <xsl:if test="marc:subfield[@code='y']">
+ <xsl:value-of select="marc:subfield[@code='y']"/>
+ </xsl:if>
+ </identifier>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="subtitle">
+ <xsl:if test="marc:subfield[@code='b']">
+ <subTitle>
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString">
+ <xsl:value-of select="marc:subfield[@code='b']"/>
+ <!--<xsl:call-template name="subfieldSelect">
+ <xsl:with-param name="codes">b</xsl:with-param>
+ </xsl:call-template>-->
+ </xsl:with-param>
+ </xsl:call-template>
+ </subTitle>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="script">
+ <xsl:param name="scriptCode"></xsl:param>
+ <xsl:attribute name="script">
+ <xsl:choose>
+ <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
+ <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
+ <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
+ <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
+ <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
+ <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:template>
+ <xsl:template name="parsePart">
+ <!-- assumes 773$q= 1:2:3<4
+ with up to 3 levels and one optional start page
+ -->
+ <xsl:variable name="level1">
+ <xsl:choose>
+ <xsl:when test="contains(text(),':')">
+ <!-- 1:2 -->
+ <xsl:value-of select="substring-before(text(),':')"></xsl:value-of>
+ </xsl:when>
+ <xsl:when test="not(contains(text(),':'))">
+ <!-- 1 or 1<3 -->
+ <xsl:if test="contains(text(),'<')">
+ <!-- 1<3 -->
+ <xsl:value-of select="substring-before(text(),'<')"></xsl:value-of>
+ </xsl:if>
+ <xsl:if test="not(contains(text(),'<'))">
+ <!-- 1 -->
+ <xsl:value-of select="text()"></xsl:value-of>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici2">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after(text(),$level1),':')">
+ <xsl:value-of select="substring(substring-after(text(),$level1),2)"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring-after(text(),$level1)"></xsl:value-of>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level2">
+ <xsl:choose>
+ <xsl:when test="contains($sici2,':')">
+ <!-- 2:3<4 -->
+ <xsl:value-of select="substring-before($sici2,':')"></xsl:value-of>
+ </xsl:when>
+ <xsl:when test="contains($sici2,'<')">
+ <!-- 1: 2<4 -->
+ <xsl:value-of select="substring-before($sici2,'<')"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici2"></xsl:value-of>
+ <!-- 1:2 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sici3">
+ <xsl:choose>
+ <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
+ <xsl:value-of select="substring(substring-after($sici2,$level2),2)"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring-after($sici2,$level2)"></xsl:value-of>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="level3">
+ <xsl:choose>
+ <xsl:when test="contains($sici3,'<')">
+ <!-- 2<4 -->
+ <xsl:value-of select="substring-before($sici3,'<')"></xsl:value-of>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$sici3"></xsl:value-of>
+ <!-- 3 -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="page">
+ <xsl:if test="contains(text(),'<')">
+ <xsl:value-of select="substring-after(text(),'<')"></xsl:value-of>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:if test="$level1">
+ <detail level="1">
+ <number>
+ <xsl:value-of select="$level1"></xsl:value-of>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level2">
+ <detail level="2">
+ <number>
+ <xsl:value-of select="$level2"></xsl:value-of>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$level3">
+ <detail level="3">
+ <number>
+ <xsl:value-of select="$level3"></xsl:value-of>
+ </number>
+ </detail>
+ </xsl:if>
+ <xsl:if test="$page">
+ <extent unit="page">
+ <start>
+ <xsl:value-of select="$page"></xsl:value-of>
+ </start>
+ </extent>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="getLanguage">
+ <xsl:param name="langString"></xsl:param>
+ <xsl:param name="controlField008-35-37"></xsl:param>
+ <xsl:variable name="length" select="string-length($langString)"></xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$length=0"></xsl:when>
+ <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <language>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="substring($langString,1,3)"></xsl:value-of>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="getLanguage">
+ <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
+ <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="isoLanguage">
+ <xsl:param name="currentLanguage"></xsl:param>
+ <xsl:param name="usedLanguages"></xsl:param>
+ <xsl:param name="remainingLanguages"></xsl:param>
+ <xsl:choose>
+ <xsl:when test="string-length($currentLanguage)=0"></xsl:when>
+ <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
+ <language>
+ <xsl:if test="@code!='a'">
+ <xsl:attribute name="objectPart">
+ <xsl:choose>
+ <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+ <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+ <xsl:when test="@code='e'">libretto</xsl:when>
+ <xsl:when test="@code='f'">table of contents</xsl:when>
+ <xsl:when test="@code='g'">accompanying material</xsl:when>
+ <xsl:when test="@code='h'">translation</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ <languageTerm authority="iso639-2b" type="code">
+ <xsl:value-of select="$currentLanguage"></xsl:value-of>
+ </languageTerm>
+ </language>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="isoLanguage">
+ <xsl:with-param name="currentLanguage">
+ <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="usedLanguages">
+ <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
+ </xsl:with-param>
+ <xsl:with-param name="remainingLanguages">
+ <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="chopBrackets">
+ <xsl:param name="chopString"></xsl:param>
+ <xsl:variable name="string">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="$chopString"></xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="substring($string, 1,1)='['">
+ <xsl:value-of select="substring($string,2, string-length($string)-2)"></xsl:value-of>
+ </xsl:if>
+ <xsl:if test="substring($string, 1,1)!='['">
+ <xsl:value-of select="$string"></xsl:value-of>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="rfcLanguages">
+ <xsl:param name="nodeNum"></xsl:param>
+ <xsl:param name="usedLanguages"></xsl:param>
+ <xsl:param name="controlField008-35-37"></xsl:param>
+ <xsl:variable name="currentLanguage" select="."></xsl:variable>
+ <xsl:choose>
+ <xsl:when test="not($currentLanguage)"></xsl:when>
+ <xsl:when test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
+ <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
+ <language>
+ <xsl:if test="@code!='a'">
+ <xsl:attribute name="objectPart">
+ <xsl:choose>
+ <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+ <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+ <xsl:when test="@code='e'">libretto</xsl:when>
+ <xsl:when test="@code='f'">table of contents</xsl:when>
+ <xsl:when test="@code='g'">accompanying material</xsl:when>
+ <xsl:when test="@code='h'">translation</xsl:when>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:if>
+ <languageTerm authority="rfc3066" type="code">
+ <xsl:value-of select="$currentLanguage"/>
+ </languageTerm>
+ </language>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="datafield">
+ <xsl:param name="tag"/>
+ <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
+ <xsl:param name="ind2"><xsl:text> </xsl:text></xsl:param>
+ <xsl:param name="subfields"/>
+ <xsl:element name="marc:datafield">
+ <xsl:attribute name="tag">
+ <xsl:value-of select="$tag"/>
+ </xsl:attribute>
+ <xsl:attribute name="ind1">
+ <xsl:value-of select="$ind1"/>
+ </xsl:attribute>
+ <xsl:attribute name="ind2">
+ <xsl:value-of select="$ind2"/>
+ </xsl:attribute>
+ <xsl:copy-of select="$subfields"/>
+ </xsl:element>
+ </xsl:template>
+
+ <xsl:template name="subfieldSelect">
+ <xsl:param name="codes"/>
+ <xsl:param name="delimeter"><xsl:text> </xsl:text></xsl:param>
+ <xsl:variable name="str">
+ <xsl:for-each select="marc:subfield">
+ <xsl:if test="contains($codes, @code)">
+ <xsl:value-of select="text()"/><xsl:value-of select="$delimeter"/>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
+ </xsl:template>
+
+ <xsl:template name="buildSpaces">
+ <xsl:param name="spaces"/>
+ <xsl:param name="char"><xsl:text> </xsl:text></xsl:param>
+ <xsl:if test="$spaces>0">
+ <xsl:value-of select="$char"/>
+ <xsl:call-template name="buildSpaces">
+ <xsl:with-param name="spaces" select="$spaces - 1"/>
+ <xsl:with-param name="char" select="$char"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuation">
+ <xsl:param name="chopString"/>
+ <xsl:param name="punctuation"><xsl:text>.:,;/ </xsl:text></xsl:param>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+ <xsl:call-template name="chopPunctuation">
+ <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+ <xsl:with-param name="punctuation" select="$punctuation"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="chopPunctuationFront">
+ <xsl:param name="chopString"/>
+ <xsl:variable name="length" select="string-length($chopString)"/>
+ <xsl:choose>
+ <xsl:when test="$length=0"/>
+ <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
+ <xsl:call-template name="chopPunctuationFront">
+ <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="not($chopString)"/>
+ <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+</xsl:stylesheet>$$ WHERE name = 'mods32';
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) 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;
+ 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;
+BEGIN
+
+ -- Start out with no field-use bools set
+ output_row.browse_field = FALSE;
+ output_row.facet_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 ORDER BY format LOOP
+
+ 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()',
+ REGEXP_REPLACE(
+ REGEXP_REPLACE( -- This escapes all &s not followed by "amp;". Data ise returned from oils_xpath (above) in UTF-8, not entity encoded
+ REGEXP_REPLACE( -- This escapes embeded <s
+ xml_node,
+ $re$(>[^<]+)(<)([^>]+<)$re$,
+ E'\\1<\\3',
+ 'g'
+ ),
+ '&(?!amp;)',
+ '&',
+ 'g'
+ ),
+ E'\\s+',
+ ' ',
+ 'g'
+ )
+ ), ' '), ''),
+ 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;
+
+ 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.reingest_metabib_field_entries( bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+DECLARE
+ fclass RECORD;
+ ind_data metabib.field_entry_template%ROWTYPE;
+ mbe_row metabib.browse_entry%ROWTYPE;
+ mbe_id BIGINT;
+ b_skip_facet BOOL;
+ b_skip_browse BOOL;
+ b_skip_search BOOL;
+ value_prepped TEXT;
+BEGIN
+
+ SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
+ SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
+ SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
+
+ PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
+ IF NOT FOUND THEN
+ IF NOT b_skip_search THEN
+ FOR fclass IN SELECT * FROM config.metabib_class LOOP
+ -- RAISE NOTICE 'Emptying out %', fclass.name;
+ EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
+ END LOOP;
+ END IF;
+ IF NOT b_skip_facet THEN
+ DELETE FROM metabib.facet_entry WHERE source = bib_id;
+ END IF;
+ IF NOT b_skip_browse THEN
+ DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
+ END IF;
+ END IF;
+
+ FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+ IF ind_data.field < 0 THEN
+ ind_data.field = -1 * ind_data.field;
+ END IF;
+
+ IF ind_data.facet_field AND NOT b_skip_facet THEN
+ INSERT INTO metabib.facet_entry (field, source, value)
+ VALUES (ind_data.field, ind_data.source, ind_data.value);
+ END IF;
+
+ IF ind_data.browse_field AND NOT b_skip_browse THEN
+ -- A caveat about this SELECT: this should take care of replacing
+ -- old mbe rows when data changes, but not if normalization (by
+ -- which I mean specifically the output of
+ -- evergreen.oils_tsearch2()) changes. It may or may not be
+ -- expensive to add a comparison of index_vector to index_vector
+ -- to the WHERE clause below.
+
+ value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
+ SELECT INTO mbe_row * FROM metabib.browse_entry
+ WHERE value = value_prepped AND sort_value = ind_data.sort_value;
+
+ IF FOUND THEN
+ mbe_id := mbe_row.id;
+ ELSE
+ INSERT INTO metabib.browse_entry
+ ( value, sort_value ) VALUES
+ ( value_prepped, ind_data.sort_value );
+
+ mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
+ END IF;
+
+ INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
+ VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
+ END IF;
+
+ IF ind_data.search_field AND NOT b_skip_search THEN
+ -- Avoid inserting duplicate rows
+ EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class ||
+ '_field_entry WHERE field = $1 AND source = $2 AND value = $3'
+ INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value;
+ -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id;
+ IF mbe_id IS NULL THEN
+ EXECUTE $$
+ INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
+ VALUES ($$ ||
+ quote_literal(ind_data.field) || $$, $$ ||
+ quote_literal(ind_data.source) || $$, $$ ||
+ quote_literal(ind_data.value) ||
+ $$);$$;
+ END IF;
+ END IF;
+
+ END LOOP;
+
+ IF NOT b_skip_search THEN
+ PERFORM metabib.update_combined_index_vectors(bib_id);
+ END IF;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+-- Don't use Title Proper search field as the browse field
+UPDATE config.metabib_field SET browse_field = FALSE, browse_xpath = NULL, browse_sort_xpath = NULL WHERE id = 6;
+
+-- Create a new Title Proper browse config
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, search_field, authority_xpath, browse_field, browse_sort_xpath ) VALUES
+ (31, 'title', 'browse', oils_i18n_gettext(31, 'Title Proper (Browse)', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleBrowse$$, FALSE, '//@xlink:href', TRUE, $$*[local-name() != "nonSort"]$$ );
+
+SELECT evergreen.upgrade_deps_block_check('0845', :eg_version);
+
+ALTER FUNCTION metabib.browse_pivot (integer[], text) STABLE;
+ALTER FUNCTION metabib.browse_bib_pivot (integer[], text) STABLE;
+ALTER FUNCTION metabib.browse_authority_pivot (integer[], text) STABLE;
+ALTER FUNCTION metabib.browse_authority_refs_pivot (integer[], text) STABLE;
+
+
+SELECT evergreen.upgrade_deps_block_check('0846', :eg_version);
+
+CREATE OR REPLACE FUNCTION vandelay.add_field ( target_xml TEXT, source_xml TEXT, field TEXT, force_add INT ) RETURNS TEXT AS $_$
+
+ use MARC::Record;
+ use MARC::File::XML (BinaryEncoding => 'UTF-8');
+ use MARC::Charset;
+ use strict;
+
+ MARC::Charset->assume_unicode(1);
+
+ my $target_xml = shift;
+ my $source_xml = shift;
+ my $field_spec = shift;
+ my $force_add = shift || 0;
+
+ my $target_r = MARC::Record->new_from_xml( $target_xml );
+ my $source_r = MARC::Record->new_from_xml( $source_xml );
+
+ return $target_xml unless ($target_r && $source_r);
+
+ my @field_list = split(',', $field_spec);
+
+ my %fields;
+ for my $f (@field_list) {
+ $f =~ s/^\s*//; $f =~ s/\s*$//;
+ if ($f =~ /^(.{3})(\w*)(?:\[([^]]*)\])?$/) {
+ my $field = $1;
+ $field =~ s/\s+//;
+ my $sf = $2;
+ $sf =~ s/\s+//;
+ my $match = $3;
+ $match =~ s/^\s*//; $match =~ s/\s*$//;
+ $fields{$field} = { sf => [ split('', $sf) ] };
+ if ($match) {
+ my ($msf,$mre) = split('~', $match);
+ if (length($msf) > 0 and length($mre) > 0) {
+ $msf =~ s/^\s*//; $msf =~ s/\s*$//;
+ $mre =~ s/^\s*//; $mre =~ s/\s*$//;
+ $fields{$field}{match} = { sf => $msf, re => qr/$mre/ };
+ }
+ }
+ }
+ }
+
+ for my $f ( keys %fields) {
+ if ( @{$fields{$f}{sf}} ) {
+ for my $from_field ($source_r->field( $f )) {
+ my @tos = $target_r->field( $f );
+ if (!@tos) {
+ next if (exists($fields{$f}{match}) and !$force_add);
+ my @new_fields = map { $_->clone } $source_r->field( $f );
+ $target_r->insert_fields_ordered( @new_fields );
+ } else {
+ for my $to_field (@tos) {
+ if (exists($fields{$f}{match})) {
+ next unless (grep { $_ =~ $fields{$f}{match}{re} } $to_field->subfield($fields{$f}{match}{sf}));
+ }
+ for my $old_sf ($from_field->subfields) {
+ $to_field->add_subfields( @$old_sf ) if grep(/$$old_sf[0]/,@{$fields{$f}{sf}});
+ }
+ }
+ }
+ }
+ } else {
+ my @new_fields = map { $_->clone } $source_r->field( $f );
+ $target_r->insert_fields_ordered( @new_fields );
+ }
+ }
+
+ $target_xml = $target_r->as_xml_record;
+ $target_xml =~ s/^<\?.+?\?>$//mo;
+ $target_xml =~ s/\n//sgo;
+ $target_xml =~ s/>\s+</></sgo;
+
+ return $target_xml;
+
+$_$ LANGUAGE PLPERLU;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0847', :eg_version);
+
+CREATE OR REPLACE FUNCTION authority.generate_overlay_template (source_xml TEXT) RETURNS TEXT AS $f$
+DECLARE
+ cset INT;
+ main_entry authority.control_set_authority_field%ROWTYPE;
+ bib_field authority.control_set_bib_field%ROWTYPE;
+ auth_id INT DEFAULT oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', source_xml)::INT;
+ tmp_data XML;
+ replace_data XML[] DEFAULT '{}'::XML[];
+ replace_rules TEXT[] DEFAULT '{}'::TEXT[];
+ auth_field XML[];
+ auth_i1 TEXT;
+ auth_i2 TEXT;
+BEGIN
+ IF auth_id IS NULL THEN
+ RETURN NULL;
+ END IF;
+
+ -- Default to the LoC controll set
+ SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+ -- if none, make a best guess
+ IF cset IS NULL THEN
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN (
+ SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marc::XML)::TEXT[])
+ FROM authority.record_entry
+ WHERE id = auth_id
+ )
+ LIMIT 1;
+ END IF;
+
+ -- if STILL none, no-op change
+ IF cset IS NULL THEN
+ RETURN XMLELEMENT(
+ name record,
+ XMLATTRIBUTES('http://www.loc.gov/MARC21/slim' AS xmlns),
+ XMLELEMENT( name leader, '00881nam a2200193 4500'),
+ XMLELEMENT(
+ name datafield,
+ XMLATTRIBUTES( '905' AS tag, ' ' AS ind1, ' ' AS ind2),
+ XMLELEMENT(
+ name subfield,
+ XMLATTRIBUTES('d' AS code),
+ '901c'
+ )
+ )
+ )::TEXT;
+ END IF;
+
+ FOR main_entry IN SELECT * FROM authority.control_set_authority_field acsaf WHERE acsaf.control_set = cset AND acsaf.main_entry IS NULL LOOP
+ auth_field := XPATH('//*[@tag="'||main_entry.tag||'"][1]',source_xml::XML);
+ auth_i1 = (XPATH('@ind1',auth_field[1]))[1];
+ auth_i2 = (XPATH('@ind2',auth_field[1]))[1];
+ IF ARRAY_LENGTH(auth_field,1) > 0 THEN
+ FOR bib_field IN SELECT * FROM authority.control_set_bib_field WHERE authority_field = main_entry.id LOOP
+ SELECT XMLELEMENT( -- XMLAGG avoids magical <element> creation, but requires unnest subquery
+ name datafield,
+ XMLATTRIBUTES(bib_field.tag AS tag, auth_i1 AS ind1, auth_i2 AS ind2),
+ XMLAGG(UNNEST)
+ ) INTO tmp_data FROM UNNEST(XPATH('//*[local-name()="subfield"]', auth_field[1]));
+ replace_data := replace_data || tmp_data;
+ replace_rules := replace_rules || ( bib_field.tag || main_entry.sf_list || E'[0~\\)' || auth_id || '$]' );
+ tmp_data = NULL;
+ END LOOP;
+ EXIT;
+ END IF;
+ END LOOP;
+
+ SELECT XMLAGG(UNNEST) INTO tmp_data FROM UNNEST(replace_data);
+
+ RETURN XMLELEMENT(
+ name record,
+ XMLATTRIBUTES('http://www.loc.gov/MARC21/slim' AS xmlns),
+ XMLELEMENT( name leader, '00881nam a2200193 4500'),
+ tmp_data,
+ XMLELEMENT(
+ name datafield,
+ XMLATTRIBUTES( '905' AS tag, ' ' AS ind1, ' ' AS ind2),
+ XMLELEMENT(
+ name subfield,
+ XMLATTRIBUTES('r' AS code),
+ ARRAY_TO_STRING(replace_rules,',')
+ )
+ )
+ )::TEXT;
+END;
+$f$ STABLE LANGUAGE PLPGSQL;
+
+SELECT evergreen.upgrade_deps_block_check('0827', :eg_version);
+SET CONSTRAINTS ALL IMMEDIATE;
+-- otherwise, the ALTER TABLE statement below
+-- will fail with pending trigger events.
+ALTER TABLE action_trigger.event_definition ADD COLUMN repeat_delay INTERVAL;
+
+COMMIT;
+
+\qecho
+\qecho
+\qecho **** Certain improvements in 2.5, particularly browse, require a reingest
+\qecho **** of all records. In order to allow this to continue without locking
+\qecho **** your entire bibliographic data set, consider generating SQL scripts
+\qecho **** with the following queries, then running those via psql:
+\qecho
+\qecho **** If you require a more responsive catalog/database while reingesting,
+\qecho **** consider adding 'pg_sleep()' calls between each reingest select or
+\qecho **** update.
+\qecho
+\qecho '\\t'
+\qecho '\\o /tmp/reingest_2.5_bib_recs.sql'
+\qecho 'SELECT ''select metabib.reingest_metabib_field_entries('' || id || '');'' FROM biblio.record_entry WHERE NOT DELETED AND id > 0;'
+\qecho
+\qecho '\\o /tmp/reingest_2.5_auth_recs.sql'
+\qecho 'SELECT ''-- Grab current setting'';'
+\qecho 'SELECT ''\\set force_reingest '' || enabled FROM config.internal_flag WHERE name = ''ingest.reingest.force_on_same_marc'';'
+\qecho 'SELECT ''update config.internal_flag set enabled = true where name = ''''ingest.reingest.force_on_same_marc'''';'';'
+\qecho 'SELECT ''update authority.record_entry set id = id where id = '' || id || '';'' FROM authority.record_entry WHERE NOT DELETED;'
+\qecho 'SELECT ''-- Restore previous setting'';'
+\qecho 'SELECT ''update config.internal_flag set enabled = :force_reingest where name = \'\'ingest.reingest.force_on_same_marc\'\';'';'
+\qecho '\\o'
+\qecho '\\t'
commit 5a9c9f79338d76c9bec28e936c9e3959d7f0f6d5
Author: Dan Wells <dbw2 at calvin.edu>
Date: Tue Nov 26 14:40:45 2013 -0500
Bumping version numbers, adding Upgrade Script and Changelog
Signed-off-by: Dan Wells <dbw2 at calvin.edu>
diff --git a/ChangeLog b/ChangeLog
index 1f72b2c..6d65c42 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,469 @@
-Evergreen doesn't keep a GNU-style ChangeLog except in release tarballs.
-Those seeking a change log are encouraged to run 'git log -v', or read
-it online at: http://git.evergreen-ils.org/?p=Evergreen.git;a=log
+commit 92ba29f2c208325e847f1367e32f2ed18de84cb0
+Author: Dan Wells <dbw2 at calvin.edu>
+Date: Tue Nov 26 14:35:22 2013 -0500
+
+ Bump OpenILS.pm version
+
+ Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1 1 Open-ILS/src/perlmods/lib/OpenILS.pm
+
+commit 45b2335bfefb3a5b77dbec6e1afdd9b12dbd7528
+Author: Mike Rylander <mrylander at gmail.com>
+Date: Wed Nov 13 18:15:21 2013 -0500
+
+ Fix boolean lists; Better atom regex; Caching
+
+ First, we didn't need to make $last_type local, and it broke explicit
+ grouping anyway. That's removed, and we now reset that (and a few more
+ like it) at calls to the top level parse() method. This introduces a
+ situation where a long list of booleans could cause query plan problems,
+ so we limit the plan depth to 40 (20 ||'d conditions).
+
+ Second, we are smarter about finding the boundary of atoms. Previous
+ to this commit, and curly brace could send the parser into a tailspin
+ from which it would not recover. Now we use alternation instead of
+ a character class, which is much safer with the default multi-character
+ float syntax specifier.
+
+ Third, as a catch-all, if we can't parse the remained of a query we
+ now simply say so (when in debug mode) and go away, instead of risking
+ an infinite loop. We do this via a final, unqualified "else" clause
+ in decompose().
+
+ Finally, instead of building 10+ regexp objects on each query parse,
+ cache them per QP subclass and reuse them.
+
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+ Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2 0 Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+117 94 Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
+2 0 Open-ILS/src/support-scripts/test-scripts/query_tests.pl
+
+commit b4f1dfba98a0971eabb8824188d5fe0f21b8351f
+Author: Bill Erickson <berick at esilibrary.com>
+Date: Mon Oct 28 10:24:37 2013 -0400
+
+ LP#1238015 hide patron credit summary when disabled
+
+ When the circ.disable_patron_credit / "Disable Patron Credit" org unit
+ setting is disabled, also hide the patron credit summary information in
+ the bills interface.
+
+ Signed-off-by: Bill Erickson <berick at esilibrary.com>
+ Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+6 1 Open-ILS/xul/staff_client/server/patron/bill2.xul
+
+commit 33fe2cee4b94a382fd62e02bfd6dcd6f5bb0684f
+Author: Mike Rylander <mrylander at gmail.com>
+Date: Mon Nov 25 10:14:08 2013 -0500
+
+ Re-apply the changes provided by 0802 for backport
+
+ Preserve record order of subfields for authority heading extraction
+
+ When extracting headings from authority records we currently read the
+ subfields of a tag in configuration order. We should, instead, read
+ them in record order, to preserve the desired sorting properties that
+ the cataloger has encoded in the record.
+
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1 1 Open-ILS/src/sql/Pg/002.schema.config.sql
+170 0 Open-ILS/src/sql/Pg/upgrade/0848.function.authority-sf-file-order-again.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0848.function.authority-sf-file-order-again.sql
+
+commit 165d51a2843954dafdd9cbb904908d17f789daea
+Author: Dan Scott <dscott at laurentian.ca>
+Date: Sun Oct 27 13:11:37 2013 -0400
+
+ Fix copy_table HTML markup errors
+
+ TD elements take a "headers" attribute, not a "header" attribute. Also,
+ we have a few typos in identifying the header attributes.
+
+ Signed-off-by: Dan Scott <dscott at laurentian.ca>
+ Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2 2 Open-ILS/src/templates/opac/css/style.css.tt2
+19 19 Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+
+commit 7db96d3ea576c2f774208c450f3baf9a72e02703
+Author: Bill Erickson <berick at esilibrary.com>
+Date: Fri Nov 22 14:55:26 2013 -0500
+
+ LP#1254146 gracefully handle custom trees sans entries
+
+ Avoid references to custom tree entries when no tree entries for a
+ custom tree exist. Prevents:
+
+ egweb: template error: undef error - Can't call method "org_unit" on an
+ undefined value at
+ /usr/local/share/perl/5.10.1/OpenILS/WWW/EGCatLoader/Util.pm line 185.\n
+
+ Signed-off-by: Bill Erickson <berick at esilibrary.com>
+ Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2 1 Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
+
+commit 1fff24ee104c1965003d4eea3123fe9227360562
+Author: Dan Wells <dbw2 at calvin.edu>
+Date: Thu Nov 14 15:12:46 2013 -0500
+
+ Improve facet styling
+
+ 1) Facets currently display very poorly when the number reaches 3-4
+ digits. Facet data is more or less a two column table, so let's style
+ it that way to make it more robust.
+
+ 2) Rearrange some styles to reduce redundancy, and allow overflow
+ where possible.
+
+ 3) Change the selected highlight to look a little better.
+
+ Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+ Signed-off-by: Ben Shum <bshum at biblio.org>
+
+15 29 Open-ILS/src/templates/opac/css/style.css.tt2
+
+commit 7de0e1f55055f9afebab2b122ec3dd49e4c7bb26
+Author: Mike Rylander <mrylander at gmail.com>
+Date: Wed Nov 20 14:45:18 2013 -0500
+
+ Pulling in new version upgrade
+
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+275 0 Open-ILS/src/sql/Pg/version-upgrade/2.4.3-2.4.4-upgrade-db.sql
+ create mode 100644 Open-ILS/src/sql/Pg/version-upgrade/2.4.3-2.4.4-upgrade-db.sql
+
+commit 916e8442af4d6bcca6a7397df7880dde942b0010
+Author: Bill Erickson <berick at esilibrary.com>
+Date: Fri Nov 15 17:06:53 2013 -0500
+
+ LP#1251774 exit and alert on multiple payments per xact
+
+ If more than one payment for a transaction is received, exit the API
+ call early and return a MULTIPLE_PAYMENTS_FOR_XACT event.
+
+ Signed-off-by: Bill Erickson <berick at esilibrary.com>
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+4 1 Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm
+
+commit 8ea35f2e331e41e2198f71f205b3331277ef61fa
+Author: Mike Rylander <mrylander at gmail.com>
+Date: Fri Nov 15 16:40:36 2013 -0500
+
+ Enforce one-payment-per-xact-per-call
+
+ There is no legitimate reason for a transaction to receive more than
+ one payment per call to open-ils.circ open-ils.circ.money.payment,
+ but we have seen the staff client generate such a data structure. This
+ leads to seemingly duplicate payments, and is bad all around. So,
+ we will enforce the restriction by taking only the first payment per
+ xact in the list of payments.
+
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+ Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+10 0 Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm
+
+commit cdac86e1201d94b610678cdcf84e0e93107fdc05
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date: Fri Nov 8 15:02:53 2013 -0500
+
+ Replace erroneous calls to $e->retrieve_authority_record($rec_id).
+
+ On lines 153 and 175 of OpenILS::Application::Cat::Authority calls
+ like the above should be $e->retrieve_authority_record_entry($rec_id).
+ This branch replaces the two misspelled calls with the proper ones.
+
+ Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+2 2 Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/Authority.pm
+
+commit 95cbc4d3cc154fe3a503a261d3146b63fa3b491a
+Author: Jason Etheridge <jason at esilibrary.com>
+Date: Thu Sep 12 12:02:15 2013 -0400
+
+ LP1093856 fix Fast Item Add with Z39.50 import
+
+ The first time I tried this fix I ran afoul of
+ https://bugs.launchpad.net/evergreen/+bug/787561
+
+ But a second attempt worked. So I didn't kill
+ two birds with one stone, but this should take
+ care of 1093856.
+
+ Signed-off-by: Jason Etheridge <jason at esilibrary.com>
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+12 3 Open-ILS/xul/staff_client/server/cat/marcedit.js
+
+commit 950dede4146fed9023f6fbf8d289b522bf615a6d
+Author: Liam Whalen <whalen.ld at gmail.com>
+Date: Sun Oct 6 22:11:56 2013 -0700
+
+ LP#1037171 Removed Expert Search paramters from subject links
+
+ After performing an Expert Search, if a user visits a record and then
+ clicks on one of the author, subject, or series search links within that
+ record, then they are given the results of the Expert Search again
+ instead of the relevant subject or author search.
+
+ This is happening because the Expert Search parameters are retained in
+ the URLs via the TT2 MACRO mkurl. In particular, the tag parameter is
+ used to identify an Expert Search, so if it is present in a URL, than an
+ Expert Search will be attempted regardless of which other paramaters are
+ in the URL.
+
+ To fix this, I created two varialbes within header.tt2 above the
+ definition of mkurl. These variables group common URL paramters for
+ Expert Searches and General Search parameters together. These variables
+ can be used wherever mkurl is used to strip out unneeded search
+ paramters.
+
+ There is a third variable that is already present within many of these
+ pages named stop_parms. While I initially tried to modify this
+ variable, I found that there are some instances where the general search
+ parameters should be retained while the Expert Search parameters must go.
+
+ This commit uses these three variables togehter as input into the third
+ arugment of the mkurl MACRO. The third arugment specifies which
+ paramtes to remove from the previous URL before making a new URL based
+ on the pervious URL.
+
+ I also added the query parameter to the Place Hold's hold_source_page
+ URL variable. I did this, so that the query terms would be preserved
+ once the user is done placing the hold or decides to cancle the placing
+ of the hold.
+
+ As well, I used the new variables to remove Expert Search paramters
+ from the Advanced Search links on the results and record pages.
+
+ Conflicts:
+
+ Open-ILS/src/templates/opac/parts/searchbar.tt2
+
+ Signed-off-by: Liam Whalen <whalen.ld at gmail.com>
+ Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+4 0 Open-ILS/src/templates/opac/parts/header.tt2
+1 1 Open-ILS/src/templates/opac/parts/record/authors.tt2
+1 1 Open-ILS/src/templates/opac/parts/record/series.tt2
+1 1 Open-ILS/src/templates/opac/parts/record/subjects.tt2
+2 2 Open-ILS/src/templates/opac/parts/result/table.tt2
+1 1 Open-ILS/src/templates/opac/parts/searchbar.tt2
+1 1 Open-ILS/src/templates/opac/results.tt2
+
+commit 7169398270feea25e79e4682dbde3029f7de083b
+Author: Remington Steed <rjs7 at calvin.edu>
+Date: Mon Nov 18 15:42:36 2013 -0500
+
+ Docs: Remove ref to missing included file
+
+ This file was moved into the 2.5 release notes. If others believe it
+ belongs in the main documentation, it can easily be added in again. For
+ now, we will remove the reference because it only generates an asciidoc
+ warning.
+
+ Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+0 2 docs/root.txt
+
+commit 2f20d95461119fbe6360cc0eaa346d07ebaddd47
+Author: Remington Steed <rjs7 at calvin.edu>
+Date: Mon Nov 18 15:21:09 2013 -0500
+
+ Docs: Fix leveloffset bug, raise REL NOTES level
+
+ We should restrict our use of the asciidoc leveloffset command to the
+ root.txt file, since it is a global setting and cannot be set relative
+ to an existing offset.
+
+ This commit also raises the Release Notes section to the highest level
+ in order to prevent the lowest level subsections within it from being
+ lost. This is in response to asciidoc errors:
+
+ WARNING: RELEASE_NOTES_2_5.txt: line 950: missing section: [sect5]
+
+ Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+27 45 docs/RELEASE_NOTES_2_5.txt
+0 4 docs/root.txt
+
+commit 6353e2b8b6e72e83ffb1513720faf1b6d7c78d2b
+Author: Dan Scott <dscott at laurentian.ca>
+Date: Fri Nov 15 11:25:35 2013 -0500
+
+ Document how to load concerto sample data
+
+ We might as well make it as easy as possible for people to use the
+ sample dataset that we created!
+
+ Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+13 0 docs/installation/server_installation.txt
+
+commit c925dc2564141656f41cd298de2ed031e0e55b6b
+Author: Dan Scott <dscott at laurentian.ca>
+Date: Thu Nov 14 18:17:58 2013 -0500
+
+ Add basic docs for testing with pgTAP
+
+ This can be expanded to describe how to create pgTAP tests later. For
+ now, let's help people actually set up their environment and test.
+
+ Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+39 0 docs/development/pgtap.txt
+1 0 docs/root.txt
+ create mode 100644 docs/development/pgtap.txt
+
+commit b0711f572cab48341af687a80bf721241e616859
+Author: Pasi Kallinen <pasi.kallinen at pttk.fi>
+Date: Tue Jul 9 09:52:22 2013 +0300
+
+ Fix untranslatable strings in several dijits:
+
+ AutoGrid, EditPane, FlattenerGrid, GridColumnPicker and HoldingCode.
+
+ [LFW: One string amended in conflict resolution; commit message edited
+ to wrap; one line of code moved (this.nls assignment in
+ GridColumnPicker.js).]
+
+ Signed-off-by: Pasi Kallinen <pasi.kallinen at pttk.fi>
+ Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+
+9 0 Open-ILS/web/js/dojo/openils/serial/nls/serial.js
+6 3 Open-ILS/web/js/dojo/openils/widget/AutoGrid.js
+7 5 Open-ILS/web/js/dojo/openils/widget/EditPane.js
+2 1 Open-ILS/web/js/dojo/openils/widget/FlattenerGrid.js
+12 10 Open-ILS/web/js/dojo/openils/widget/GridColumnPicker.js
+12 13 Open-ILS/web/js/dojo/openils/widget/HoldingCode.js
+13 0 Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js
+
+commit 6ea75506c952a66d0f3aa98b5a662c3da91a8617
+Author: Steven Callender <stevecallender at esilibrary.com>
+Date: Thu Nov 14 15:42:12 2013 -0500
+
+ LP1251424 - Fix for submit button when placing holds in staff client
+
+ I've moved the initializing of the cur_hold_barcode variable
+ to within the function rather than floating outside of it.
+ This seemed to fix an intermittent issue where the submit
+ button would not become activatable when first going to the
+ place hold screen via the staff client. To create the hold,
+ ths user had to cycle through the "Place hold by patron barcode"
+ option and then back to "Place hold for me" option.
+
+ It looked like behind the scenes for certain org units that
+ variable would not be set and the button will not open until
+ it at least has something. This causes it to be set on the initial
+ loading of the screen.
+
+ Signed-off-by: Steven Callender <stevecallender at esilibrary.com>
+ Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1 1 Open-ILS/web/js/ui/default/opac/staff.js
+
+commit eaf9c8ec442c7da292ac377c6ccd83695920caf0
+Author: Garry Collum <gcollum at gmail.com>
+Date: Mon Jul 22 14:30:04 2013 -0400
+
+ lp1012237 HOLD_ITEM_CHECKED_OUT display
+
+ Added a definition to the HOLD_ITEM_CHECKED_OUT event in ils_events.xml.
+ Trying to be generic between the opac and the staff client the message
+ reads, "The item you have attempted to place on hold is already checked
+ out to the requestor."
+
+ [LFW: I made a tiny spelling change to be consistent with other
+ appearances in Evergreen of the term "requestor".]
+
+ Signed-off-by: Garry Collum <gcollum at gmail.com>
+ Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+
+3 0 Open-ILS/src/extras/ils_events.xml
+
+commit 7604c810051ec85cdcac40c69fde9cc4f8b930a0
+Author: Remington Steed <rjs7 at calvin.edu>
+Date: Mon Nov 11 14:15:25 2013 -0500
+
+ Update version of release notes in 2.5 docs
+
+ Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+1 1 docs/root.txt
+
+commit 88ced5b157978dab2260296859319cadb7675e9d
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date: Mon Oct 14 17:28:07 2013 -0400
+
+ Acq: Improvements to account-matching incoming EDI messages
+
+ The way the EDI fetcher works gives us a problem. That process iterates
+ over EDI accounts for which it has FTP host and credential information,
+ downloads documents from each of those sites, and files the messages
+ within those documents under the EDI account from which the login
+ credentials came. The problem is that in practice the exact same host
+ and login information is used by multiple accounts under the same
+ vendor, and files relating to these sub-accounts are commingled, so that
+ you can't make the decision about which messages should be filed under
+ which accounts based on the name of the document or its location. You
+ have to make that decision later, based on its contents.
+
+ We are already incompletely doing this, distinguishing between
+ sub-accounts under which we could file our messages when the vendor
+ specifies the buyer's SAN next to the specific sub-account number *and*
+ those sub-accounts belong to different Evergreen org units. We still
+ need ways to distinguish in other cases.
+
+ This will do what is natural for at least one vendor, and match the
+ message content against the vendacct field of the acq.edi_account table.
+
+ *Also,*
+
+ We were re-retrieving the working acq.edi_message row from the database
+ before writing it, throwing away possible changes to the object in hand
+ made by O::A::Acq::EDI::process_parsed_msg(). We should only do that in
+ the case where that function has raised an exception.
+
+ We were doing the same kind of thing in another place actually inside
+ process_parsed_msg() where we set the edi_message's purchase_order field
+ based on the first lineitem encountered if the message itself didn't
+ specify a valid PO identifier.
+
+ This supports making account-correction work for ORDRSP messages in
+ addition to INVOIC messages.
+
+ We also propagate that same correction to the provider and shipper
+ fields of any invoices that get created from said edi_message.
+
+ Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+ Signed-off-by: Kathy Lussier <klussier at masslnc.org>
+ Signed-off-by: Ben Shum <bshum at biblio.org>
+
+56 13 Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/EDI.pm
+
+commit b52e340ac3407558ebecace2334fb75dc9aaadea
+Author: Dan Wells <dbw2 at calvin.edu>
+Date: Mon Oct 28 11:23:08 2013 -0400
+
+ TPAC: Remove fixed height from 'View My List' button
+
+ The TPAC button styles have been largely consolidated, but this little
+ outlier got missed. It doesn't do anything of noticeable value in
+ recent browsers, and in fact hurts the display by causing the "Sort by"
+ widget to "hang" when resizing the window to certain intermediate
+ sizes. Remove it.
+
+ Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+ Signed-off-by: Ben Shum <bshum at biblio.org>
+
+0 2 Open-ILS/src/templates/opac/css/style.css.tt2
+1 1 Open-ILS/src/templates/opac/results.tt2
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application.pm
index d750216..4c8c8de 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application.pm
@@ -7,7 +7,7 @@ use OpenILS::Utils::Fieldmapper;
sub ils_version {
# version format is "x-y-z", for example "2-0-0" for Evergreen 2.0.0
# For branches, format is "x-y"
- return "HEAD";
+ return "2-5-1";
}
__PACKAGE__->register_method(
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 2744e49..92fb6d3 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -92,6 +92,7 @@ CREATE TRIGGER no_overlapping_deps
FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0848', :eg_version); -- miker
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.5.1', :eg_version);
CREATE TABLE config.bib_source (
id SERIAL PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/version-upgrade/2.5.0-2.5.1-upgrade-db.sql b/Open-ILS/src/sql/Pg/version-upgrade/2.5.0-2.5.1-upgrade-db.sql
new file mode 100644
index 0000000..61582ad
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/version-upgrade/2.5.0-2.5.1-upgrade-db.sql
@@ -0,0 +1,173 @@
+--Upgrade Script for 2.5.0 to 2.5.1
+\set eg_version '''2.5.1'''
+BEGIN;
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.5.1', :eg_version);
+
+SELECT evergreen.upgrade_deps_block_check('0848', :eg_version);
+
+CREATE OR REPLACE FUNCTION authority.normalize_heading( marcxml TEXT, no_thesaurus BOOL ) RETURNS TEXT AS $func$
+DECLARE
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ sf_node TEXT;
+ tag_node TEXT;
+ thes_code TEXT;
+ cset INT;
+ heading_text TEXT;
+ tmp_text TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT;
+BEGIN
+ SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+ IF cset IS NULL THEN
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]))
+ LIMIT 1;
+ END IF;
+
+ thes_code := vandelay.marc21_extract_fixed_field(marcxml,'Subj');
+ IF thes_code IS NULL THEN
+ thes_code := '|';
+ ELSIF thes_code = 'z' THEN
+ thes_code := COALESCE( oils_xpath_string('//*[@tag="040"]/*[@code="f"][1]', marcxml), '' );
+ END IF;
+
+ heading_text := '';
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset AND main_entry IS NULL LOOP
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+ first_sf := TRUE;
+
+ FOR tag_node IN SELECT unnest(oils_xpath('//*[@tag="'||tag_used||'"]',marcxml)) LOOP
+ FOR sf_node IN SELECT unnest(oils_xpath('//*[contains("'||acsaf.sf_list||'", at code)]',tag_node)) LOOP
+
+ tmp_text := oils_xpath_string('.', sf_node);
+ sf := oils_xpath_string('./@code', sf_node);
+
+ IF first_sf AND tmp_text IS NOT NULL AND nfi_used IS NOT NULL THEN
+
+ tmp_text := SUBSTRING(
+ tmp_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('./@ind'||nfi_used, tag_node),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ END IF;
+
+ first_sf := FALSE;
+
+ IF tmp_text IS NOT NULL AND tmp_text <> '' THEN
+ heading_text := heading_text || E'\u2021' || sf || ' ' || tmp_text;
+ END IF;
+ END LOOP;
+
+ EXIT WHEN heading_text <> '';
+ END LOOP;
+
+ EXIT WHEN heading_text <> '';
+ END LOOP;
+
+ IF heading_text <> '' THEN
+ IF no_thesaurus IS TRUE THEN
+ heading_text := tag_used || ' ' || public.naco_normalize(heading_text);
+ ELSE
+ heading_text := tag_used || '_' || COALESCE(nfi_used,'-') || '_' || thes_code || ' ' || public.naco_normalize(heading_text);
+ END IF;
+ ELSE
+ heading_text := 'NOHEADING_' || thes_code || ' ' || MD5(marcxml);
+ END IF;
+
+ RETURN heading_text;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION authority.simple_heading_set( marcxml TEXT ) RETURNS SETOF authority.simple_heading AS $func$
+DECLARE
+ res authority.simple_heading%ROWTYPE;
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ cset INT;
+ heading_text TEXT;
+ sort_text TEXT;
+ tmp_text TEXT;
+ tmp_xml TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml)::INT;
+BEGIN
+
+ res.record := auth_id;
+
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]) )
+ LIMIT 1;
+
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset LOOP
+
+ res.atag := acsaf.id;
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+
+ FOR tmp_xml IN SELECT UNNEST(XPATH('//*[@tag="'||tag_used||'"]', marcxml::XML)) LOOP
+
+ heading_text := public.naco_normalize(
+ COALESCE(
+ oils_xpath_string('//*[contains("'||acsaf.sf_list||'", at code)]',tmp_xml::TEXT, ' '),
+ ''
+ )
+ );
+
+ IF nfi_used IS NOT NULL THEN
+
+ sort_text := SUBSTRING(
+ heading_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('./@ind'||nfi_used, tmp_xml::TEXT),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ ELSE
+ sort_text := heading_text;
+ END IF;
+
+ IF heading_text IS NOT NULL AND heading_text <> '' THEN
+ res.value := heading_text;
+ res.sort_value := sort_text;
+ RETURN NEXT res;
+ END IF;
+
+ END LOOP;
+
+ END LOOP;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+
+COMMIT;
diff --git a/Open-ILS/xul/staff_client/chrome/content/main/about.html b/Open-ILS/xul/staff_client/chrome/content/main/about.html
index 2737f47..12027b9 100644
--- a/Open-ILS/xul/staff_client/chrome/content/main/about.html
+++ b/Open-ILS/xul/staff_client/chrome/content/main/about.html
@@ -1,7 +1,7 @@
<html><head><script></script></head><body onload="var x = document.getElementById('version'); var version ='/xul/server/'.split(/\//)[2]; if (version == 'server') { version = 'versionless debug build'; } x.appendChild(document.createTextNode(version));">
<h1 style="text-decoration: underline">Evergreen</h1>
<p>Target Server ID: <span id="version"></span></p>
-<p>$HeadURL$</p>
+<p>http://git.evergreen-ils.org/?p=Evergreen.git;a=shortlog;h=refs/heads/tags/rel_2_5_1</p>
<h2>What is Evergreen?</h2>
<blockquote>
<p>
diff --git a/Open-ILS/xul/staff_client/defaults/preferences/prefs.js b/Open-ILS/xul/staff_client/defaults/preferences/prefs.js
index 0613a13..c27c716 100644
--- a/Open-ILS/xul/staff_client/defaults/preferences/prefs.js
+++ b/Open-ILS/xul/staff_client/defaults/preferences/prefs.js
@@ -11,7 +11,7 @@ pref("toolkit.singletonWindowType", "eg_main");
pref("open-ils.enable_join_tabs", true);
// We'll use this one to help brand some build information into the client, and rely on subversion keywords
-pref("open-ils.repository.headURL","$HeadURL$");
+pref("open-ils.repository.headURL","http://git.evergreen-ils.org/?p=Evergreen.git;a=shortlog;h=refs/heads/tags/rel_2_5_1");
pref("open-ils.repository.author","$Author$");
pref("open-ils.repository.revision","$Revision$");
pref("open-ils.repository.date","$Date$");
diff --git a/Open-ILS/xul/staff_client/windowssetup.nsi b/Open-ILS/xul/staff_client/windowssetup.nsi
index a954357..5ba81df 100644
--- a/Open-ILS/xul/staff_client/windowssetup.nsi
+++ b/Open-ILS/xul/staff_client/windowssetup.nsi
@@ -3,7 +3,7 @@
; HM NIS Edit Wizard helper defines
; Old versions of makensis don't like this, moved to Makefile
;!define /file PRODUCT_VERSION "client/VERSION"
-!define PRODUCT_TAG "Master"
+!define PRODUCT_TAG "2.5"
!define PRODUCT_INSTALL_TAG "${PRODUCT_TAG}"
!define UI_IMAGESET "beta"
;!define UI_IMAGESET "release"
diff --git a/README b/README
deleted file mode 120000
index b57451a..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-docs/installation/server_installation.txt
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..ee1fd98
--- /dev/null
+++ b/README
@@ -0,0 +1,551 @@
+Installing the Evergreen server
+===============================
+:toc:
+:numbered:
+
+Preamble: referenced user accounts
+----------------------------------
+
+In subsequent sections, we will refer to a number of different accounts, as
+follows:
+
+ * Linux user accounts:
+ ** The *user* Linux account is the account that you use to log onto the
+ Linux system as a regular user.
+ ** The *root* Linux account is an account that has system administrator
+ privileges. On Debian and Fedora you can switch to this account from
+ your *user* account by issuing the `su -` command and entering the
+ password for the *root* account when prompted. On Ubuntu you can switch
+ to this account from your *user* account using the `sudo su -` command
+ and entering the password for your *user* account when prompted.
+ ** The *opensrf* Linux account is an account that you create when installing
+ OpenSRF. You can switch to this account from the *root* account by
+ issuing the `su - opensrf` command.
+ ** The *postgres* Linux account is created automatically when you install
+ the PostgreSQL database server. You can switch to this account from the
+ *root* account by issuing the `su - postgres` command.
+ * PostgreSQL user accounts:
+ ** The *evergreen* PostgreSQL account is a superuser account that you will
+ create to connect to the PostgreSQL database server.
+ * Evergreen administrator account:
+ ** The *egadmin* Evergreen account is an administrator account for
+ Evergreen that you will use to test connectivity and configure your
+ Evergreen instance.
+
+Preamble: developer instructions
+--------------------------------
+
+[NOTE]
+Skip this section if you are using an official release tarball downloaded
+from http://evergreen-ils.org/downloads
+
+Developers working directly with the source code from the Git repository,
+rather than an official release tarball, must install some extra packages
+and perform one step before they can proceed with the `./configure` step.
+
+As the *root* Linux account, install the following packages:
+
+ * autoconf
+ * automake
+ * libtool
+
+As the *user* Linux account, issue the following command in the Evergreen
+source directory to generate the configure script and Makefiles:
+
+[source, bash]
+------------------------------------------------------------------------------
+autoreconf -i
+------------------------------------------------------------------------------
+
+After running `make install`, developers also need to install the Dojo Toolkit
+set of JavaScript libraries. The appropriate version of Dojo is included
+in Evergreen release tarballs. Developers should install the Dojo 1.3.3
+version of Dojo by issuing the following commands as the *opensrf* Linux
+account:
+
+[source, bash]
+------------------------------------------------------------------------------
+wget http://download.dojotoolkit.org/release-1.3.3/dojo-release-1.3.3.tar.gz
+tar -C /openils/var/web/js -xzf dojo-release-1.3.3.tar.gz
+cp -r /openils/var/web/js/dojo-release-1.3.3/* /openils/var/web/js/dojo/.
+------------------------------------------------------------------------------
+
+Installing prerequisites
+------------------------
+
+Evergreen has a number of prerequisite packages that must be installed
+before you can successfully configure, compile, and install Evergreen.
+
+1. Begin by installing the most recent version of OpenSRF (2.2.1 or later).
+ You can download OpenSRF releases from http://evergreen-ils.org/opensrf-downloads/
+2. On many distributions, it is necessary to install PostgreSQL 9 from external
+ repositories.
++
+ * On Debian Squeeze, open `/etc/apt/sources.list` in a text editor as the
+ *root* Linux account and add the following line:
++
+[source, bash]
+------------------------------------------------------------------------------
+deb http://backports.debian.org/debian-backports squeeze-backports main contrib
+------------------------------------------------------------------------------
++
+ * On Ubuntu Lucid, you can use a PPA (personal package archive), which are
+ package sources hosted on Launchpad. The one most commonly used by Evergreen
+ Community members is maintained by Martin Pitt, who also maintains the
+ official PostgreSQL packages for Ubuntu. As the *root* Linux account, issue
+ the following commands to add the PPA source:
++
+[source, bash]
+------------------------------------------------------------------------------
+apt-get install python-software-properties
+add-apt-repository ppa:pitti/postgresql
+------------------------------------------------------------------------------
++
+ * Ubuntu Precise comes with PostgreSQL 9, so no additional steps are required.
++
+ * Fedora comes with PostgreSQL 9, so no additional steps are required.
++
+3. On Debian and Ubuntu, run `aptitude update` as the *root* Linux account to
+ retrieve the new packages from the backports repository.
+4. Issue the following commands as the *root* Linux account to install
+ prerequisites using the `Makefile.install` prerequisite installer,
+ substituting `debian-squeeze`, `fedora`, `ubuntu-lucid`, or
+ `ubuntu-precise` for <osname> below:
++
+[source, bash]
+------------------------------------------------------------------------------
+make -f Open-ILS/src/extras/Makefile.install <osname>
+------------------------------------------------------------------------------
++
+5. Add the libdbi-libdbd libraries to the system dynamic library path by
+ issuing the following commands as the *root* Linux account:
++
+[NOTE]
+You should skip this step if installing on Ubuntu Precise. The ubuntu-precise
+target uses libdbd-pgsql from packages.
++
+.Debian / Ubuntu Lucid
+[source, bash]
+------------------------------------------------------------------------------
+echo "/usr/local/lib/dbd" > /etc/ld.so.conf.d/eg.conf
+ldconfig
+------------------------------------------------------------------------------
++
+.Fedora
+[source, bash]
+------------------------------------------------------------------------------
+echo "/usr/lib64/dbd" > /etc/ld.so.conf.d/eg.conf
+ldconfig
+------------------------------------------------------------------------------
+
+Configuration and compilation instructions
+------------------------------------------
+
+For the time being, we are still installing everything in the `/openils/`
+directory. From the Evergreen source directory, issue the following commands as
+the *user* Linux account to configure and build Evergreen:
+
+[source, bash]
+------------------------------------------------------------------------------
+PATH=/openils/bin:$PATH ./configure --prefix=/openils --sysconfdir=/openils/conf
+make
+------------------------------------------------------------------------------
+
+These instructions assume that you have also installed OpenSRF under `/openils/`.
+If not, please adjust PATH as needed so that the Evergreen `configure` script
+can find `osrf_config`.
+
+Installation instructions
+-------------------------
+
+1. Once you have configured and compiled Evergreen, issue the following
+ command as the *root* Linux account to install Evergreen, build the server
+ portion of the staff client, and copy example configuration files to
+ `/openils/conf`.
+ Change the value of the `STAFF_CLIENT_STAMP_ID` variable to match the version
+ of the staff client that you will use to connect to the Evergreen server.
++
+[source, bash]
+------------------------------------------------------------------------------
+make STAFF_CLIENT_STAMP_ID=rel_2_5_1 install
+------------------------------------------------------------------------------
++
+2. The server portion of the staff client expects `http://hostname/xul/server`
+ to resolve. Issue the following commands as the *root* Linux account to
+ create a symbolic link pointing to the `server` subdirectory of the server
+ portion of the staff client that we just built using the staff client ID
+ 'rel_name':
++
+[source, bash]
+------------------------------------------------------------------------------
+cd /openils/var/web/xul
+ln -sf rel_name/server server
+------------------------------------------------------------------------------
+
+Change ownership of the Evergreen files
+---------------------------------------
+
+All files in the `/openils/` directory and subdirectories must be owned by the
+`opensrf` user. Issue the following command as the *root* Linux account to
+change the ownership on the files:
+
+[source, bash]
+------------------------------------------------------------------------------
+chown -R opensrf:opensrf /openils
+------------------------------------------------------------------------------
+
+Configure the Apache Web server
+-------------------------------
+
+1. Use the example configuration files in `Open-ILS/examples/apache/` (for
+Apache versions below 2.4) or `Open-ILS/examples/apache_24/` (for Apache
+versions 2.4 or greater) to configure your Web server for the Evergreen
+catalog, staff client, Web services, and administration interfaces. Issue the
+following commands as the *root* Linux account:
++
+.Debian and Ubuntu
+[source,bash]
+------------------------------------------------------------------------------
+cp Open-ILS/examples/apache/eg.conf /etc/apache2/sites-available/
+cp Open-ILS/examples/apache/eg_vhost.conf /etc/apache2/
+cp Open-ILS/examples/apache/eg_startup /etc/apache2/
+# Now set up SSL
+mkdir /etc/apache2/ssl
+cd /etc/apache2/ssl
+------------------------------------------------------------------------------
++
+.Fedora
+[source,bash]
+------------------------------------------------------------------------------
+cp Open-ILS/examples/apache_24/eg_24.conf /etc/httpd/conf.d/
+cp Open-ILS/examples/apache_24/eg_vhost_24.conf /etc/httpd/eg_vhost.conf
+cp Open-ILS/examples/apache/eg_startup /etc/httpd/
+# Now set up SSL
+mkdir /etc/httpd/ssl
+cd /etc/httpd/ssl
+------------------------------------------------------------------------------
++
+2. The `openssl` command cuts a new SSL key for your Apache server. For a
+production server, you should purchase a signed SSL certificate, but you can
+just use a self-signed certificate and accept the warnings in the staff client
+and browser during testing and development. Create an SSL key for the Apache
+server by issuing the following command as the *root* Linux account:
++
+[source,bash]
+------------------------------------------------------------------------------
+openssl req -new -x509 -days 365 -nodes -out server.crt -keyout server.key
+------------------------------------------------------------------------------
++
+3. As the *root* Linux account, edit the `eg.conf` file that you copied into
+place.
+ a. To enable access to the offline upload / execute interface from any
+ workstation on any network, make the following change (and note that
+ you *must* secure this for a production instance):
+ * (Apache 2.2): Replace `Allow from 10.0.0.0/8` with `Allow from all`
+ * (Apache 2.4): Replace `Require host 10.0.0.0/8` with `Require all granted`
+ b. (Fedora): Change references from the non-existent `/etc/apache2/` directory
+ to `/etc/httpd/`.
+4. Change the user for the Apache server.
+ * (Debian and Ubuntu): As the *root* Linux account, edit
+ `/etc/apache2/envvars`. Change `export APACHE_RUN_USER=www-data` to
+ `export APACHE_RUN_USER=opensrf`.
+ * (Fedora): As the *root* Linux account , edit `/etc/httpd/conf/httpd.conf`.
+ Change `User apache` to `User opensrf`.
+5. Configure Apache with performance settings appropriate for Evergreen:
+ * (Debian and Ubuntu): As the *root* Linux account, edit
+ `/etc/apache2/apache2.conf`:
+ * (Fedora): As the *root* Linux account, edit `/etc/httpd/conf/httpd.conf`:
+ a. Change `KeepAliveTimeout` to `1`. Higher values reduce the chance of
+ a request timing out unexpectedly, but increase the risk of using up
+ all available Apache child processes.
+ b. 'Optional': Change `MaxKeepAliveRequests` to `100`
+ c. Update the prefork configuration section to suit your environment. The
+ following settings apply to a busy system:
++
+[source,bash]
+------------------------------------------------------------------------------
+<IfModule mpm_prefork_module>
+ StartServers 20
+ MinSpareServers 5
+ MaxSpareServers 15
+ MaxClients 150
+ MaxRequestsPerChild 10000
+</IfModule>
+------------------------------------------------------------------------------
++
+6. (Fedora): As the *root* Linux account, edit the `/etc/httpd/eg_vhost.conf`
+ file to change references from the non-existent `/etc/apache2/` directory
+ to `/etc/httpd/`.
+7. (Debian and Ubuntu): As the *root* Linux account, enable the Evergreen site:
++
+[source,bash]
+------------------------------------------------------------------------------
+a2dissite default # OPTIONAL: disable the default site (the "It Works" page)
+a2ensite eg.conf
+------------------------------------------------------------------------------
+
+Configure OpenSRF for the Evergreen application
+-----------------------------------------------
+There are a number of example OpenSRF configuration files in `/openils/conf/`
+that you can use as a template for your Evergreen installation. Issue the
+following commands as the *opensrf* Linux account:
+
+[source, bash]
+------------------------------------------------------------------------------
+cp -b /openils/conf/opensrf_core.xml.example /openils/conf/opensrf_core.xml
+cp -b /openils/conf/opensrf.xml.example /openils/conf/opensrf.xml
+------------------------------------------------------------------------------
+
+When you installed OpenSRF, you created four Jabber users on two
+separate domains and edited the `opensrf_core.xml` file accordingly. Please
+refer back to the OpenSRF README and, as the *opensrf* Linux account, edit the
+Evergreen version of the `opensrf_core.xml` file using the same Jabber users
+and domains as you used while installing and testing OpenSRF.
+
+[NOTE]
+The `-b` flag tells the `cp` command to create a backup version of the
+destination file. The backup version of the destination file has a tilde (`~`)
+appended to the file name, so if you have forgotten the Jabber users and
+domains, you can retrieve the settings from the backup version of the files.
+
+`eg_db_config`, described in the following section, sets the database
+connection information in `opensrf.xml` for you.
+
+Creating the Evergreen database
+-------------------------------
+
+By default, the `Makefile.install` prerequisite installer does not install
+the PostgreSQL 9 database server required by every Evergreen system;
+for production use, most libraries install the PostgreSQL database server on a
+dedicated machine. You can install the packages required by Debian or Ubuntu Lucid
+on the machine of your choice using the following commands as the *root*
+Linux account:
+
+.(Debian / Ubuntu / Fedora) Installing PostgreSQL server packages
+
+Each OS build target provides the postgres server installation packages
+required for each operating system. To install Postgres server packages,
+use the make target 'postgres-server-<OSTYPE>'. Choose the most appropriate
+command below based on your operating system.
+
+[source, bash]
+------------------------------------------------------------------------------
+make -f Open-ILS/src/extras/Makefile.install postgres-server-debian-wheezy
+make -f Open-ILS/src/extras/Makefile.install postgres-server-debian-squeeze
+make -f Open-ILS/src/extras/Makefile.install postgres-server-ubuntu-lucid
+make -f Open-ILS/src/extras/Makefile.install postgres-server-ubuntu-precise
+make -f Open-ILS/src/extras/Makefile.install postgres-server-fedora
+------------------------------------------------------------------------------
+
+.(Fedora) Postgres initialization
+
+Installing Postgres on Fedora requires one additional step.
+
+[source, bash]
+------------------------------------------------------------------------------
+postgresql-setup initdb
+------------------------------------------------------------------------------
+
+For a standalone PostgreSQL server, install the following Perl modules as the
+*root* Linux account:
+
+.(Debian / Ubuntu) Installing additional Perl modules on a standalone PostgreSQL 9 server
+[source, bash]
+------------------------------------------------------------------------------
+aptitude install gcc libxml-libxml-perl libxml-libxslt-perl
+cpan Business::ISBN
+cpan JSON::XS
+cpan Library::CallNumber::LC
+cpan MARC::Record
+cpan MARC::File::XML
+cpan UUID::Tiny
+cpan Rose::URI
+------------------------------------------------------------------------------
+
+.(Fedora) Installing additional Perl modules on a standalone PostgreSQL 9 server
+[source, bash]
+------------------------------------------------------------------------------
+yum install gcc perl-XML-LibXML perl-XML-LibXSLT perl-Business-ISBN
+yum install perl-Library-CallNumber-LC perl-MARC-Record perl-MARC-Charset
+yum install perl-MARC-File-XML perl-UUID-Tiny
+------------------------------------------------------------------------------
+
+You need to create a PostgreSQL superuser to create and access the database.
+Issue the following command as the *postgres* Linux account to create a new
+PostgreSQL superuser named `evergreen`. When prompted, enter the new user's
+password:
+
+[source, bash]
+------------------------------------------------------------------------------
+createuser -s -P evergreen
+------------------------------------------------------------------------------
+
+Once you have created the *evergreen* PostgreSQL account, you also need to
+create the database and schema, and configure your configuration files to point
+at the database server. Issue the following command as the *root* Linux account
+from inside the Evergreen source directory, replacing <user>, <password>,
+<hostname>, <port>, and <dbname> with the appropriate values for your
+PostgreSQL database (where <user> and <password> are for the *evergreen*
+PostgreSQL account you just created), and replace <admin-user> and <admin-pass>
+with the values you want for the *egadmin* Evergreen administrator account:
+
+[source, bash]
+------------------------------------------------------------------------------
+perl Open-ILS/src/support-scripts/eg_db_config --update-config \
+ --service all --create-database --create-schema --create-offline \
+ --user <user> --password <password> --hostname <hostname> --port <port> \
+ --database <dbname> --admin-user <admin-user> --admin-pass <admin-pass>
+------------------------------------------------------------------------------
+
+This creates the database and schema and configures all of the services in
+your `/openils/conf/opensrf.xml` configuration file to point to that database.
+It also creates the configuration files required by the Evergreen `cgi-bin`
+administration scripts, and sets the user name and password for the *egadmin*
+Evergreen administrator account to your requested values.
+
+You can get a complete set of options for `eg_db_config.pl` by passing the
+`--help` parameter.
+
+Loading sample data
+~~~~~~~~~~~~~~~~~~~
+If you add the `--load-all-sample` parameter to the `eg_db_config` command,
+a set of authority and bibliographic records, call numbers, copies, staff
+and regular users, and transactions will be loaded into your target
+database. This sample dataset is commonly referred to as the _concerto_
+sample data, and can be useful for testing out Evergreen functionality and
+for creating problem reports that developers can easily recreate with their
+own copy of the _concerto_ sample data.
+
+Creating the database on a remote server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In a production instance of Evergreen, your PostgreSQL server should be
+installed on a dedicated server.
+
+PostgreSQL 9.1 and later
+^^^^^^^^^^^^^^^^^^^^^^^^
+To create the database instance on a remote database server running PostgreSQL
+9.1 or later, simply use the `--create-database` flag on `eg_db_config`.
+
+Starting Evergreen
+------------------
+1. As the *root* Linux account, start the `memcached` and `ejabberd` services
+(if they aren't already running):
++
+[source, bash]
+------------------------------------------------------------------------------
+/etc/init.d/ejabberd start
+/etc/init.d/memcached start
+------------------------------------------------------------------------------
++
+2. As the *opensrf* Linux account, start Evergreen. The `-l` flag in the
+following command is only necessary if you want to force Evergreen to treat the
+hostname as `localhost`; if you configured `opensrf.xml` using the real
+hostname of your machine as returned by `perl -ENet::Domain 'print
+Net::Domain::hostfqdn() . "\n";'`, you should not use the `-l` flag.
++
+[source, bash]
+------------------------------------------------------------------------------
+osrf_ctl.sh -l -a start_all
+------------------------------------------------------------------------------
++
+ ** If you receive the error message `bash: osrf_ctl.sh: command not found`,
+ then your environment variable `PATH` does not include the `/openils/bin`
+ directory; this should have been set in the *opensrf* Linux account's
+ `.bashrc` configuration file. To manually set the `PATH` variable, edit the
+ configuration file `~/.bashrc` as the *opensrf* Linux account and add the
+ following line:
++
+[source, bash]
+------------------------------------------------------------------------------
+export PATH=$PATH:/openils/bin
+------------------------------------------------------------------------------
++
+3. As the *opensrf* Linux account, generate the Web files needed by the staff
+ client and catalogue and update the organization unit proximity (you need to do
+ this the first time you start Evergreen, and after that each time you change
+ the library hierarchy in `config.cgi`):
++
+[source, bash]
+------------------------------------------------------------------------------
+autogen.sh -u
+------------------------------------------------------------------------------
++
+4. As the *root* Linux account, restart the Apache Web server:
++
+[source, bash]
+------------------------------------------------------------------------------
+/etc/init.d/apache2 restart
+------------------------------------------------------------------------------
++
+If the Apache Web server was running when you started the OpenSRF services, you
+might not be able to successfully log in to the OPAC or staff client until the
+Apache Web server is restarted.
+
+Testing connections to Evergreen
+--------------------------------
+
+Once you have installed and started Evergreen, test your connection to
+Evergreen via `srfsh`. As the *opensrf* Linux account, issue the following
+commands to start `srfsh` and try to log onto the Evergreen server using the
+*egadmin* Evergreen administrator user name and password that you set using the
+`eg_db_config` command:
+
+[source, bash]
+------------------------------------------------------------------------------
+/openils/bin/srfsh
+srfsh% login <admin-user> <admin-pass>
+------------------------------------------------------------------------------
+
+You should see a result like:
+
+ Received Data: "250bf1518c7527a03249858687714376"
+ ------------------------------------
+ Request Completed Successfully
+ Request Time in seconds: 0.045286
+ ------------------------------------
+
+ Received Data: {
+ "ilsevent":0,
+ "textcode":"SUCCESS",
+ "desc":" ",
+ "pid":21616,
+ "stacktrace":"oils_auth.c:304",
+ "payload":{
+ "authtoken":"e5f9827cc0f93b503a1cc66bee6bdd1a",
+ "authtime":420
+ }
+
+ }
+
+ ------------------------------------
+ Request Completed Successfully
+ Request Time in seconds: 1.336568
+ ------------------------------------
+
+If this does not work, it's time to do some troubleshooting.
+
+ * As the *opensrf* Linux account, run the `settings-tester.pl` script to see
+ if it finds any system configuration problems. The script is found at
+ `Open-ILS/src/support-scripts/settings-tester.pl` in the Evergreen source
+ tree.
+ * Follow the steps in the http://evergreen-ils.org/dokuwiki/doku.php?id=troubleshooting:checking_for_errors[troubleshooting guide].
+ * If you have faithfully followed the entire set of installation steps
+ listed here, you are probably extremely close to a working system.
+ Gather your configuration files and log files and contact the
+ http://evergreen-ils.org/communicate/mailing-lists/[Evergreen development
+mailing list] for assistance before making any drastic changes to your system
+ configuration.
+
+Getting help
+------------
+
+Need help installing or using Evergreen? Join the mailing lists at
+http://evergreen-ils.org/communicate/mailing-lists/ or contact us on the Freenode
+IRC network on the #evergreen channel.
+
+License
+-------
+This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
+Unported License. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
+Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
diff --git a/configure.ac b/configure.ac
index 99370e4..ce744f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,8 +20,8 @@
export PATH=${PATH}:/usr/sbin
AC_PREREQ(2.61)
-AC_INIT(Open-ILS, trunk, open-ils-dev at list.georgialibraries.org)
-AM_INIT_AUTOMAKE([OpenILS], [trunk])
+AC_INIT(Open-ILS, 2.5.1, open-ils-dev at list.georgialibraries.org)
+AM_INIT_AUTOMAKE([OpenILS], [2.5.1])
AC_REVISION($Revision: 0.1 $)
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_SUBDIRS([Open-ILS/xul/staff_client/external/libmar])
commit 9bc51396d5fb86ca8b10ea22a5773665ccc20eeb
Author: Dan Wells <dbw2 at calvin.edu>
Date: Thu Nov 7 16:35:15 2013 -0500
Changes to smooth out make_release
1) Make the fake 'HeadURL' into a URL which works with our web repo.
Note that this has 'tags/' hardcoded in, so it only works with true
release branches (e.g. rel_x_y_z) not "working" branches
(e.g. rel_x_y).
2) Change range selector when building log to exclude commits from
rel_2_4.
3) Switch the XULRunner download order so that we can remove them
automatically during make_release and manually afterwards.
4) Add a pause between tagging and building for manual tweaks.
Signed-off-by: Dan Wells <dbw2 at calvin.edu>
diff --git a/build/tools/make_release b/build/tools/make_release
index c141ca7..3a710d6 100755
--- a/build/tools/make_release
+++ b/build/tools/make_release
@@ -2,7 +2,7 @@
GIT_ABS=`git rev-parse --show-toplevel`
GIT_BRANCH=`git rev-parse --abbrev-ref HEAD | sed 's|.*/||'`
-HEADURLBASE="http://git.evergreen-ils.org/Evergreen.git?h=refs/heads/"
+HEADURLBASE="http://git.evergreen-ils.org/?p=Evergreen.git;a=shortlog;h=refs/heads/tags/"
HEADURL="$HEADURLBASE$GIT_BRANCH"
# Drop to the root of the checkout
@@ -246,7 +246,7 @@ if [ $PREV_BRANCH != "PACKAGE" ]; then
grep -i -m 1 Signed-off-by ChangeLog &> /dev/null
if [ $? -ne 0 ]; then
echo "Building ChangeLog"
- git log --cherry-pick --right-only --no-merges --pretty --summary --numstat $PREV_BRANCH..HEAD > $GIT_ABS/ChangeLog
+ git log --cherry-pick --right-only --no-merges --pretty --summary --numstat $PREV_BRANCH...HEAD > $GIT_ABS/ChangeLog
else
echo "Not overwriting existing ChangeLog!"
fi
@@ -257,6 +257,8 @@ if [ $PREV_BRANCH != "PACKAGE" ]; then
COMMIT_MESSAGE="Bumping version numbers, adding Upgrade Script and Changelog"
fi
git commit -asm "$COMMIT_MESSAGE"
+
+ read -p "If you wish to make manual edits before building, suspend and do so now..."
fi
echo "Building release dump"
@@ -283,24 +285,25 @@ if [ ! -f "../dojo.tgz" ]; then
wget http://evergreen-ils.org/downloads/dojo.tgz -O ../dojo.tgz
fi
tar xzf ../dojo.tgz -C Open-ILS/web/js/dojo/
-echo "Grabbing XULRunner (to avoid issues with version changes)"
-cd Open-ILS/xul/staff_client
-XULRUNNER_VERSION=`grep '^XULRUNNER_VERSION' Makefile.am`
-XULRUNNER_VERSION=${XULRUNNER_VERSION##XULRUNNER_VERSION=}
-wget http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/$XULRUNNER_VERSION/runtimes/xulrunner-$XULRUNNER_VERSION.en-US.win32.zip
-wget http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/$XULRUNNER_VERSION/runtimes/xulrunner-$XULRUNNER_VERSION.en-US.linux-i686.tar.bz2
-wget http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/$XULRUNNER_VERSION/runtimes/xulrunner-$XULRUNNER_VERSION.en-US.linux-x86_64.tar.bz2
+cd ..
echo "Prepping server download files"
-cd ../../../../
tar czf Evergreen-ILS-$VERSION.tar.gz Evergreen-ILS-$VERSION/
md5sum Evergreen-ILS-$VERSION.tar.gz > Evergreen-ILS-$VERSION.tar.gz.md5
if [ $PREV_BRANCH != "PACKAGE" ]; then # We need to have tagged to do this ;)
cp Evergreen-ILS-$VERSION/ChangeLog ChangeLog-$PREV_VERSION-$VERSION
fi
+echo "Grabbing XULRunner (to avoid issues with version changes)"
+cd Evergreen-ILS-$VERSION/Open-ILS/xul/staff_client
+XULRUNNER_VERSION=`grep '^XULRUNNER_VERSION' Makefile.am`
+XULRUNNER_VERSION=${XULRUNNER_VERSION##XULRUNNER_VERSION=}
+wget http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/$XULRUNNER_VERSION/runtimes/xulrunner-$XULRUNNER_VERSION.en-US.win32.zip
+wget http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/$XULRUNNER_VERSION/runtimes/xulrunner-$XULRUNNER_VERSION.en-US.linux-i686.tar.bz2
+wget http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/$XULRUNNER_VERSION/runtimes/xulrunner-$XULRUNNER_VERSION.en-US.linux-x86_64.tar.bz2
+cd ../../..
+
echo "Running enough of configure to build staff client"
-cd Evergreen-ILS-$VERSION/
./configure --disable-core --disable-web --disable-updates --disable-apache-modules --disable-reporter
echo "Building Release Staff Clients"
commit 92ba29f2c208325e847f1367e32f2ed18de84cb0
Author: Dan Wells <dbw2 at calvin.edu>
Date: Tue Nov 26 14:35:22 2013 -0500
Bump OpenILS.pm version
Signed-off-by: Dan Wells <dbw2 at calvin.edu>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS.pm b/Open-ILS/src/perlmods/lib/OpenILS.pm
index d7235ce..bfaff18 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS.pm
@@ -6,6 +6,6 @@ OpenILS - Client and server support for the Evergreen open source library system
=cut
-our $VERSION = '2.4';
+our $VERSION = '2.0501';
1;
-----------------------------------------------------------------------
hooks/post-receive
--
Evergreen ILS
More information about the open-ils-commits
mailing list