2 * Copyright (C) 2008 Equinox Software, Inc.
3 * Mike Rylander <miker@esilibrary.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
18 ALTER TABLE auditor.asset_copy_history ALTER COLUMN price DROP NOT NULL; -- Price is nullable in 1.4+, auditor triggers complain when it's not informed of this
20 -- Get rid of embedded slashes from old ingest
21 UPDATE metabib.title_field_entry
22 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
23 WHERE value ~ E'(\\w+)\\/(\\w+)';
25 UPDATE metabib.author_field_entry
26 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
27 WHERE value ~ E'(\\w+)\\/(\\w+)';
29 UPDATE metabib.subject_field_entry
30 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
31 WHERE value ~ E'(\\w+)\\/(\\w+)';
33 UPDATE metabib.series_field_entry
34 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
35 WHERE value ~ E'(\\w+)\\/(\\w+)';
37 UPDATE metabib.keyword_field_entry
38 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
39 WHERE value ~ E'(\\w+)\\/(\\w+)';
41 UPDATE metabib.full_rec
42 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
43 WHERE value ~ E'(\\w+)\\/(\\w+)';
49 -- To avoid any updates while we're doin' our thing...
50 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
52 CREATE TABLE config.upgrade_log (
53 version TEXT PRIMARY KEY,
54 install_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
56 INSERT INTO config.upgrade_log (version) VALUES ('1.4.0.0');
58 SELECT set_curcfg('default');
60 CREATE OR REPLACE FUNCTION public.extract_marc_field ( TEXT, BIGINT, TEXT, TEXT ) RETURNS TEXT AS $$
61 SELECT regexp_replace(array_to_string( array_accum( output ),' ' ),$4,'','g') FROM xpath_table('id', 'marc', $1, $3, 'id='||$2)x(id INT, output TEXT);
64 CREATE OR REPLACE FUNCTION public.extract_marc_field ( TEXT, BIGINT, TEXT ) RETURNS TEXT AS $$
65 SELECT public.extract_marc_field($1,$2,$3,'');
68 CREATE TABLE config.i18n_locale (
69 code TEXT PRIMARY KEY,
70 marc_code TEXT NOT NULL REFERENCES config.language_map (code) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
71 name TEXT UNIQUE NOT NULL,
74 INSERT INTO config.i18n_locale (code,marc_code,name,description) VALUES ('en-US', 'eng', 'English (US)', 'American English');
75 INSERT INTO config.i18n_locale (code,marc_code,name,description) VALUES ('en-CA', 'eng', 'English (Canada)', 'Canadian English');
76 INSERT INTO config.i18n_locale (code,marc_code,name,description) VALUES ('fr-CA', 'fre', 'French (Canada)', 'Canadian French');
77 INSERT INTO config.i18n_locale (code,marc_code,name,description) VALUES ('hy-AM', 'arm', 'Armenian', 'Armenian');
80 CREATE TABLE config.i18n_core (
81 id BIGSERIAL PRIMARY KEY,
82 fq_field TEXT NOT NULL,
83 identity_value TEXT NOT NULL,
84 translation TEXT NOT NULL REFERENCES config.i18n_locale (code) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
87 CREATE UNIQUE INDEX i18n_identity ON config.i18n_core (fq_field,identity_value,translation);
89 CREATE OR REPLACE FUNCTION oils_i18n_xlate ( keytable TEXT, keyclass TEXT, keycol TEXT, identcol TEXT, keyvalue TEXT, raw_locale TEXT ) RETURNS TEXT AS $func$
91 locale TEXT := REGEXP_REPLACE( REGEXP_REPLACE( raw_locale, E'[;, ].+$', '' ), E'_', '-', 'g' );
92 language TEXT := REGEXP_REPLACE( locale, E'-.+$', '' );
93 result config.i18n_core%ROWTYPE;
95 keyfield TEXT := keyclass || '.' || keycol;
98 -- Try the full locale
100 FROM config.i18n_core
101 WHERE fq_field = keyfield
102 AND identity_value = keyvalue
103 AND translation = locale;
105 -- Try just the language
108 FROM config.i18n_core
109 WHERE fq_field = keyfield
110 AND identity_value = keyvalue
111 AND translation = language;
114 -- Fall back to the string we passed in in the first place
119 ' FROM ' || keytable ||
120 ' WHERE ' || identcol || ' = ' || quote_literal(keyvalue)
125 RETURN result.string;
127 $func$ LANGUAGE PLPGSQL;
129 -- Functions for marking translatable strings in SQL statements
130 -- Parameters are: primary key, string, class hint, property
131 CREATE OR REPLACE FUNCTION oils_i18n_gettext( INT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$
135 CREATE OR REPLACE FUNCTION oils_i18n_gettext( TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$
139 ALTER TABLE config.xml_transform DROP CONSTRAINT xml_transform_namespace_uri_key;
140 INSERT INTO config.xml_transform VALUES ( 'mods32', 'http://www.loc.gov/mods/', 'mods', '' );
143 /* Upgrade to MODS32 for transforms */
144 ALTER TABLE config.metabib_field ALTER COLUMN format SET DEFAULT 'mods32';
145 UPDATE config.metabib_field SET format = 'mods32';
147 /* Update index definitions to MODS32-compliant XPaths */
148 UPDATE config.metabib_field
149 SET xpath = $$//mods:mods/mods:name[@type='corporate']/mods:namePart[../mods:role/mods:roleTerm[text()='creator']]$$
150 WHERE field_class = 'author' AND name = 'corporate';
151 UPDATE config.metabib_field
152 SET xpath = $$//mods:mods/mods:name[@type='personal']/mods:namePart[../mods:role/mods:roleTerm[text()='creator']]$$
153 WHERE field_class = 'author' AND name = 'personal';
154 UPDATE config.metabib_field
155 SET xpath = $$//mods:mods/mods:name[@type='conference']/mods:namePart[../mods:role/mods:roleTerm[text()='creator']]$$
156 WHERE field_class = 'author' AND name = 'conference';
158 /* And they all want mods32: as their prefix */
159 UPDATE config.metabib_field SET xpath = regexp_replace(xpath, 'mods:', 'mods32:', 'g');
162 ALTER TABLE config.copy_status ADD COLUMN opac_visible BOOL NOT NULL DEFAULT FALSE;
163 UPDATE config.copy_status SET opac_visible = holdable;
165 CREATE TABLE config.bib_level_map (
166 code TEXT PRIMARY KEY,
169 INSERT INTO config.bib_level_map (code, value) VALUES ('a', oils_i18n_gettext('a', 'Monographic component part', 'cblvl', 'value'));
170 INSERT INTO config.bib_level_map (code, value) VALUES ('b', oils_i18n_gettext('b', 'Serial component part', 'cblvl', 'value'));
171 INSERT INTO config.bib_level_map (code, value) VALUES ('c', oils_i18n_gettext('c', 'Collection', 'cblvl', 'value'));
172 INSERT INTO config.bib_level_map (code, value) VALUES ('d', oils_i18n_gettext('d', 'Subunit', 'cblvl', 'value'));
173 INSERT INTO config.bib_level_map (code, value) VALUES ('i', oils_i18n_gettext('i', 'Integrating resource', 'cblvl', 'value'));
174 INSERT INTO config.bib_level_map (code, value) VALUES ('m', oils_i18n_gettext('m', 'Monograph/Item', 'cblvl', 'value'));
175 INSERT INTO config.bib_level_map (code, value) VALUES ('s', oils_i18n_gettext('s', 'Serial', 'cblvl', 'value'));
177 CREATE TABLE config.z3950_source (
178 name TEXT PRIMARY KEY,
179 label TEXT NOT NULL UNIQUE,
183 record_format TEXT NOT NULL DEFAULT 'FI',
184 transmission_format TEXT NOT NULL DEFAULT 'usmarc',
185 auth BOOL NOT NULL DEFAULT TRUE
187 INSERT INTO config.z3950_source (name, label, host, port, db, auth)
188 VALUES ('loc', oils_i18n_gettext('loc', 'Library of Congress', 'czs', 'label'), 'z3950.loc.gov', 7090, 'Voyager', FALSE);
189 INSERT INTO config.z3950_source (name, label, host, port, db, auth)
190 VALUES ('oclc', oils_i18n_gettext('loc', 'OCLC', 'czs', 'label'), 'zcat.oclc.org', 210, 'OLUCWorldCat', TRUE);
193 CREATE TABLE config.z3950_attr (
194 id SERIAL PRIMARY KEY,
195 source TEXT NOT NULL REFERENCES config.z3950_source (name) DEFERRABLE INITIALLY DEFERRED,
200 truncation INT NOT NULL DEFAULT 0,
201 CONSTRAINT z_code_format_once_per_source UNIQUE (code,format,source)
203 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
204 VALUES (1, 'loc','tcn', oils_i18n_gettext(1, 'Title Control Number', 'cza', 'label'), 12, 1);
205 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
206 VALUES (2, 'loc', 'isbn', oils_i18n_gettext(2, 'ISBN', 'cza', 'label'), 7, 6);
207 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
208 VALUES (3, 'loc', 'lccn', oils_i18n_gettext(3, 'LCCN', 'cza', 'label'), 9, 1);
209 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
210 VALUES (4, 'loc', 'author', oils_i18n_gettext(4, 'Author', 'cza', 'label'), 1003, 6);
211 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
212 VALUES (5, 'loc', 'title', oils_i18n_gettext(5, 'Title', 'cza', 'label'), 4, 6);
213 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
214 VALUES (6, 'loc', 'issn', oils_i18n_gettext(6, 'ISSN', 'cza', 'label'), 8, 1);
215 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
216 VALUES (7, 'loc', 'publisher', oils_i18n_gettext(7, 'Publisher', 'cza', 'label'), 1018, 6);
217 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
218 VALUES (8, 'loc', 'pubdate', oils_i18n_gettext(8, 'Publication Date', 'cza', 'label'), 31, 1);
219 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
220 VALUES (9, 'loc', 'item_type', oils_i18n_gettext(9, 'Item Type', 'cza', 'label'), 1001, 1);
222 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
223 VALUES (10, 'oclc', 'tcn', oils_i18n_gettext(10, 'Title Control Number', 'cza', 'label'), 12, 1);
224 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
225 VALUES (11, 'oclc', 'isbn', oils_i18n_gettext(11, 'ISBN', 'cza', 'label'), 7, 6);
226 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
227 VALUES (12, 'oclc', 'lccn', oils_i18n_gettext(12, 'LCCN', 'cza', 'label'), 9, 1);
228 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
229 VALUES (13, 'oclc', 'author', oils_i18n_gettext(13, 'Author', 'cza', 'label'), 1003, 6);
230 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
231 VALUES (14, 'oclc', 'title', oils_i18n_gettext(14, 'Title', 'cza', 'label'), 4, 6);
232 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
233 VALUES (15, 'oclc', 'issn', oils_i18n_gettext(15, 'ISSN', 'cza', 'label'), 8, 1);
234 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
235 VALUES (16, 'oclc', 'publisher', oils_i18n_gettext(16, 'Publisher', 'cza', 'label'), 1018, 6);
236 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
237 VALUES (17, 'oclc', 'pubdate', oils_i18n_gettext(17, 'Publication Date', 'cza', 'label'), 31, 1);
238 INSERT INTO config.z3950_attr (id, source, name, label, code, format)
239 VALUES (18, 'oclc', 'item_type', oils_i18n_gettext(18, 'Item Type', 'cza', 'label'), 1001, 1);
240 SELECT SETVAL('config.z3950_attr_id_seq'::TEXT, 100);
244 CREATE TABLE actor.org_lasso (
245 id SERIAL PRIMARY KEY,
249 CREATE TABLE actor.org_lasso_map (
250 id SERIAL PRIMARY KEY,
251 lasso INT NOT NULL REFERENCES actor.org_lasso (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
252 org_unit INT NOT NULL REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
254 CREATE UNIQUE INDEX ou_lasso_lasso_ou_idx ON actor.org_lasso_map (lasso, org_unit);
255 CREATE INDEX ou_lasso_org_unit_idx ON actor.org_lasso_map (org_unit);
258 CREATE TABLE permission.usr_object_perm_map (
259 id SERIAL PRIMARY KEY,
260 usr INT NOT NULL REFERENCES actor.usr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
261 perm INT NOT NULL REFERENCES permission.perm_list (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
262 object_type TEXT NOT NULL,
263 object_id TEXT NOT NULL,
264 grantable BOOL NOT NULL DEFAULT FALSE,
265 CONSTRAINT perm_usr_obj_once UNIQUE (usr,perm,object_type,object_id)
267 CREATE INDEX uopm_usr_idx ON permission.usr_object_perm_map (usr);
270 CREATE OR REPLACE FUNCTION permission.grp_ancestors ( INT ) RETURNS SETOF permission.grp_tree AS $$
272 FROM connectby('permission.grp_tree'::text,'parent'::text,'id'::text,'name'::text,$1::text,100,'.'::text)
273 AS t(keyid text, parent_keyid text, level int, branch text,pos int)
274 JOIN permission.grp_tree a ON a.id::text = t.keyid::text
276 CASE WHEN a.parent IS NULL
280 $$ LANGUAGE SQL STABLE;
282 CREATE OR REPLACE FUNCTION permission.usr_has_object_perm ( iuser INT, tperm TEXT, obj_type TEXT, obj_id TEXT, target_ou INT ) RETURNS BOOL AS $$
284 r_usr actor.usr%ROWTYPE;
288 SELECT * INTO r_usr FROM actor.usr WHERE id = iuser;
290 IF r_usr.active = FALSE THEN
294 IF r_usr.super_user = TRUE THEN
298 SELECT TRUE INTO res FROM permission.usr_object_perm_map WHERE usr = r_usr.id AND object_type = obj_type AND object_id = obj_id;
304 IF target_ou > -1 THEN
305 RETURN permission.usr_has_perm( iuser, tperm, target_ou);
313 CREATE OR REPLACE FUNCTION permission.usr_has_object_perm ( INT, TEXT, TEXT, TEXT ) RETURNS BOOL AS $$
314 SELECT permission.usr_has_object_perm( $1, $2, $3, $4, -1 );
317 CREATE OR REPLACE FUNCTION permission.grp_descendants ( INT ) RETURNS SETOF permission.grp_tree AS $$
319 FROM connectby('permission.grp_tree'::text,'id'::text,'parent'::text,'name'::text,$1::text,100,'.'::text)
320 AS t(keyid text, parent_keyid text, level int, branch text,pos int)
321 JOIN permission.grp_tree a ON a.id::text = t.keyid::text
322 ORDER BY CASE WHEN a.parent IS NULL THEN 0 ELSE 1 END, a.name;
323 $$ LANGUAGE SQL STABLE;
325 CREATE OR REPLACE FUNCTION permission.grp_full_path ( INT ) RETURNS SETOF permission.grp_tree AS $$
327 FROM permission.grp_ancestors($1)
330 FROM permission.grp_descendants($1);
331 $$ LANGUAGE SQL STABLE;
333 CREATE OR REPLACE FUNCTION permission.grp_combined_ancestors ( INT, INT ) RETURNS SETOF permission.grp_tree AS $$
335 FROM permission.grp_ancestors($1)
338 FROM permission.grp_ancestors($2);
339 $$ LANGUAGE SQL STABLE;
341 CREATE OR REPLACE FUNCTION permission.grp_common_ancestors ( INT, INT ) RETURNS SETOF permission.grp_tree AS $$
343 FROM permission.grp_ancestors($1)
346 FROM permission.grp_ancestors($2);
347 $$ LANGUAGE SQL STABLE;
349 CREATE OR REPLACE FUNCTION permission.grp_proximity ( INT, INT ) RETURNS INT AS $$
350 SELECT COUNT(id)::INT FROM (
351 SELECT id FROM permission.grp_combined_ancestors($1, $2)
353 SELECT id FROM permission.grp_common_ancestors($1, $2)
355 $$ LANGUAGE SQL STABLE;
357 INSERT INTO permission.usr_work_ou_map (usr, work_ou)
358 SELECT DISTINCT u.id, u.home_ou
360 JOIN permission.grp_tree g ON (u.profile = g.id)
361 LEFT JOIN permission.usr_work_ou_map m ON (u.id = m.usr AND u.home_ou = m.work_ou)
364 SELECT DISTINCT (permission.grp_descendants(grp)).id
365 FROM permission.grp_perm_map gpm JOIN permission.perm_list pl ON (pl.id = gpm.perm)
366 WHERE pl.code = 'STAFF_LOGIN'
369 /* Enable LIKE to use an index for database clusters with locales other than C or POSIX */
370 CREATE INDEX authority_full_rec_value_tpo_index ON authority.full_rec (value text_pattern_ops);
373 CREATE OR REPLACE FUNCTION public.naco_normalize( TEXT, TEXT ) RETURNS TEXT AS $func$
374 use Unicode::Normalize;
380 $txt =~ s/\pM+//go; # Remove diacritics
382 $txt =~ s/\xE6/AE/go; # Convert ae digraph
383 $txt =~ s/\x{153}/OE/go;# Convert oe digraph
384 $txt =~ s/\xFE/TH/go; # Convert Icelandic thorn
386 $txt =~ tr/\x{2070}\x{2071}\x{2072}\x{2073}\x{2074}\x{2075}\x{2076}\x{2077}\x{2078}\x{2079}\x{207A}\x{207B}/0123456789+-/;# Convert superscript numbers
387 $txt =~ tr/\x{2080}\x{2081}\x{2082}\x{2083}\x{2084}\x{2085}\x{2086}\x{2087}\x{2088}\x{2089}\x{208A}\x{208B}/0123456889+-/;# Convert subscript numbers
389 $txt =~ tr/\x{0251}\x{03B1}\x{03B2}\x{0262}\x{03B3}/AABGG/; # Convert Latin and Greek
390 $txt =~ tr/\x{2113}\xF0\!\"\(\)\-\{\}\<\>\;\:\.\?\xA1\xBF\/\\\@\*\%\=\xB1\+\xAE\xA9\x{2117}\$\xA3\x{FFE1}\xB0\^\_\~\`/LD /; # Convert Misc
391 $txt =~ tr/\'\[\]\|//d; # Remove Misc
393 if ($sf && $sf =~ /^a/o) {
394 my $commapos = index($txt,',');
395 if ($commapos > -1) {
396 if ($commapos != length($txt) - 1) {
397 my @list = split /,/, $txt;
398 my $first = shift @list;
399 $txt = $first . ',' . join(' ', @list);
408 $txt =~ s/\s+/ /go; # Compress multiple spaces
409 $txt =~ s/^\s+//o; # Remove leading space
410 $txt =~ s/\s+$//o; # Remove trailing space
413 $func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
415 CREATE OR REPLACE FUNCTION public.naco_normalize( TEXT ) RETURNS TEXT AS $func$
416 SELECT public.naco_normalize($1,'');
417 $func$ LANGUAGE 'sql' STRICT IMMUTABLE;
419 CREATE OR REPLACE FUNCTION public.normalize_space( TEXT ) RETURNS TEXT AS $$
420 SELECT regexp_replace(regexp_replace(regexp_replace($1, E'\\n', ' ', 'g'), E'(?:^\\s+)|(\\s+$)', '', 'g'), E'\\s+', ' ', 'g');
423 CREATE OR REPLACE FUNCTION public.lowercase( TEXT ) RETURNS TEXT AS $$
427 CREATE OR REPLACE FUNCTION public.uppercase( TEXT ) RETURNS TEXT AS $$
431 CREATE OR REPLACE FUNCTION public.remove_diacritics( TEXT ) RETURNS TEXT AS $$
432 use Unicode::Normalize;
440 CREATE OR REPLACE FUNCTION public.entityize( TEXT ) RETURNS TEXT AS $$
441 use Unicode::Normalize;
444 $x =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
450 CREATE OR REPLACE FUNCTION public.call_number_dewey( TEXT ) RETURNS TEXT AS $$
453 $txt =~ s/[\[\]\{\}\(\)`'"#<>\*\?\-\+\$\\]+//og;
455 if ($txt =~ /(\d{3}(?:\.\d+)?)/o) {
458 return (split /\s+/, $txt)[0];
460 $$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
463 CREATE OR REPLACE FUNCTION actor.org_unit_descendants ( INT ) RETURNS SETOF actor.org_unit AS $$
465 FROM connectby('actor.org_unit'::text,'id'::text,'parent_ou'::text,'name'::text,$1::text,100,'.'::text)
466 AS t(keyid text, parent_keyid text, level int, branch text,pos int)
467 JOIN actor.org_unit a ON a.id::text = t.keyid::text
468 ORDER BY CASE WHEN a.parent_ou IS NULL THEN 0 ELSE 1 END, a.name;
469 $$ LANGUAGE SQL STABLE;
471 CREATE OR REPLACE FUNCTION actor.org_unit_ancestors ( INT ) RETURNS SETOF actor.org_unit AS $$
473 FROM connectby('actor.org_unit'::text,'parent_ou'::text,'id'::text,'name'::text,$1::text,100,'.'::text)
474 AS t(keyid text, parent_keyid text, level int, branch text,pos int)
475 JOIN actor.org_unit a ON a.id::text = t.keyid::text
476 ORDER BY CASE WHEN a.parent_ou IS NULL THEN 0 ELSE 1 END, a.name;
477 $$ LANGUAGE SQL STABLE;
479 CREATE OR REPLACE FUNCTION actor.org_unit_descendants ( INT,INT ) RETURNS SETOF actor.org_unit AS $$
481 FROM connectby('actor.org_unit'::text,'id'::text,'parent_ou'::text,'name'::text,
483 FROM actor.org_unit_ancestors($1) x
484 JOIN actor.org_unit_type y ON x.ou_type = y.id
485 WHERE y.depth = $2)::text
487 AS t(keyid text, parent_keyid text, level int, branch text,pos int)
488 JOIN actor.org_unit a ON a.id::text = t.keyid::text
489 ORDER BY CASE WHEN a.parent_ou IS NULL THEN 0 ELSE 1 END, a.name;
490 $$ LANGUAGE SQL STABLE;
492 ALTER TABLE metabib.rec_descriptor ADD COLUMN date1 TEXT;
493 ALTER TABLE metabib.rec_descriptor ADD COLUMN date2 TEXT;
495 UPDATE metabib.rec_descriptor
496 SET date1 = regexp_replace(substring(metabib.full_rec.value,8,4),E'\\D','0','g'),
497 date2 = regexp_replace(substring(metabib.full_rec.value,12,4),E'\\D','9','g')
498 FROM metabib.full_rec
499 WHERE metabib.full_rec.record = metabib.rec_descriptor.record AND metabib.full_rec.tag = '008';
502 ALTER TABLE money.credit_card_payment ALTER cc_type DROP NOT NULL;
503 ALTER TABLE money.credit_card_payment ALTER cc_number DROP NOT NULL;
504 ALTER TABLE money.credit_card_payment ALTER expire_month DROP NOT NULL;
505 ALTER TABLE money.credit_card_payment ALTER expire_year DROP NOT NULL;
506 ALTER TABLE money.credit_card_payment ALTER approval_code DROP NOT NULL;
509 ALTER TABLE asset.copy_location ADD CONSTRAINT acl_name_once_per_lib UNIQUE (name, owning_lib);
510 ALTER TABLE asset.copy ALTER price DROP NOT NULL;
511 ALTER TABLE asset.copy ALTER price DROP DEFAULT;
513 CREATE OR REPLACE FUNCTION asset.merge_record_assets( target_record BIGINT, source_record BIGINT ) RETURNS INT AS $func$
516 source_cn asset.call_number%ROWTYPE;
517 target_cn asset.call_number%ROWTYPE;
519 FOR source_cn IN SELECT * FROM asset.call_number WHERE record = source_record LOOP
521 SELECT INTO target_cn *
522 FROM asset.call_number
523 WHERE label = source_cn.label
524 AND owning_lib = source_cn.owning_lib
525 AND record = target_record;
529 SET call_number = target_cn.id
530 WHERE call_number = source_cn.id;
531 DELETE FROM asset.call_number
532 WHERE id = target_cn.id;
534 UPDATE asset.call_number
535 SET record = target_record
536 WHERE id = source_cn.id;
539 moved_cns := moved_cns + 1;
544 $func$ LANGUAGE plpgsql;
547 ALTER TABLE money.billable_xact ADD COLUMN unrecovered BOOL;
549 CREATE OR REPLACE VIEW money.billable_xact_summary AS
554 credit.amount AS total_paid,
555 credit.payment_ts AS last_payment_ts,
556 credit.note AS last_payment_note,
557 credit.payment_type AS last_payment_type,
558 debit.amount AS total_owed,
559 debit.billing_ts AS last_billing_ts,
560 debit.note AS last_billing_note,
561 debit.billing_type AS last_billing_type,
562 COALESCE(debit.amount, 0::numeric) - COALESCE(credit.amount, 0::numeric) AS balance_owed,
563 p.relname AS xact_type
564 FROM money.billable_xact xact
565 JOIN pg_class p ON xact.tableoid = p.oid
568 sum(billing.amount) AS amount,
569 max(billing.billing_ts) AS billing_ts,
570 last(billing.note) AS note,
571 last(billing.billing_type) AS billing_type
573 WHERE billing.voided IS FALSE
574 GROUP BY billing.xact
575 ) debit ON xact.id = debit.xact
577 SELECT payment_view.xact,
578 sum(payment_view.amount) AS amount,
579 max(payment_view.payment_ts) AS payment_ts,
580 last(payment_view.note) AS note,
581 last(payment_view.payment_type) AS payment_type
582 FROM money.payment_view
583 WHERE payment_view.voided IS FALSE
584 GROUP BY payment_view.xact
585 ) credit ON xact.id = credit.xact
586 ORDER BY debit.billing_ts, credit.payment_ts;
588 ALTER TABLE action.circulation ADD COLUMN create_time TIMESTAMP WITH TIME ZONE DEFAULT NOW();
591 CREATE TABLE action.aged_circulation (
593 usr_home_ou INT NOT NULL,
594 usr_profile INT NOT NULL,
596 copy_call_number INT NOT NULL,
597 copy_location INT NOT NULL,
598 copy_owning_lib INT NOT NULL,
599 copy_circ_lib INT NOT NULL,
600 copy_bib_record BIGINT NOT NULL,
601 LIKE action.circulation
604 ALTER TABLE action.aged_circulation ADD PRIMARY KEY (id);
605 ALTER TABLE action.aged_circulation DROP COLUMN usr;
606 CREATE INDEX aged_circ_circ_lib_idx ON "action".aged_circulation (circ_lib);
607 CREATE INDEX aged_circ_start_idx ON "action".aged_circulation (xact_start);
608 CREATE INDEX aged_circ_copy_circ_lib_idx ON "action".aged_circulation (copy_circ_lib);
609 CREATE INDEX aged_circ_copy_owning_lib_idx ON "action".aged_circulation (copy_owning_lib);
610 CREATE INDEX aged_circ_copy_location_idx ON "action".aged_circulation (copy_location);
612 CREATE OR REPLACE VIEW action.all_circulation AS
613 SELECT id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
614 copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
615 circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
616 stop_fines_time, checkin_time, create_time, duration, fine_interval, recuring_fine,
617 max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recuring_fine_rule,
618 max_fine_rule, stop_fines
619 FROM action.aged_circulation
621 SELECT circ.id,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,
622 cp.call_number AS copy_call_number, cp.location AS copy_location, cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib,
623 cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish, circ.target_copy, circ.circ_lib, circ.circ_staff, circ.checkin_staff,
624 circ.checkin_lib, circ.renewal_remaining, circ.due_date, circ.stop_fines_time, circ.checkin_time, circ.create_time, circ.duration,
625 circ.fine_interval, circ.recuring_fine, circ.max_fine, circ.phone_renewal, circ.desk_renewal, circ.opac_renewal, circ.duration_rule,
626 circ.recuring_fine_rule, circ.max_fine_rule, circ.stop_fines
627 FROM action.circulation circ
628 JOIN asset.copy cp ON (circ.target_copy = cp.id)
629 JOIN asset.call_number cn ON (cp.call_number = cn.id)
630 JOIN actor.usr p ON (circ.usr = p.id)
631 LEFT JOIN actor.usr_address a ON (p.mailing_address = a.id)
632 LEFT JOIN actor.usr_address b ON (p.billing_address = a.id);
634 CREATE OR REPLACE FUNCTION action.age_circ_on_delete () RETURNS TRIGGER AS $$
636 INSERT INTO action.aged_circulation
637 (id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
638 copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
639 circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
640 stop_fines_time, checkin_time, create_time, duration, fine_interval, recuring_fine,
641 max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recuring_fine_rule,
642 max_fine_rule, stop_fines)
644 id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
645 copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
646 circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
647 stop_fines_time, checkin_time, create_time, duration, fine_interval, recuring_fine,
648 max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recuring_fine_rule,
649 max_fine_rule, stop_fines
650 FROM action.all_circulation WHERE id = OLD.id;
654 $$ LANGUAGE 'plpgsql';
656 CREATE TRIGGER action_circulation_aging_tgr
657 BEFORE DELETE ON action.circulation
659 EXECUTE PROCEDURE action.age_circ_on_delete ();
661 CREATE OR REPLACE VIEW extend_reporter.full_circ_count AS
662 SELECT cp.id, COALESCE(sum(c.circ_count), 0::bigint) + COALESCE(count(circ.id), 0::bigint) AS circ_count
664 LEFT JOIN extend_reporter.legacy_circ_count c USING (id)
665 LEFT JOIN "action".all_circulation circ ON circ.target_copy = cp.id
670 CREATE OR REPLACE FUNCTION search.staged_fts (
674 param_searches TEXT, -- JSON hash, to be turned into a resultset via search.parse_search_args
675 param_statuses INT[],
676 param_locations INT[],
677 param_audience TEXT[],
678 param_language TEXT[],
679 param_lit_form TEXT[],
682 param_vformats TEXT[],
683 param_bib_level TEXT[],
687 param_between TEXT[],
688 param_pref_lang TEXT,
689 param_pref_lang_multiplier REAL,
691 param_sort_desc BOOL,
698 ) RETURNS SETOF search.search_result AS $func$
701 current_res search.search_result%ROWTYPE;
702 query_part search.search_args%ROWTYPE;
703 phrase_query_part search.search_args%ROWTYPE;
708 rank_adjust search.relevance_adjustment%ROWTYPE;
713 ranks TEXT[] := '{}';
714 query_table_alias TEXT;
715 from_alias_array TEXT[] := '{}';
716 used_ranks TEXT[] := '{}';
719 search_org_list INT[];
720 select_clause TEXT := 'SELECT';
721 from_clause TEXT := ' FROM metabib.metarecord_source_map m JOIN metabib.rec_descriptor mrd ON (m.source = mrd.record) ';
722 where_clause TEXT := ' WHERE 1=1 ';
723 mrd_used BOOL := FALSE;
724 sort_desc BOOL := FALSE;
727 core_cursor REFCURSOR;
729 vis_limit_query TEXT;
730 inner_where_clause TEXT;
732 total_count INT := 0;
733 check_count INT := 0;
734 deleted_count INT := 0;
735 visible_count INT := 0;
736 excluded_count INT := 0;
740 core_rel_limit := COALESCE( param_rel_limit, 25000 );
741 core_chk_limit := COALESCE( param_chk_limit, 1000 );
742 core_skip_chk := COALESCE( param_skip_chk, 1 );
745 select_clause := select_clause || ' m.metarecord as id, array_accum(distinct m.source) as records,';
747 select_clause := select_clause || ' m.source as id, array_accum(distinct m.source) as records,';
750 -- first we need to construct the base query
751 FOR query_part IN SELECT * FROM search.parse_search_args(param_searches) WHERE term_type = 'fts_query' LOOP
753 inner_where_clause := 'index_vector @@ ' || query_part.term;
755 IF query_part.field_name IS NOT NULL THEN
757 SELECT id INTO mb_field
758 FROM config.metabib_field
759 WHERE field_class = query_part.field_class
760 AND name = query_part.field_name;
763 inner_where_clause := inner_where_clause ||
764 ' AND ' || 'field = ' || mb_field;
769 -- moving on to the rank ...
770 SELECT * INTO query_part
771 FROM search.parse_search_args(param_searches)
772 WHERE term_type = 'fts_rank'
773 AND table_alias = query_part.table_alias;
775 current_rank := query_part.term || ' * ' || query_part.table_alias || '_weight.weight';
777 IF query_part.field_name IS NOT NULL THEN
779 SELECT array_accum(distinct id) INTO mb_field_list
780 FROM config.metabib_field
781 WHERE field_class = query_part.field_class
782 AND name = query_part.field_name;
786 SELECT array_accum(distinct id) INTO mb_field_list
787 FROM config.metabib_field
788 WHERE field_class = query_part.field_class;
792 FOR rank_adjust IN SELECT * FROM search.relevance_adjustment WHERE active AND field IN ( SELECT * FROM search.explode_array( mb_field_list ) ) LOOP
794 IF NOT rank_adjust.bump_type = ANY (used_ranks) THEN
796 IF rank_adjust.bump_type = 'first_word' THEN
797 SELECT term INTO tmp_text
798 FROM search.parse_search_args(param_searches)
799 WHERE table_alias = query_part.table_alias AND term_type = 'word'
803 tmp_text := query_part.table_alias || '.value ILIKE ' || quote_literal( tmp_text || '%' );
805 ELSIF rank_adjust.bump_type = 'word_order' THEN
806 SELECT array_to_string( array_accum( term ), '%' ) INTO tmp_text
807 FROM search.parse_search_args(param_searches)
808 WHERE table_alias = query_part.table_alias AND term_type = 'word';
810 tmp_text := query_part.table_alias || '.value ILIKE ' || quote_literal( '%' || tmp_text || '%' );
812 ELSIF rank_adjust.bump_type = 'full_match' THEN
813 SELECT array_to_string( array_accum( term ), E'\\s+' ) INTO tmp_text
814 FROM search.parse_search_args(param_searches)
815 WHERE table_alias = query_part.table_alias AND term_type = 'word';
817 tmp_text := query_part.table_alias || '.value ~ ' || quote_literal( '^' || tmp_text || E'\\W*$' );
822 IF tmp_text IS NOT NULL THEN
823 current_rank := current_rank || ' * ( CASE WHEN ' || tmp_text ||
824 ' THEN ' || rank_adjust.multiplier || '::REAL ELSE 1.0 END )';
827 used_ranks := array_append( used_ranks, rank_adjust.bump_type );
833 ranks := array_append( ranks, current_rank );
836 FOR phrase_query_part IN
838 FROM search.parse_search_args(param_searches)
839 WHERE term_type = 'phrase'
840 AND table_alias = query_part.table_alias LOOP
842 tmp_text := replace( phrase_query_part.term, '*', E'\\*' );
843 tmp_text := replace( tmp_text, '?', E'\\?' );
844 tmp_text := replace( tmp_text, '+', E'\\+' );
845 tmp_text := replace( tmp_text, '|', E'\\|' );
846 tmp_text := replace( tmp_text, '(', E'\\(' );
847 tmp_text := replace( tmp_text, ')', E'\\)' );
848 tmp_text := replace( tmp_text, '[', E'\\[' );
849 tmp_text := replace( tmp_text, ']', E'\\]' );
851 inner_where_clause := inner_where_clause || ' AND ' || 'value ~* ' || quote_literal( E'(^|\\W+)' || regexp_replace(tmp_text, E'\\s+',E'\\\\s+','g') || E'(\\W+|\$)' );
855 query_table := search.pick_table(query_part.field_class);
857 from_clause := from_clause ||
858 ' JOIN ( SELECT * FROM ' || query_table || ' WHERE ' || inner_where_clause ||
859 CASE WHEN core_rel_limit > 0 THEN ' LIMIT ' || core_rel_limit::TEXT ELSE '' END || ' ) AS ' || query_part.table_alias ||
860 ' ON ( m.source = ' || query_part.table_alias || '.source )' ||
861 ' JOIN config.metabib_field AS ' || query_part.table_alias || '_weight' ||
862 ' ON ( ' || query_part.table_alias || '.field = ' || query_part.table_alias || '_weight.id AND ' || query_part.table_alias || '_weight.search_field)';
864 from_alias_array := array_append(from_alias_array, query_part.table_alias);
868 IF param_pref_lang IS NOT NULL AND param_pref_lang_multiplier IS NOT NULL THEN
869 current_rank := ' CASE WHEN mrd.item_lang = ' || quote_literal( param_pref_lang ) ||
870 ' THEN ' || param_pref_lang_multiplier || '::REAL ELSE 1.0 END ';
872 -- ranks := array_append( ranks, current_rank );
875 current_rank := ' AVG( ( (' || array_to_string( ranks, ') + (' ) || ') ) * ' || current_rank || ' ) ';
876 select_clause := select_clause || current_rank || ' AS rel,';
878 sort_desc = param_sort_desc;
880 IF param_sort = 'pubdate' THEN
882 tmp_text := '999999';
883 IF param_sort_desc THEN tmp_text := '0'; END IF;
885 current_rank := $$ COALESCE( FIRST(NULLIF(REGEXP_REPLACE(mrd.date1, E'\\D+', '9', 'g'),'')), $$ || quote_literal(tmp_text) || $$ )::INT $$;
887 ELSIF param_sort = 'title' THEN
889 tmp_text := 'zzzzzz';
890 IF param_sort_desc THEN tmp_text := ' '; END IF;
894 SELECT LTRIM(SUBSTR( frt.value, COALESCE(SUBSTRING(frt.ind2 FROM E'\\d+'),'0')::INT + 1 ))
895 FROM metabib.full_rec frt
896 WHERE frt.record = m.source
898 AND frt.subfield = 'a'
900 )),$$ || quote_literal(tmp_text) || $$))
903 ELSIF param_sort = 'author' THEN
905 tmp_text := 'zzzzzz';
906 IF param_sort_desc THEN tmp_text := ' '; END IF;
910 SELECT LTRIM(fra.value)
911 FROM metabib.full_rec fra
912 WHERE fra.record = m.source
913 AND fra.tag LIKE '1%'
914 AND fra.subfield = 'a'
915 ORDER BY fra.tag::text::int
917 )),$$ || quote_literal(tmp_text) || $$))
920 ELSIF param_sort = 'create_date' THEN
921 current_rank := $$( FIRST (( SELECT create_date FROM biblio.record_entry rbr WHERE rbr.id = m.source)) )$$;
922 ELSIF param_sort = 'edit_date' THEN
923 current_rank := $$( FIRST (( SELECT edit_date FROM biblio.record_entry rbr WHERE rbr.id = m.source)) )$$;
925 sort_desc := NOT COALESCE(param_sort_desc, FALSE);
928 select_clause := select_clause || current_rank || ' AS rank';
930 -- now add the other qualifiers
931 IF param_audience IS NOT NULL AND array_upper(param_audience, 1) > 0 THEN
932 where_clause = where_clause || $$ AND mrd.audience IN ('$$ || array_to_string(param_audience, $$','$$) || $$') $$;
935 IF param_language IS NOT NULL AND array_upper(param_language, 1) > 0 THEN
936 where_clause = where_clause || $$ AND mrd.item_lang IN ('$$ || array_to_string(param_language, $$','$$) || $$') $$;
939 IF param_lit_form IS NOT NULL AND array_upper(param_lit_form, 1) > 0 THEN
940 where_clause = where_clause || $$ AND mrd.lit_form IN ('$$ || array_to_string(param_lit_form, $$','$$) || $$') $$;
943 IF param_types IS NOT NULL AND array_upper(param_types, 1) > 0 THEN
944 where_clause = where_clause || $$ AND mrd.item_type IN ('$$ || array_to_string(param_types, $$','$$) || $$') $$;
947 IF param_forms IS NOT NULL AND array_upper(param_forms, 1) > 0 THEN
948 where_clause = where_clause || $$ AND mrd.item_form IN ('$$ || array_to_string(param_forms, $$','$$) || $$') $$;
951 IF param_vformats IS NOT NULL AND array_upper(param_vformats, 1) > 0 THEN
952 where_clause = where_clause || $$ AND mrd.vr_format IN ('$$ || array_to_string(param_vformats, $$','$$) || $$') $$;
955 IF param_bib_level IS NOT NULL AND array_upper(param_bib_level, 1) > 0 THEN
956 where_clause = where_clause || $$ AND mrd.bib_level IN ('$$ || array_to_string(param_bib_level, $$','$$) || $$') $$;
959 IF param_before IS NOT NULL AND param_before <> '' THEN
960 where_clause = where_clause || $$ AND mrd.date1 <= $$ || quote_literal(param_before) || ' ';
963 IF param_after IS NOT NULL AND param_after <> '' THEN
964 where_clause = where_clause || $$ AND mrd.date1 >= $$ || quote_literal(param_after) || ' ';
967 IF param_during IS NOT NULL AND param_during <> '' THEN
968 where_clause = where_clause || $$ AND $$ || quote_literal(param_during) || $$ BETWEEN mrd.date1 AND mrd.date2 $$;
971 IF param_between IS NOT NULL AND array_upper(param_between, 1) > 1 THEN
972 where_clause = where_clause || $$ AND mrd.date1 BETWEEN '$$ || array_to_string(param_between, $$' AND '$$) || $$' $$;
975 core_rel_query := select_clause || from_clause || where_clause ||
976 ' GROUP BY 1 ORDER BY 4' || CASE WHEN sort_desc THEN ' DESC' ELSE ' ASC' END || ';';
977 --RAISE NOTICE 'Base Query: %', core_rel_query;
979 IF param_search_ou > 0 THEN
980 IF param_depth IS NOT NULL THEN
981 SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou, param_depth );
983 SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou );
985 ELSIF param_search_ou < 0 THEN
986 SELECT array_accum(distinct org_unit) INTO search_org_list FROM actor.org_lasso_map WHERE lasso = -param_search_ou;
987 ELSIF param_search_ou = 0 THEN
988 -- reserved for user lassos (ou_buckets/type='lasso') with ID passed in depth ... hack? sure.
991 OPEN core_cursor FOR EXECUTE core_rel_query;
995 FETCH core_cursor INTO core_result;
999 IF total_count % 1000 = 0 THEN
1000 -- RAISE NOTICE ' % total, % checked so far ... ', total_count, check_count;
1003 IF core_chk_limit > 0 AND total_count - core_skip_chk + 1 >= core_chk_limit THEN
1004 total_count := total_count + 1;
1008 total_count := total_count + 1;
1010 CONTINUE WHEN param_skip_chk IS NOT NULL and total_count < param_skip_chk;
1012 check_count := check_count + 1;
1014 PERFORM 1 FROM biblio.record_entry b WHERE NOT b.deleted AND b.id IN ( SELECT * FROM search.explode_array( core_result.records ) );
1016 -- RAISE NOTICE ' % were all deleted ... ', core_result.records;
1017 deleted_count := deleted_count + 1;
1022 FROM biblio.record_entry b
1023 JOIN config.bib_source s ON (b.source = s.id)
1024 WHERE s.transcendant
1025 AND b.id IN ( SELECT * FROM search.explode_array( core_result.records ) );
1028 -- RAISE NOTICE ' % were all transcendant ... ', core_result.records;
1029 visible_count := visible_count + 1;
1031 current_res.id = core_result.id;
1032 current_res.rel = core_result.rel;
1036 SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
1040 current_res.record = core_result.records[1];
1042 current_res.record = NULL;
1045 RETURN NEXT current_res;
1050 IF param_statuses IS NOT NULL AND array_upper(param_statuses, 1) > 0 THEN
1053 FROM asset.call_number cn
1054 JOIN asset.copy cp ON (cp.call_number = cn.id)
1055 WHERE NOT cn.deleted
1057 AND cp.status IN ( SELECT * FROM search.explode_array( param_statuses ) )
1058 AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
1059 AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
1063 -- RAISE NOTICE ' % were all status-excluded ... ', core_result.records;
1064 excluded_count := excluded_count + 1;
1070 IF param_locations IS NOT NULL AND array_upper(param_locations, 1) > 0 THEN
1073 FROM asset.call_number cn
1074 JOIN asset.copy cp ON (cp.call_number = cn.id)
1075 WHERE NOT cn.deleted
1077 AND cp.location IN ( SELECT * FROM search.explode_array( param_locations ) )
1078 AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
1079 AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
1083 -- RAISE NOTICE ' % were all copy_location-excluded ... ', core_result.records;
1084 excluded_count := excluded_count + 1;
1090 IF staff IS NULL OR NOT staff THEN
1093 FROM asset.call_number cn
1094 JOIN asset.copy cp ON (cp.call_number = cn.id)
1095 JOIN actor.org_unit a ON (cp.circ_lib = a.id)
1096 JOIN asset.copy_location cl ON (cp.location = cl.id)
1097 JOIN config.copy_status cs ON (cp.status = cs.id)
1098 WHERE NOT cn.deleted
1104 AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
1105 AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
1109 -- RAISE NOTICE ' % were all visibility-excluded ... ', core_result.records;
1110 excluded_count := excluded_count + 1;
1117 FROM asset.call_number cn
1118 JOIN asset.copy cp ON (cp.call_number = cn.id)
1119 JOIN actor.org_unit a ON (cp.circ_lib = a.id)
1120 JOIN asset.copy_location cl ON (cp.location = cl.id)
1121 WHERE NOT cn.deleted
1123 AND cp.circ_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
1124 AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
1130 FROM asset.call_number cn
1131 WHERE cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
1135 -- RAISE NOTICE ' % were all visibility-excluded ... ', core_result.records;
1136 excluded_count := excluded_count + 1;
1144 visible_count := visible_count + 1;
1146 current_res.id = core_result.id;
1147 current_res.rel = core_result.rel;
1151 SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
1155 current_res.record = core_result.records[1];
1157 current_res.record = NULL;
1160 RETURN NEXT current_res;
1162 IF visible_count % 1000 = 0 THEN
1163 -- RAISE NOTICE ' % visible so far ... ', visible_count;
1168 current_res.id = NULL;
1169 current_res.rel = NULL;
1170 current_res.record = NULL;
1171 current_res.total = total_count;
1172 current_res.checked = check_count;
1173 current_res.deleted = deleted_count;
1174 current_res.visible = visible_count;
1175 current_res.excluded = excluded_count;
1179 RETURN NEXT current_res;
1182 $func$ LANGUAGE PLPGSQL;
1184 -- This index, right here, is the reason for this change.
1185 DROP INDEX IF EXISTS metabib.metabib_full_rec_value_idx;
1188 -- Move the table out of the way ...
1189 ALTER TABLE metabib.full_rec RENAME TO real_full_rec;
1191 -- ... and let the trigger management functions know about the change ...
1192 CREATE OR REPLACE FUNCTION reporter.disable_materialized_simple_record_trigger () RETURNS VOID AS $$
1193 DROP TRIGGER zzz_update_materialized_simple_record_tgr ON metabib.real_full_rec;
1196 CREATE OR REPLACE FUNCTION reporter.enable_materialized_simple_record_trigger () RETURNS VOID AS $$
1198 TRUNCATE TABLE reporter.materialized_simple_record;
1200 INSERT INTO reporter.materialized_simple_record
1201 (id,fingerprint,quality,tcn_source,tcn_value,title,author,publisher,pubdate,isbn,issn)
1202 SELECT DISTINCT ON (id) * FROM reporter.old_super_simple_record;
1204 CREATE TRIGGER zzz_update_materialized_simple_record_tgr
1205 AFTER INSERT OR UPDATE OR DELETE ON metabib.real_full_rec
1206 FOR EACH ROW EXECUTE PROCEDURE reporter.simple_rec_sync();
1210 -- ... replace the table with a suitable view, which applies the index contstraint we'll use ...
1211 CREATE OR REPLACE VIEW metabib.full_rec AS
1218 SUBSTRING(value,1,1024) AS value,
1220 FROM metabib.real_full_rec;
1222 -- ... now some rules to transform DML against the view into DML against the underlying table ...
1223 CREATE OR REPLACE RULE metabib_full_rec_insert_rule
1224 AS ON INSERT TO metabib.full_rec
1226 INSERT INTO metabib.real_full_rec VALUES (
1227 COALESCE(NEW.id, NEXTVAL('metabib.full_rec_id_seq'::REGCLASS)),
1237 CREATE OR REPLACE RULE metabib_full_rec_update_rule
1238 AS ON UPDATE TO metabib.full_rec
1240 UPDATE metabib.real_full_rec SET
1242 record = NEW.record,
1246 subfield = NEW.subfield,
1248 index_vector = NEW.index_vector
1251 CREATE OR REPLACE RULE metabib_full_rec_delete_rule
1252 AS ON DELETE TO metabib.full_rec
1254 DELETE FROM metabib.real_full_rec WHERE id = OLD.id;
1256 -- ... and last, but not least, create a fore-shortened index on the value column.
1257 CREATE INDEX metabib_full_rec_value_idx ON metabib.real_full_rec (substring(value,1,1024));
1260 CREATE OR REPLACE FUNCTION explode_array(anyarray) RETURNS SETOF anyelement AS $BODY$
1261 SELECT ($1)[s] FROM generate_series(1, array_upper($1, 1)) AS s;
1263 LANGUAGE 'sql' IMMUTABLE;
1265 -- NOTE: current config.item_type should get sip2_media_type and magnetic_media columns
1267 -- New table needed to handle circ modifiers inside the DB. Will still require
1268 -- central admin. The circ_modifier column on asset.copy will become an fkey to this table.
1269 CREATE TABLE config.circ_modifier (
1270 code TEXT PRIMARY KEY,
1271 name TEXT UNIQUE NOT NULL,
1272 description TEXT NOT NULL,
1273 sip2_media_type TEXT NOT NULL,
1274 magnetic_media BOOL NOT NULL DEFAULT TRUE
1277 UPDATE asset.copy SET circ_modifier = UPPER(circ_modifier) WHERE circ_modifier IS NOT NULL AND circ_modifier <> '';
1278 UPDATE asset.copy SET circ_modifier = NULL WHERE circ_modifier = '';
1280 INSERT INTO config.circ_modifier (code, name, description, sip2_media_type )
1282 UPPER(circ_modifier),
1283 UPPER(circ_modifier),
1284 LOWER(circ_modifier),
1287 WHERE circ_modifier IS NOT NULL;
1289 -- add an fkey pointing to the new circ mod table
1290 ALTER TABLE asset.copy ADD CONSTRAINT circ_mod_fkey FOREIGN KEY (circ_modifier) REFERENCES config.circ_modifier (code) ON UPDATE CASCADE ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
1292 -- config table to hold the vr_format names
1293 CREATE TABLE config.videorecording_format_map (
1294 code TEXT PRIMARY KEY,
1298 INSERT INTO config.videorecording_format_map VALUES ('a','Beta');
1299 INSERT INTO config.videorecording_format_map VALUES ('b','VHS');
1300 INSERT INTO config.videorecording_format_map VALUES ('c','U-matic');
1301 INSERT INTO config.videorecording_format_map VALUES ('d','EIAJ');
1302 INSERT INTO config.videorecording_format_map VALUES ('e','Type C');
1303 INSERT INTO config.videorecording_format_map VALUES ('f','Quadruplex');
1304 INSERT INTO config.videorecording_format_map VALUES ('g','Laserdisc');
1305 INSERT INTO config.videorecording_format_map VALUES ('h','CED');
1306 INSERT INTO config.videorecording_format_map VALUES ('i','Betacam');
1307 INSERT INTO config.videorecording_format_map VALUES ('j','Betacam SP');
1308 INSERT INTO config.videorecording_format_map VALUES ('k','Super-VHS');
1309 INSERT INTO config.videorecording_format_map VALUES ('m','M-II');
1310 INSERT INTO config.videorecording_format_map VALUES ('o','D-2');
1311 INSERT INTO config.videorecording_format_map VALUES ('p','8 mm.');
1312 INSERT INTO config.videorecording_format_map VALUES ('q','Hi-8 mm.');
1313 INSERT INTO config.videorecording_format_map VALUES ('u','Unknown');
1314 INSERT INTO config.videorecording_format_map VALUES ('v','DVD');
1315 INSERT INTO config.videorecording_format_map VALUES ('z','Other');
1317 CREATE TABLE config.circ_matrix_matchpoint (
1318 id SERIAL PRIMARY KEY,
1319 active BOOL NOT NULL DEFAULT TRUE,
1320 org_unit INT NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
1321 grp INT NOT NULL REFERENCES permission.grp_tree (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top applicable group from the group tree; will need descendents and prox functions for filtering
1322 circ_modifier TEXT REFERENCES config.circ_modifier (code) DEFERRABLE INITIALLY DEFERRED,
1323 marc_type TEXT REFERENCES config.item_type_map (code) DEFERRABLE INITIALLY DEFERRED,
1324 marc_form TEXT REFERENCES config.item_form_map (code) DEFERRABLE INITIALLY DEFERRED,
1325 marc_vr_format TEXT REFERENCES config.videorecording_format_map (code) DEFERRABLE INITIALLY DEFERRED,
1328 usr_age_lower_bound INTERVAL,
1329 usr_age_upper_bound INTERVAL,
1330 CONSTRAINT ep_once_per_grp_loc_mod_marc UNIQUE (grp, org_unit, circ_modifier, marc_type, marc_form, marc_vr_format, ref_flag, usr_age_lower_bound, usr_age_upper_bound, is_renewal)
1332 INSERT INTO config.circ_matrix_matchpoint (org_unit,grp) VALUES (1,1);
1335 -- Tests to determine if circ can occur for this item at this location for this patron
1336 CREATE TABLE config.circ_matrix_test (
1337 matchpoint INT PRIMARY KEY NOT NULL REFERENCES config.circ_matrix_matchpoint (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
1338 circulate BOOL NOT NULL DEFAULT TRUE, -- Hard "can't circ" flag requiring an override
1339 max_items_out INT, -- Total current active circulations must be less than this, NULL means skip (always pass)
1340 max_overdue INT, -- Total overdue active circulations must be less than this, NULL means skip (always pass)
1341 max_fines NUMERIC(8,2), -- Total fines owed must be less than this, NULL means skip (always pass)
1342 org_depth INT, -- Set to the top OU for the max-out applicability range
1343 script_test TEXT -- filename or javascript source ??
1346 -- Tests for max items out by circ_modifier
1347 CREATE TABLE config.circ_matrix_circ_mod_test (
1348 id SERIAL PRIMARY KEY,
1349 matchpoint INT NOT NULL REFERENCES config.circ_matrix_matchpoint (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
1350 items_out INT NOT NULL, -- Total current active circulations must be less than this, NULL means skip (always pass)
1351 circ_mod TEXT NOT NULL REFERENCES config.circ_modifier (code) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED-- circ_modifier type that the max out applies to
1355 -- How to circ, assuming tests pass
1356 CREATE TABLE config.circ_matrix_ruleset (
1357 matchpoint INT PRIMARY KEY REFERENCES config.circ_matrix_matchpoint (id) DEFERRABLE INITIALLY DEFERRED,
1358 duration_rule INT NOT NULL REFERENCES config.rule_circ_duration (id) DEFERRABLE INITIALLY DEFERRED,
1359 recurring_fine_rule INT NOT NULL REFERENCES config.rule_recuring_fine (id) DEFERRABLE INITIALLY DEFERRED,
1360 max_fine_rule INT NOT NULL REFERENCES config.rule_max_fine (id) DEFERRABLE INITIALLY DEFERRED
1363 CREATE OR REPLACE FUNCTION action.find_circ_matrix_matchpoint( context_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS INT AS $func$
1365 current_group permission.grp_tree%ROWTYPE;
1366 user_object actor.usr%ROWTYPE;
1367 item_object asset.copy%ROWTYPE;
1368 rec_descriptor metabib.rec_descriptor%ROWTYPE;
1369 current_mp config.circ_matrix_matchpoint%ROWTYPE;
1370 matchpoint config.circ_matrix_matchpoint%ROWTYPE;
1372 SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1373 SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1374 SELECT INTO rec_descriptor r.* FROM metabib.rec_descriptor r JOIN asset.call_number c USING (record) WHERE c.id = item_object.call_number;
1375 SELECT INTO current_group * FROM permission.grp_tree WHERE id = user_object.profile;
1378 -- for each potential matchpoint for this ou and group ...
1381 FROM config.circ_matrix_matchpoint m
1382 JOIN actor.org_unit_ancestors( context_ou ) d ON (m.org_unit = d.id)
1383 LEFT JOIN actor.org_unit_proximity p ON (p.from_org = context_ou AND p.to_org = d.id)
1384 WHERE m.grp = current_group.id AND m.active
1385 ORDER BY CASE WHEN p.prox IS NULL THEN 999 ELSE p.prox END,
1386 CASE WHEN m.is_renewal = renewal THEN 64 ELSE 0 END +
1387 CASE WHEN m.circ_modifier IS NOT NULL THEN 32 ELSE 0 END +
1388 CASE WHEN m.marc_type IS NOT NULL THEN 16 ELSE 0 END +
1389 CASE WHEN m.marc_form IS NOT NULL THEN 8 ELSE 0 END +
1390 CASE WHEN m.marc_vr_format IS NOT NULL THEN 4 ELSE 0 END +
1391 CASE WHEN m.ref_flag IS NOT NULL THEN 2 ELSE 0 END +
1392 CASE WHEN m.usr_age_lower_bound IS NOT NULL THEN 0.5 ELSE 0 END +
1393 CASE WHEN m.usr_age_upper_bound IS NOT NULL THEN 0.5 ELSE 0 END DESC LOOP
1395 IF current_mp.circ_modifier IS NOT NULL THEN
1396 CONTINUE WHEN current_mp.circ_modifier <> item_object.circ_modifier;
1399 IF current_mp.marc_type IS NOT NULL THEN
1400 IF item_object.circ_as_type IS NOT NULL THEN
1401 CONTINUE WHEN current_mp.marc_type <> item_object.circ_as_type;
1403 CONTINUE WHEN current_mp.marc_type <> rec_descriptor.item_type;
1407 IF current_mp.marc_form IS NOT NULL THEN
1408 CONTINUE WHEN current_mp.marc_form <> rec_descriptor.item_form;
1411 IF current_mp.marc_vr_format IS NOT NULL THEN
1412 CONTINUE WHEN current_mp.marc_vr_format <> rec_descriptor.vr_format;
1415 IF current_mp.ref_flag IS NOT NULL THEN
1416 CONTINUE WHEN current_mp.ref_flag <> item_object.ref;
1419 IF current_mp.usr_age_lower_bound IS NOT NULL THEN
1420 CONTINUE WHEN user_object.dob IS NULL OR current_mp.usr_age_lower_bound < age(user_object.dob);
1423 IF current_mp.usr_age_upper_bound IS NOT NULL THEN
1424 CONTINUE WHEN user_object.dob IS NULL OR current_mp.usr_age_upper_bound > age(user_object.dob);
1428 -- everything was undefined or matched
1429 matchpoint = current_mp;
1431 EXIT WHEN matchpoint.id IS NOT NULL;
1434 EXIT WHEN current_group.parent IS NULL OR matchpoint.id IS NOT NULL;
1436 SELECT INTO current_group * FROM permission.grp_tree WHERE id = current_group.parent;
1439 RETURN matchpoint.id;
1441 $func$ LANGUAGE plpgsql;
1444 CREATE TYPE action.matrix_test_result AS ( success BOOL, matchpoint INT, fail_part TEXT );
1445 CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
1448 user_object actor.usr%ROWTYPE;
1449 item_object asset.copy%ROWTYPE;
1450 item_status_object config.copy_status%ROWTYPE;
1451 item_location_object asset.copy_location%ROWTYPE;
1452 result action.matrix_test_result;
1453 circ_test config.circ_matrix_test%ROWTYPE;
1454 out_by_circ_mod config.circ_matrix_circ_mod_test%ROWTYPE;
1458 current_fines NUMERIC(8,2) := 0.0;
1459 tmp_fines NUMERIC(8,2);
1464 result.success := TRUE;
1466 -- Fail if the user is BARRED
1467 SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1469 -- Fail if we couldn't find a user
1470 IF user_object.id IS NULL THEN
1471 result.fail_part := 'no_user';
1472 result.success := FALSE;
1478 IF user_object.barred IS TRUE THEN
1479 result.fail_part := 'actor.usr.barred';
1480 result.success := FALSE;
1485 -- Fail if the item can't circulate
1486 SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1487 IF item_object.circulate IS FALSE THEN
1488 result.fail_part := 'asset.copy.circulate';
1489 result.success := FALSE;
1494 -- Fail if the item isn't in a circulateable status on a non-renewal
1495 IF NOT renewal AND item_object.status NOT IN ( 0, 7, 8 ) THEN
1496 result.fail_part := 'asset.copy.status';
1497 result.success := FALSE;
1500 ELSIF renewal AND item_object.status <> 1 THEN
1501 result.fail_part := 'asset.copy.status';
1502 result.success := FALSE;
1507 -- Fail if the item can't circulate because of the shelving location
1508 SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
1509 IF item_location_object.circulate IS FALSE THEN
1510 result.fail_part := 'asset.copy_location.circulate';
1511 result.success := FALSE;
1516 SELECT INTO matchpoint_id action.find_circ_matrix_matchpoint(circ_ou, match_item, match_user, renewal);
1517 result.matchpoint := matchpoint_id;
1519 SELECT INTO circ_test * from config.circ_matrix_test WHERE matchpoint = result.matchpoint;
1521 IF circ_test.org_depth IS NOT NULL THEN
1522 SELECT INTO overdue_orgs ARRAY_ACCUM(id) FROM actor.org_unit_descendants( circ_ou, circ_test.org_depth );
1525 -- Fail if we couldn't find a set of tests
1526 IF result.matchpoint IS NULL THEN
1527 result.fail_part := 'no_matchpoint';
1528 result.success := FALSE;
1533 -- Fail if the test is set to hard non-circulating
1534 IF circ_test.circulate IS FALSE THEN
1535 result.fail_part := 'config.circ_matrix_test.circulate';
1536 result.success := FALSE;
1541 -- Fail if the user has too many items checked out
1542 IF circ_test.max_items_out IS NOT NULL THEN
1543 SELECT INTO items_out COUNT(*)
1544 FROM action.circulation
1545 WHERE usr = match_user
1546 AND (circ_test.org_depth IS NULL OR (circ_test.org_depth IS NOT NULL AND circ_lib IN ( SELECT * FROM explode_array(overdue_orgs) )))
1547 AND checkin_time IS NULL
1548 AND (stop_fines IN ('MAXFINES','LONGOVERDUE') OR stop_fines IS NULL);
1549 IF items_out >= circ_test.max_items_out THEN
1550 result.fail_part := 'config.circ_matrix_test.max_items_out';
1551 result.success := FALSE;
1557 -- Fail if the user has too many items with specific circ_modifiers checked out
1558 FOR out_by_circ_mod IN SELECT * FROM config.circ_matrix_circ_mod_test WHERE matchpoint = matchpoint_id LOOP
1559 SELECT INTO items_out COUNT(*)
1560 FROM action.circulation circ
1561 JOIN asset.copy cp ON (cp.id = circ.target_copy)
1562 WHERE circ.usr = match_user
1563 AND (circ_test.org_depth IS NULL OR (circ_test.org_depth IS NOT NULL AND circ_lib IN ( SELECT * FROM explode_array(overdue_orgs) )))
1564 AND circ.checkin_time IS NULL
1565 AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL)
1566 AND cp.circ_modifier = out_by_circ_mod.circ_mod;
1567 IF items_out >= out_by_circ_mod.items_out THEN
1568 result.fail_part := 'config.circ_matrix_circ_mod_test';
1569 result.success := FALSE;
1575 -- Fail if the user has too many overdue items
1576 IF circ_test.max_overdue IS NOT NULL THEN
1577 SELECT INTO items_overdue COUNT(*)
1578 FROM action.circulation
1579 WHERE usr = match_user
1580 AND (circ_test.org_depth IS NULL OR (circ_test.org_depth IS NOT NULL AND circ_lib IN ( SELECT * FROM explode_array(overdue_orgs) )))
1581 AND checkin_time IS NULL
1582 AND due_date < NOW()
1583 AND (stop_fines IN ('MAXFINES','LONGOVERDUE') OR stop_fines IS NULL);
1584 IF items_overdue >= circ_test.max_overdue THEN
1585 result.fail_part := 'config.circ_matrix_test.max_overdue';
1586 result.success := FALSE;
1592 -- Fail if the user has a high fine balance
1593 IF circ_test.max_fines IS NOT NULL THEN
1594 FOR tmp_groc IN SELECT * FROM money.grocery WHERE usr = match_usr AND xact_finish IS NULL AND (circ_test.org_depth IS NULL OR (circ_test.org_depth IS NOT NULL AND billing_location IN ( SELECT * FROM explode_array(overdue_orgs) ))) LOOP
1595 SELECT INTO tmp_fines SUM( amount ) FROM money.billing WHERE xact = tmp_groc.id AND NOT voided;
1596 current_fines = current_fines + COALESCE(tmp_fines, 0.0);
1597 SELECT INTO tmp_fines SUM( amount ) FROM money.payment WHERE xact = tmp_groc.id AND NOT voided;
1598 current_fines = current_fines - COALESCE(tmp_fines, 0.0);
1601 FOR tmp_circ IN SELECT * FROM action.circulation WHERE usr = match_usr AND xact_finish IS NULL AND (circ_test.org_depth IS NULL OR (circ_test.org_depth IS NOT NULL AND circ_lib IN ( SELECT * FROM explode_array(overdue_orgs) ))) LOOP
1602 SELECT INTO tmp_fines SUM( amount ) FROM money.billing WHERE xact = tmp_circ.id AND NOT voided;
1603 current_fines = current_fines + COALESCE(tmp_fines, 0.0);
1604 SELECT INTO tmp_fines SUM( amount ) FROM money.payment WHERE xact = tmp_circ.id AND NOT voided;
1605 current_fines = current_fines - COALESCE(tmp_fines, 0.0);
1608 IF current_fines >= circ_test.max_fines THEN
1609 result.fail_part := 'config.circ_matrix_test.max_fines';
1610 result.success := FALSE;
1616 -- If we passed everything, return the successful matchpoint id
1623 $func$ LANGUAGE plpgsql;
1625 CREATE OR REPLACE FUNCTION action.item_user_circ_test( INT, BIGINT, INT ) RETURNS SETOF action.matrix_test_result AS $func$
1626 SELECT * FROM action.item_user_circ_test( $1, $2, $3, FALSE );
1627 $func$ LANGUAGE SQL;
1629 CREATE OR REPLACE FUNCTION action.item_user_renew_test( INT, BIGINT, INT ) RETURNS SETOF action.matrix_test_result AS $func$
1630 SELECT * FROM action.item_user_circ_test( $1, $2, $3, TRUE );
1631 $func$ LANGUAGE SQL;
1634 CREATE TABLE config.hold_matrix_matchpoint (
1635 id SERIAL PRIMARY KEY,
1636 active BOOL NOT NULL DEFAULT TRUE,
1637 user_home_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
1638 request_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
1639 pickup_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
1640 item_owning_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
1641 item_circ_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
1642 usr_grp INT REFERENCES permission.grp_tree (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top applicable group from the group tree; will need descendents and prox functions for filtering
1643 requestor_grp INT NOT NULL REFERENCES permission.grp_tree (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top applicable group from the group tree; will need descendents and prox functions for filtering
1644 circ_modifier TEXT REFERENCES config.circ_modifier (code) DEFERRABLE INITIALLY DEFERRED,
1645 marc_type TEXT REFERENCES config.item_type_map (code) DEFERRABLE INITIALLY DEFERRED,
1646 marc_form TEXT REFERENCES config.item_form_map (code) DEFERRABLE INITIALLY DEFERRED,
1647 marc_vr_format TEXT REFERENCES config.videorecording_format_map (code) DEFERRABLE INITIALLY DEFERRED,
1649 CONSTRAINT hous_once_per_grp_loc_mod_marc UNIQUE (user_home_ou, request_ou, pickup_ou, item_owning_ou, item_circ_ou, requestor_grp, usr_grp, circ_modifier, marc_type, marc_form, marc_vr_format)
1651 INSERT INTO config.hold_matrix_matchpoint (requestor_grp) VALUES (1);
1654 -- Tests to determine if hold against a specific copy is possible for a user at (and from) a location
1655 CREATE TABLE config.hold_matrix_test (
1656 matchpoint INT PRIMARY KEY REFERENCES config.hold_matrix_matchpoint (id) DEFERRABLE INITIALLY DEFERRED,
1657 holdable BOOL NOT NULL DEFAULT TRUE, -- Hard "can't hold" flag requiring an override
1658 distance_is_from_owner BOOL NOT NULL DEFAULT FALSE, -- How to calculate transit_range. True means owning lib, false means copy circ lib
1659 transit_range INT REFERENCES actor.org_unit_type (id) DEFERRABLE INITIALLY DEFERRED, -- Can circ inside range of cn.owner/cp.circ_lib at depth of the org_unit_type specified here
1660 max_holds INT, -- Total hold requests must be less than this, NULL means skip (always pass)
1661 include_frozen_holds BOOL NOT NULL DEFAULT TRUE, -- Include frozen hold requests in the count for max_holds test
1662 stop_blocked_user BOOL NOT NULL DEFAULT FALSE, -- Stop users who cannot check out items from placing holds
1663 age_hold_protect_rule INT REFERENCES config.rule_age_hold_protect (id) DEFERRABLE INITIALLY DEFERRED -- still not sure we want to move this off the copy
1666 CREATE OR REPLACE FUNCTION action.find_hold_matrix_matchpoint( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT ) RETURNS INT AS $func$
1668 current_requestor_group permission.grp_tree%ROWTYPE;
1669 root_ou actor.org_unit%ROWTYPE;
1670 requestor_object actor.usr%ROWTYPE;
1671 user_object actor.usr%ROWTYPE;
1672 item_object asset.copy%ROWTYPE;
1673 item_cn_object asset.call_number%ROWTYPE;
1674 rec_descriptor metabib.rec_descriptor%ROWTYPE;
1675 current_mp_weight FLOAT;
1676 matchpoint_weight FLOAT;
1678 current_mp config.hold_matrix_matchpoint%ROWTYPE;
1679 matchpoint config.hold_matrix_matchpoint%ROWTYPE;
1681 SELECT INTO root_ou * FROM actor.org_unit WHERE parent_ou IS NULL;
1682 SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1683 SELECT INTO requestor_object * FROM actor.usr WHERE id = match_requestor;
1684 SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1685 SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
1686 SELECT INTO rec_descriptor r.* FROM metabib.rec_descriptor r WHERE r.record = item_cn_object.record;
1687 SELECT INTO current_requestor_group * FROM permission.grp_tree WHERE id = requestor_object.profile;
1690 -- for each potential matchpoint for this ou and group ...
1693 FROM config.hold_matrix_matchpoint m
1694 WHERE m.requestor_grp = current_requestor_group.id AND m.active
1695 ORDER BY CASE WHEN m.circ_modifier IS NOT NULL THEN 16 ELSE 0 END +
1696 CASE WHEN m.marc_type IS NOT NULL THEN 8 ELSE 0 END +
1697 CASE WHEN m.marc_form IS NOT NULL THEN 4 ELSE 0 END +
1698 CASE WHEN m.marc_vr_format IS NOT NULL THEN 2 ELSE 0 END +
1699 CASE WHEN m.ref_flag IS NOT NULL THEN 1 ELSE 0 END DESC LOOP
1701 current_mp_weight := 5.0;
1703 IF current_mp.circ_modifier IS NOT NULL THEN
1704 CONTINUE WHEN current_mp.circ_modifier <> item_object.circ_modifier;
1707 IF current_mp.marc_type IS NOT NULL THEN
1708 IF item_object.circ_as_type IS NOT NULL THEN
1709 CONTINUE WHEN current_mp.marc_type <> item_object.circ_as_type;
1711 CONTINUE WHEN current_mp.marc_type <> rec_descriptor.item_type;
1715 IF current_mp.marc_form IS NOT NULL THEN
1716 CONTINUE WHEN current_mp.marc_form <> rec_descriptor.item_form;
1719 IF current_mp.marc_vr_format IS NOT NULL THEN
1720 CONTINUE WHEN current_mp.marc_vr_format <> rec_descriptor.vr_format;
1723 IF current_mp.ref_flag IS NOT NULL THEN
1724 CONTINUE WHEN current_mp.ref_flag <> item_object.ref;
1728 -- caclulate the rule match weight
1729 IF current_mp.item_owning_ou IS NOT NULL AND current_mp.item_owning_ou <> root_ou.id THEN
1730 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.item_owning_ou, item_cn_object.owning_lib)::FLOAT + 1.0)::FLOAT;
1731 current_mp_weight := current_mp_weight - tmp_weight;
1734 IF current_mp.item_circ_ou IS NOT NULL AND current_mp.item_circ_ou <> root_ou.id THEN
1735 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.item_circ_ou, item_object.circ_lib)::FLOAT + 1.0)::FLOAT;
1736 current_mp_weight := current_mp_weight - tmp_weight;
1739 IF current_mp.pickup_ou IS NOT NULL AND current_mp.pickup_ou <> root_ou.id THEN
1740 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.pickup_ou, pickup_ou)::FLOAT + 1.0)::FLOAT;
1741 current_mp_weight := current_mp_weight - tmp_weight;
1744 IF current_mp.request_ou IS NOT NULL AND current_mp.request_ou <> root_ou.id THEN
1745 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.request_ou, request_ou)::FLOAT + 1.0)::FLOAT;
1746 current_mp_weight := current_mp_weight - tmp_weight;
1749 IF current_mp.user_home_ou IS NOT NULL AND current_mp.user_home_ou <> root_ou.id THEN
1750 SELECT INTO tmp_weight 1.0 / (actor.org_unit_proximity(current_mp.user_home_ou, user_object.home_ou)::FLOAT + 1.0)::FLOAT;
1751 current_mp_weight := current_mp_weight - tmp_weight;
1754 -- set the matchpoint if we found the best one
1755 IF matchpoint_weight IS NULL OR matchpoint_weight > current_mp_weight THEN
1756 matchpoint = current_mp;
1757 matchpoint_weight = current_mp_weight;
1762 EXIT WHEN current_requestor_group.parent IS NULL OR matchpoint.id IS NOT NULL;
1764 SELECT INTO current_requestor_group * FROM permission.grp_tree WHERE id = current_requestor_group.parent;
1767 RETURN matchpoint.id;
1769 $func$ LANGUAGE plpgsql;
1772 CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT ) RETURNS SETOF action.matrix_test_result AS $func$
1775 user_object actor.usr%ROWTYPE;
1776 age_protect_object config.rule_age_hold_protect%ROWTYPE;
1777 transit_range_ou_type actor.org_unit_type%ROWTYPE;
1778 transit_source actor.org_unit%ROWTYPE;
1779 item_object asset.copy%ROWTYPE;
1780 result action.matrix_test_result;
1781 hold_test config.hold_matrix_test%ROWTYPE;
1783 hold_transit_prox INT;
1784 frozen_hold_count INT;
1785 patron_penalties INT;
1788 SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1790 -- Fail if we couldn't find a user
1791 IF user_object.id IS NULL THEN
1792 result.fail_part := 'no_user';
1793 result.success := FALSE;
1799 -- Fail if user is barred
1800 IF user_object.barred IS TRUE THEN
1801 result.fail_part := 'actor.usr.barred';
1802 result.success := FALSE;
1808 SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1810 -- Fail if we couldn't find a copy
1811 IF item_object.id IS NULL THEN
1812 result.fail_part := 'no_item';
1813 result.success := FALSE;
1819 SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(pickup_ou, request_ou, match_item, match_user, match_requestor);
1821 -- Fail if we couldn't find any matchpoint (requires a default)
1822 IF matchpoint_id IS NULL THEN
1823 result.fail_part := 'no_matchpoint';
1824 result.success := FALSE;
1830 SELECT INTO hold_test * FROM config.hold_matrix_test WHERE matchpoint = matchpoint_id;
1832 result.matchpoint := matchpoint_id;
1833 result.success := TRUE;
1835 IF hold_test.holdable IS FALSE THEN
1836 result.fail_part := 'config.hold_matrix_test.holdable';
1837 result.success := FALSE;
1842 IF hold_test.transit_range IS NOT NULL THEN
1843 SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
1844 IF hold_test.distance_is_from_owner THEN
1845 SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number;
1847 SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
1850 PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = pickup_ou;
1853 result.fail_part := 'transit_range';
1854 result.success := FALSE;
1860 IF hold_test.stop_blocked_user IS TRUE THEN
1861 SELECT INTO patron_penalties COUNT(*)
1862 FROM actor.usr_standing_penalty
1863 WHERE usr = match_user;
1865 IF items_out > 0 THEN
1866 result.fail_part := 'config.hold_matrix_test.stop_blocked_user';
1867 result.success := FALSE;
1873 IF hold_test.max_holds IS NOT NULL THEN
1874 SELECT INTO hold_count COUNT(*)
1875 FROM action.hold_request
1876 WHERE usr = match_user
1877 AND fulfillment_time IS NULL
1878 AND cancel_time IS NULL
1879 AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END;
1881 IF items_out >= hold_test.max_holds THEN
1882 result.fail_part := 'config.hold_matrix_test.max_holds';
1883 result.success := FALSE;
1889 IF item_object.age_protect IS NOT NULL THEN
1890 SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
1892 IF item_object.create_date + age_protect_object.age > NOW() THEN
1893 IF hold_test.distance_is_from_owner THEN
1894 SELECT INTO hold_transit_prox prox FROM actor.org_unit_prox WHERE from_org = item_cn_object.owning_lib AND to_org = pickup_ou;
1896 SELECT INTO hold_transit_prox prox FROM actor.org_unit_prox WHERE from_org = item_object.circ_lib AND to_org = pickup_ou;
1899 IF hold_transit_prox > age_protect_object.prox THEN
1900 result.fail_part := 'config.rule_age_hold_protect.prox';
1901 result.success := FALSE;
1914 $func$ LANGUAGE plpgsql;
1916 CREATE SCHEMA vandelay;
1918 CREATE TABLE vandelay.queue (
1919 id BIGSERIAL PRIMARY KEY,
1920 owner INT NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
1922 complete BOOL NOT NULL DEFAULT FALSE,
1923 queue_type TEXT NOT NULL DEFAULT 'bib' CHECK (queue_type IN ('bib','authority')),
1924 CONSTRAINT vand_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
1927 CREATE TABLE vandelay.queued_record (
1928 id BIGSERIAL PRIMARY KEY,
1929 create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
1930 import_time TIMESTAMP WITH TIME ZONE,
1931 purpose TEXT NOT NULL DEFAULT 'import' CHECK (purpose IN ('import','overlay')),
1937 /* Bib stuff at the top */
1938 ----------------------------------------------------
1940 CREATE TABLE vandelay.bib_attr_definition (
1941 id SERIAL PRIMARY KEY,
1942 code TEXT UNIQUE NOT NULL,
1944 xpath TEXT NOT NULL,
1945 remove TEXT NOT NULL DEFAULT '',
1946 ident BOOL NOT NULL DEFAULT FALSE
1949 -- Each TEXT field (other than 'name') should hold an XPath predicate for pulling the data needed
1950 -- DROP TABLE vandelay.import_item_attr_definition CASCADE;
1951 CREATE TABLE vandelay.import_item_attr_definition (
1952 id BIGSERIAL PRIMARY KEY,
1953 owner INT NOT NULL REFERENCES actor.org_unit (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
1956 keep BOOL NOT NULL DEFAULT FALSE,
1965 deposit_amount TEXT,
1974 pub_note_title TEXT,
1976 priv_note_title TEXT,
1978 CONSTRAINT vand_import_item_attr_def_idx UNIQUE (owner,name)
1981 CREATE TABLE vandelay.bib_queue (
1982 queue_type TEXT NOT NULL DEFAULT 'bib' CHECK (queue_type = 'bib'),
1983 item_attr_def BIGINT REFERENCES vandelay.import_item_attr_definition (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
1984 CONSTRAINT vand_bib_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
1985 ) INHERITS (vandelay.queue);
1986 ALTER TABLE vandelay.bib_queue ADD PRIMARY KEY (id);
1988 CREATE TABLE vandelay.queued_bib_record (
1989 queue INT NOT NULL REFERENCES vandelay.bib_queue (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
1990 bib_source INT REFERENCES config.bib_source (id) DEFERRABLE INITIALLY DEFERRED,
1991 imported_as INT REFERENCES biblio.record_entry (id) DEFERRABLE INITIALLY DEFERRED
1992 ) INHERITS (vandelay.queued_record);
1993 ALTER TABLE vandelay.queued_bib_record ADD PRIMARY KEY (id);
1995 CREATE TABLE vandelay.queued_bib_record_attr (
1996 id BIGSERIAL PRIMARY KEY,
1997 record BIGINT NOT NULL REFERENCES vandelay.queued_bib_record (id) DEFERRABLE INITIALLY DEFERRED,
1998 field INT NOT NULL REFERENCES vandelay.bib_attr_definition (id) DEFERRABLE INITIALLY DEFERRED,
1999 attr_value TEXT NOT NULL
2002 CREATE TABLE vandelay.bib_match (
2003 id BIGSERIAL PRIMARY KEY,
2004 field_type TEXT NOT NULL CHECK (field_type in ('isbn','tcn_value','id')),
2005 matched_attr INT REFERENCES vandelay.queued_bib_record_attr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2006 queued_record BIGINT REFERENCES vandelay.queued_bib_record (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2007 eg_record BIGINT REFERENCES biblio.record_entry (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
2010 -- DROP TABLE vandelay.import_item CASCADE;
2011 CREATE TABLE vandelay.import_item (
2012 id BIGSERIAL PRIMARY KEY,
2013 record BIGINT NOT NULL REFERENCES vandelay.queued_bib_record (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2014 definition BIGINT NOT NULL REFERENCES vandelay.import_item_attr_definition (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2023 deposit_amount NUMERIC(8,2),
2036 CREATE TABLE vandelay.import_bib_trash_fields (
2037 id BIGSERIAL PRIMARY KEY,
2038 owner INT NOT NULL REFERENCES actor.org_unit (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2039 field TEXT NOT NULL,
2040 CONSTRAINT vand_import_bib_trash_fields_idx UNIQUE (owner,field)
2043 CREATE OR REPLACE FUNCTION vandelay.strip_field ( xml TEXT, field TEXT ) RETURNS TEXT AS $_$
2046 use MARC::File::XML;
2049 my $field_spec = shift;
2051 my $r = MARC::Record->new_from_xml( $xml );
2052 $r->delete_field( $_ ) for ( $r->field( $field_spec ) );
2054 $xml = $r->as_xml_record;
2055 $xml =~ s/^<\?.+?\?>$//mo;
2057 $xml =~ s/>\s+</></sgo;
2061 $_$ LANGUAGE PLPERLU;
2064 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
2075 deposit_amount TEXT;
2088 tmp_attr_set RECORD;
2089 attr_set vandelay.import_item%ROWTYPE;
2095 SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
2099 attr_set.definition := attr_def.id;
2101 -- Build the combined XPath
2105 WHEN attr_def.owning_lib IS NULL THEN 'null()'
2106 WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]'
2107 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib
2112 WHEN attr_def.circ_lib IS NULL THEN 'null()'
2113 WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]'
2114 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib
2119 WHEN attr_def.call_number IS NULL THEN 'null()'
2120 WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]'
2121 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number
2126 WHEN attr_def.copy_number IS NULL THEN 'null()'
2127 WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]'
2128 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number
2133 WHEN attr_def.status IS NULL THEN 'null()'
2134 WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]'
2135 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status
2140 WHEN attr_def.location IS NULL THEN 'null()'
2141 WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]'
2142 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location
2147 WHEN attr_def.circulate IS NULL THEN 'null()'
2148 WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]'
2149 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate
2154 WHEN attr_def.deposit IS NULL THEN 'null()'
2155 WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]'
2156 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit
2161 WHEN attr_def.deposit_amount IS NULL THEN 'null()'
2162 WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]'
2163 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount
2168 WHEN attr_def.ref IS NULL THEN 'null()'
2169 WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]'
2170 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref
2175 WHEN attr_def.holdable IS NULL THEN 'null()'
2176 WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]'
2177 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable
2182 WHEN attr_def.price IS NULL THEN 'null()'
2183 WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]'
2184 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price
2189 WHEN attr_def.barcode IS NULL THEN 'null()'
2190 WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]'
2191 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode
2196 WHEN attr_def.circ_modifier IS NULL THEN 'null()'
2197 WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]'
2198 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier
2203 WHEN attr_def.circ_as_type IS NULL THEN 'null()'
2204 WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]'
2205 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type
2210 WHEN attr_def.alert_message IS NULL THEN 'null()'
2211 WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]'
2212 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message
2217 WHEN attr_def.opac_visible IS NULL THEN 'null()'
2218 WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]'
2219 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible
2224 WHEN attr_def.pub_note IS NULL THEN 'null()'
2225 WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]'
2226 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note
2230 WHEN attr_def.priv_note IS NULL THEN 'null()'
2231 WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]'
2232 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note
2237 owning_lib || '|' ||
2239 call_number || '|' ||
2240 copy_number || '|' ||
2245 deposit_amount || '|' ||
2250 circ_modifier || '|' ||
2251 circ_as_type || '|' ||
2252 alert_message || '|' ||
2257 -- RAISE NOTICE 'XPath: %', xpath;
2261 FROM xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id )
2262 AS t( id BIGINT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
2263 dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
2264 circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, opac_vis TEXT )
2267 tmp_attr_set.pr = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
2268 tmp_attr_set.dep_amount = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
2270 tmp_attr_set.pr := NULLIF( tmp_attr_set.pr, '' );
2271 tmp_attr_set.dep_amount := NULLIF( tmp_attr_set.dep_amount, '' );
2273 SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
2274 SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
2275 SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
2277 SELECT id INTO attr_set.location
2278 FROM asset.copy_location
2279 WHERE LOWER(name) = LOWER(tmp_attr_set.cl)
2280 AND owning_lib = COALESCE(attr_set.owning_lib, attr_set.circ_lib); -- INT
2282 attr_set.circulate :=
2283 LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
2284 OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
2287 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
2288 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
2290 attr_set.holdable :=
2291 LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
2292 OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
2294 attr_set.opac_visible :=
2295 LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
2296 OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
2299 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
2300 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
2302 attr_set.copy_number := tmp_attr_set.cnum::INT; -- INT,
2303 attr_set.deposit_amount := tmp_attr_set.dep_amount::NUMERIC(6,2); -- NUMERIC(6,2),
2304 attr_set.price := tmp_attr_set.pr::NUMERIC(8,2); -- NUMERIC(8,2),
2306 attr_set.call_number := tmp_attr_set.cn; -- TEXT
2307 attr_set.barcode := tmp_attr_set.bc; -- TEXT,
2308 attr_set.circ_modifier := tmp_attr_set.circ_mod; -- TEXT,
2309 attr_set.circ_as_type := tmp_attr_set.circ_as; -- TEXT,
2310 attr_set.alert_message := tmp_attr_set.amessage; -- TEXT,
2311 attr_set.pub_note := tmp_attr_set.note; -- TEXT,
2312 attr_set.priv_note := tmp_attr_set.pnote; -- TEXT,
2313 attr_set.alert_message := tmp_attr_set.amessage; -- TEXT,
2315 RETURN NEXT attr_set;
2322 $$ LANGUAGE PLPGSQL;
2325 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_marc ( ) RETURNS TRIGGER AS $$
2331 FOR adef IN SELECT * FROM vandelay.bib_attr_definition LOOP
2333 SELECT extract_marc_field('vandelay.queued_bib_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_bib_record WHERE id = NEW.id;
2334 IF (value IS NOT NULL AND value <> '') THEN
2335 INSERT INTO vandelay.queued_bib_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value);
2342 $$ LANGUAGE PLPGSQL;
2344 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_items ( ) RETURNS TRIGGER AS $func$
2348 item_data vandelay.import_item%ROWTYPE;
2351 SELECT * INTO queue_rec FROM vandelay.bib_queue WHERE id = NEW.queue;
2353 FOR item_rule IN SELECT r.* FROM actor.org_unit_ancestors( queue_rec.owner ) o JOIN vandelay.import_item_attr_definition r ON ( r.owner = o.id ) LOOP
2354 FOR item_data IN SELECT * FROM vandelay.ingest_items( NEW.id::BIGINT, item_rule.id::BIGINT ) LOOP
2355 INSERT INTO vandelay.import_item (
2379 item_data.definition,
2380 item_data.owning_lib,
2382 item_data.call_number,
2383 item_data.copy_number,
2386 item_data.circulate,
2388 item_data.deposit_amount,
2393 item_data.circ_modifier,
2394 item_data.circ_as_type,
2395 item_data.alert_message,
2397 item_data.priv_note,
2398 item_data.opac_visible
2405 $func$ LANGUAGE PLPGSQL;
2407 CREATE OR REPLACE FUNCTION vandelay.match_bib_record ( ) RETURNS TRIGGER AS $func$
2412 FOR attr IN SELECT a.* FROM vandelay.queued_bib_record_attr a JOIN vandelay.bib_attr_definition d ON (d.id = a.field) WHERE record = NEW.id AND d.ident IS TRUE LOOP
2414 -- All numbers? check for an id match
2415 IF (attr.attr_value ~ $r$^\d+$$r$) THEN
2416 FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE id = attr.attr_value::BIGINT AND deleted IS FALSE LOOP
2417 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('id', attr.id, NEW.id, eg_rec.id);
2421 -- Looks like an ISBN? check for an isbn match
2422 IF (attr.attr_value ~* $r$^[0-9x]+$$r$ AND character_length(attr.attr_value) IN (10,13)) THEN
2423 FOR eg_rec IN EXECUTE $$SELECT * FROM metabib.full_rec fr WHERE fr.value LIKE LOWER('$$ || attr.attr_value || $$%') AND fr.tag = '020' AND fr.subfield = 'a'$$ LOOP
2424 PERFORM id FROM biblio.record_entry WHERE id = eg_rec.record AND deleted IS FALSE;
2426 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('isbn', attr.id, NEW.id, eg_rec.record);
2430 -- subcheck for isbn-as-tcn
2431 FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = 'i' || attr.attr_value AND deleted IS FALSE LOOP
2432 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
2436 -- check for an OCLC tcn_value match
2437 IF (attr.attr_value ~ $r$^o\d+$$r$) THEN
2438 FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = regexp_replace(attr.attr_value,'^o','ocm') AND deleted IS FALSE LOOP
2439 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
2443 -- check for a direct tcn_value match
2444 FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = attr.attr_value AND deleted IS FALSE LOOP
2445 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
2452 $func$ LANGUAGE PLPGSQL;
2454 CREATE OR REPLACE FUNCTION vandelay.cleanup_bib_marc ( ) RETURNS TRIGGER AS $$
2456 DELETE FROM vandelay.queued_bib_record_attr WHERE record = OLD.id;
2457 DELETE FROM vandelay.import_item WHERE record = OLD.id;
2459 IF TG_OP = 'UPDATE' THEN
2464 $$ LANGUAGE PLPGSQL;
2466 CREATE TRIGGER cleanup_bib_trigger
2467 BEFORE UPDATE OR DELETE ON vandelay.queued_bib_record
2468 FOR EACH ROW EXECUTE PROCEDURE vandelay.cleanup_bib_marc();
2470 CREATE TRIGGER ingest_bib_trigger
2471 AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
2472 FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_bib_marc();
2474 CREATE TRIGGER ingest_item_trigger
2475 AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
2476 FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_bib_items();
2478 CREATE TRIGGER zz_match_bibs_trigger
2479 AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
2480 FOR EACH ROW EXECUTE PROCEDURE vandelay.match_bib_record();
2483 /* Authority stuff down here */
2484 ---------------------------------------
2485 CREATE TABLE vandelay.authority_attr_definition (
2486 id SERIAL PRIMARY KEY,
2487 code TEXT UNIQUE NOT NULL,
2489 xpath TEXT NOT NULL,
2490 remove TEXT NOT NULL DEFAULT '',
2491 ident BOOL NOT NULL DEFAULT FALSE
2494 CREATE TABLE vandelay.authority_queue (
2495 queue_type TEXT NOT NULL DEFAULT 'authority' CHECK (queue_type = 'authority'),
2496 CONSTRAINT vand_authority_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
2497 ) INHERITS (vandelay.queue);
2498 ALTER TABLE vandelay.authority_queue ADD PRIMARY KEY (id);
2500 CREATE TABLE vandelay.queued_authority_record (
2501 queue INT NOT NULL REFERENCES vandelay.authority_queue (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2502 imported_as INT REFERENCES authority.record_entry (id) DEFERRABLE INITIALLY DEFERRED
2503 ) INHERITS (vandelay.queued_record);
2504 ALTER TABLE vandelay.queued_authority_record ADD PRIMARY KEY (id);
2506 CREATE TABLE vandelay.queued_authority_record_attr (
2507 id BIGSERIAL PRIMARY KEY,
2508 record BIGINT NOT NULL REFERENCES vandelay.queued_authority_record (id) DEFERRABLE INITIALLY DEFERRED,
2509 field INT NOT NULL REFERENCES vandelay.authority_attr_definition (id) DEFERRABLE INITIALLY DEFERRED,
2510 attr_value TEXT NOT NULL
2513 CREATE TABLE vandelay.authority_match (
2514 id BIGSERIAL PRIMARY KEY,
2515 matched_attr INT REFERENCES vandelay.queued_authority_record_attr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2516 queued_record BIGINT REFERENCES vandelay.queued_authority_record (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2517 eg_record BIGINT REFERENCES authority.record_entry (id) DEFERRABLE INITIALLY DEFERRED
2520 CREATE OR REPLACE FUNCTION vandelay.ingest_authority_marc ( ) RETURNS TRIGGER AS $$
2526 FOR adef IN SELECT * FROM vandelay.authority_attr_definition LOOP
2528 SELECT extract_marc_field('vandelay.queued_authority_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_authority_record WHERE id = NEW.id;
2529 IF (value IS NOT NULL AND value <> '') THEN
2530 INSERT INTO vandelay.queued_authority_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value);
2537 $$ LANGUAGE PLPGSQL;
2539 CREATE OR REPLACE FUNCTION vandelay.cleanup_authority_marc ( ) RETURNS TRIGGER AS $$
2541 DELETE FROM vandelay.queued_authority_record_attr WHERE record = OLD.id;
2542 IF TG_OP = 'UPDATE' THEN
2547 $$ LANGUAGE PLPGSQL;
2549 CREATE TRIGGER cleanup_authority_trigger
2550 BEFORE UPDATE OR DELETE ON vandelay.queued_authority_record
2551 FOR EACH ROW EXECUTE PROCEDURE vandelay.cleanup_authority_marc();
2553 CREATE TRIGGER ingest_authority_trigger
2554 AFTER INSERT OR UPDATE ON vandelay.queued_authority_record
2555 FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_authority_marc();
2557 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (1, 'title', oils_i18n_gettext(1, 'Title of work', 'vqbrad', 'description'),'//*[@tag="245"]/*[contains("abcmnopr",@code)]');
2558 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (2, 'author', oils_i18n_gettext(2, 'Author of work', 'vqbrad', 'description'),'//*[@tag="100" or @tag="110" or @tag="113"]/*[contains("ad",@code)]');
2559 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (3, 'language', oils_i18n_gettext(3, 'Language of work', 'vqbrad', 'description'),'//*[@tag="240"]/*[@code="l"][1]');
2560 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (4, 'pagination', oils_i18n_gettext(4, 'Pagination', 'vqbrad', 'description'),'//*[@tag="300"]/*[@code="a"][1]');
2561 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, ident, remove ) VALUES (5, 'isbn',oils_i18n_gettext(5, 'ISBN', 'vqbrad', 'description'),'//*[@tag="020"]/*[@code="a"]', TRUE, $r$(?:-|\s.+$)$r$);
2562 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, ident, remove ) VALUES (6, 'issn',oils_i18n_gettext(6, 'ISSN', 'vqbrad', 'description'),'//*[@tag="022"]/*[@code="a"]', TRUE, $r$(?:-|\s.+$)$r$);
2563 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (7, 'price',oils_i18n_gettext(7, 'Price', 'vqbrad', 'description'),'//*[@tag="020" or @tag="022"]/*[@code="c"][1]');
2564 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, ident ) VALUES (8, 'rec_identifier',oils_i18n_gettext(8, 'Accession Number', 'vqbrad', 'description'),'//*[@tag="001"]', TRUE);
2565 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, ident ) VALUES (9, 'eg_tcn',oils_i18n_gettext(9, 'TCN Value', 'vqbrad', 'description'),'//*[@tag="901"]/*[@code="a"]', TRUE);
2566 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, ident ) VALUES (10, 'eg_tcn_source',oils_i18n_gettext(10, 'TCN Source', 'vqbrad', 'description'),'//*[@tag="901"]/*[@code="b"]', TRUE);
2567 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, ident ) VALUES (11, 'eg_identifier',oils_i18n_gettext(11, 'Internal ID', 'vqbrad', 'description'),'//*[@tag="901"]/*[@code="c"]', TRUE);
2568 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (12, 'publisher',oils_i18n_gettext(12, 'Publisher', 'vqbrad', 'description'),'//*[@tag="260"]/*[@code="b"][1]');
2569 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath, remove ) VALUES (13, 'pubdate',oils_i18n_gettext(13, 'Publication Date', 'vqbrad', 'description'),'//*[@tag="260"]/*[@code="c"][1]',$r$\D$r$);
2570 INSERT INTO vandelay.bib_attr_definition ( id, code, description, xpath ) VALUES (14, 'edition',oils_i18n_gettext(14, 'Edition', 'vqbrad', 'description'),'//*[@tag="250"]/*[@code="a"][1]');
2572 INSERT INTO vandelay.import_item_attr_definition (
2573 owner, name, tag, owning_lib, circ_lib, location,
2574 call_number, circ_modifier, barcode, price, copy_number,
2575 circulate, ref, holdable, opac_visible, status
2578 'Evergreen 852 export format',
2588 '[@code = "x" and text() = "circulating"]',
2589 '[@code = "x" and text() = "reference"]',
2590 '[@code = "x" and text() = "holdable"]',
2591 '[@code = "x" and text() = "visible"]',
2595 INSERT INTO vandelay.import_item_attr_definition (
2608 'Unicorn Import format -- 999',
2619 CREATE OR REPLACE VIEW extend_reporter.global_bibs_by_holding_update AS
2620 SELECT DISTINCT ON (id) id, holding_update, update_type
2622 LAST(cp.create_date) AS holding_update,
2623 'add' AS update_type
2624 FROM biblio.record_entry b
2625 JOIN asset.call_number cn ON (cn.record = b.id)
2626 JOIN asset.copy cp ON (cp.call_number = cn.id)
2627 WHERE NOT cp.deleted
2632 LAST(cp.edit_date) AS holding_update,
2633 'delete' AS update_type
2634 FROM biblio.record_entry b
2635 JOIN asset.call_number cn ON (cn.record = b.id)
2636 JOIN asset.copy cp ON (cp.call_number = cn.id)
2640 ORDER BY id, holding_update;
2642 INSERT INTO vandelay.authority_attr_definition ( code, description, xpath, ident ) VALUES ('rec_identifier','Identifier','//*[@tag="001"]', TRUE);
2644 UPDATE config.xml_transform SET xslt=$$<?xml version="1.0" encoding="UTF-8"?>
2645 <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">
2646 <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
2648 Revision 1.14 - Fixed template isValid and fields 010, 020, 022, 024, 028, and 037 to output additional identifier elements
2649 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
2651 Revision 1.13 - Changed order of output under cartographics to reflect schema 2006/11/28 tmee
2653 Revision 1.12 - Updated to reflect MODS 3.2 Mapping 2006/10/11 tmee
2655 Revision 1.11 - The attribute objectPart moved from <languageTerm> to <language>
2658 Revision 1.10 MODS 3.1 revisions to language and classification elements
2659 (plus ability to find marc:collection embedded in wrapper elements such as SRU zs: wrappers)
2662 Revision 1.9 subfield $y was added to field 242 2004/09/02 10:57 jrad
2664 Revision 1.8 Subject chopPunctuation expanded and attribute fixes 2004/08/12 jrad
2666 Revision 1.7 2004/03/25 08:29 jrad
2668 Revision 1.6 various validation fixes 2004/02/20 ntra
2670 Revision 1.5 2003/10/02 16:18:58 ntra
2671 MODS2 to MODS3 updates, language unstacking and
2672 de-duping, chopPunctuation expanded
2674 Revision 1.3 2003/04/03 00:07:19 ntra
2675 Revision 1.3 Additional Changes not related to MODS Version 2.0 by ntra
2677 Revision 1.2 2003/03/24 19:37:42 ckeith
2681 <xsl:template match="/">
2683 <xsl:when test="//marc:collection">
2684 <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">
2685 <xsl:for-each select="//marc:collection/marc:record">
2686 <mods version="3.2">
2687 <xsl:call-template name="marcRecord"/>
2693 <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">
2694 <xsl:for-each select="//marc:record">
2695 <xsl:call-template name="marcRecord"/>
2701 <xsl:template name="marcRecord">
2702 <xsl:variable name="leader" select="marc:leader"/>
2703 <xsl:variable name="leader6" select="substring($leader,7,1)"/>
2704 <xsl:variable name="leader7" select="substring($leader,8,1)"/>
2705 <xsl:variable name="controlField008" select="marc:controlfield[@tag='008']"/>
2706 <xsl:variable name="typeOf008">
2708 <xsl:when test="$leader6='a'">
2710 <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>
2711 <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when>
2714 <xsl:when test="$leader6='t'">BK</xsl:when>
2715 <xsl:when test="$leader6='p'">MM</xsl:when>
2716 <xsl:when test="$leader6='m'">CF</xsl:when>
2717 <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when>
2718 <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when>
2719 <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'">MU</xsl:when>
2722 <xsl:for-each select="marc:datafield[@tag='245']">
2724 <xsl:variable name="title">
2726 <xsl:when test="marc:subfield[@code='b']">
2727 <xsl:call-template name="specialSubfieldSelect">
2728 <xsl:with-param name="axis">b</xsl:with-param>
2729 <xsl:with-param name="beforeCodes">afgk</xsl:with-param>
2730 </xsl:call-template>
2733 <xsl:call-template name="subfieldSelect">
2734 <xsl:with-param name="codes">abfgk</xsl:with-param>
2735 </xsl:call-template>
2739 <xsl:variable name="titleChop">
2740 <xsl:call-template name="chopPunctuation">
2741 <xsl:with-param name="chopString">
2742 <xsl:value-of select="$title"/>
2744 </xsl:call-template>
2747 <xsl:when test="@ind2>0">
2749 <xsl:value-of select="substring($titleChop,1,@ind2)"/>
2752 <xsl:value-of select="substring($titleChop,@ind2+1)"/>
2757 <xsl:value-of select="$titleChop"/>
2761 <xsl:if test="marc:subfield[@code='b']">
2763 <xsl:call-template name="chopPunctuation">
2764 <xsl:with-param name="chopString">
2765 <xsl:call-template name="specialSubfieldSelect">
2766 <xsl:with-param name="axis">b</xsl:with-param>
2767 <xsl:with-param name="anyCodes">b</xsl:with-param>
2768 <xsl:with-param name="afterCodes">afgk</xsl:with-param>
2769 </xsl:call-template>
2771 </xsl:call-template>
2774 <xsl:call-template name="part"></xsl:call-template>
2777 <xsl:for-each select="marc:datafield[@tag='210']">
2778 <titleInfo type="abbreviated">
2780 <xsl:call-template name="chopPunctuation">
2781 <xsl:with-param name="chopString">
2782 <xsl:call-template name="subfieldSelect">
2783 <xsl:with-param name="codes">a</xsl:with-param>
2784 </xsl:call-template>
2786 </xsl:call-template>
2788 <xsl:call-template name="subtitle"/>
2791 <xsl:for-each select="marc:datafield[@tag='242']">
2792 <titleInfo type="translated">
2793 <!--09/01/04 Added subfield $y-->
2794 <xsl:for-each select="marc:subfield[@code='y']">
2795 <xsl:attribute name="lang">
2796 <xsl:value-of select="text()"/>
2800 <xsl:call-template name="chopPunctuation">
2801 <xsl:with-param name="chopString">
2802 <xsl:call-template name="subfieldSelect">
2803 <!-- 1/04 removed $h, b -->
2804 <xsl:with-param name="codes">a</xsl:with-param>
2805 </xsl:call-template>
2807 </xsl:call-template>
2810 <xsl:call-template name="subtitle"/>
2811 <xsl:call-template name="part"/>
2814 <xsl:for-each select="marc:datafield[@tag='246']">
2815 <titleInfo type="alternative">
2816 <xsl:for-each select="marc:subfield[@code='i']">
2817 <xsl:attribute name="displayLabel">
2818 <xsl:value-of select="text()"/>
2822 <xsl:call-template name="chopPunctuation">
2823 <xsl:with-param name="chopString">
2824 <xsl:call-template name="subfieldSelect">
2825 <!-- 1/04 removed $h, $b -->
2826 <xsl:with-param name="codes">af</xsl:with-param>
2827 </xsl:call-template>
2829 </xsl:call-template>
2831 <xsl:call-template name="subtitle"/>
2832 <xsl:call-template name="part"/>
2835 <xsl:for-each select="marc:datafield[@tag='130']|marc:datafield[@tag='240']|marc:datafield[@tag='730'][@ind2!='2']">
2836 <titleInfo type="uniform">
2838 <xsl:variable name="str">
2839 <xsl:for-each select="marc:subfield">
2840 <xsl:if test="(contains('adfklmor',@code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">
2841 <xsl:value-of select="text()"/>
2842 <xsl:text> </xsl:text>
2846 <xsl:call-template name="chopPunctuation">
2847 <xsl:with-param name="chopString">
2848 <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
2850 </xsl:call-template>
2852 <xsl:call-template name="part"/>
2855 <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
2856 <titleInfo type="alternative">
2858 <xsl:call-template name="chopPunctuation">
2859 <xsl:with-param name="chopString">
2860 <xsl:call-template name="subfieldSelect">
2861 <xsl:with-param name="codes">ah</xsl:with-param>
2862 </xsl:call-template>
2864 </xsl:call-template>
2866 <xsl:call-template name="part"/>
2869 <xsl:for-each select="marc:datafield[@tag='100']">
2870 <name type="personal">
2871 <xsl:call-template name="nameABCDQ"/>
2872 <xsl:call-template name="affiliation"/>
2874 <roleTerm authority="marcrelator" type="text">creator</roleTerm>
2876 <xsl:call-template name="role"/>
2879 <xsl:for-each select="marc:datafield[@tag='110']">
2880 <name type="corporate">
2881 <xsl:call-template name="nameABCDN"/>
2883 <roleTerm authority="marcrelator" type="text">creator</roleTerm>
2885 <xsl:call-template name="role"/>
2888 <xsl:for-each select="marc:datafield[@tag='111']">
2889 <name type="conference">
2890 <xsl:call-template name="nameACDEQ"/>
2892 <roleTerm authority="marcrelator" type="text">creator</roleTerm>
2894 <xsl:call-template name="role"/>
2897 <xsl:for-each select="marc:datafield[@tag='700'][not(marc:subfield[@code='t'])]">
2898 <name type="personal">
2899 <xsl:call-template name="nameABCDQ"/>
2900 <xsl:call-template name="affiliation"/>
2901 <xsl:call-template name="role"/>
2904 <xsl:for-each select="marc:datafield[@tag='710'][not(marc:subfield[@code='t'])]">
2905 <name type="corporate">
2906 <xsl:call-template name="nameABCDN"/>
2907 <xsl:call-template name="role"/>
2910 <xsl:for-each select="marc:datafield[@tag='711'][not(marc:subfield[@code='t'])]">
2911 <name type="conference">
2912 <xsl:call-template name="nameACDEQ"/>
2913 <xsl:call-template name="role"/>
2916 <xsl:for-each select="marc:datafield[@tag='720'][not(marc:subfield[@code='t'])]">
2918 <xsl:if test="@ind1=1">
2919 <xsl:attribute name="type">
2920 <xsl:text>personal</xsl:text>
2924 <xsl:value-of select="marc:subfield[@code='a']"/>
2926 <xsl:call-template name="role"/>
2930 <xsl:if test="$leader7='c'">
2931 <xsl:attribute name="collection">yes</xsl:attribute>
2933 <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
2934 <xsl:attribute name="manuscript">yes</xsl:attribute>
2937 <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
2938 <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
2939 <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
2940 <xsl:when test="$leader6='i'">sound recording-nonmusical</xsl:when>
2941 <xsl:when test="$leader6='j'">sound recording-musical</xsl:when>
2942 <xsl:when test="$leader6='k'">still image</xsl:when>
2943 <xsl:when test="$leader6='g'">moving image</xsl:when>
2944 <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
2945 <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
2946 <xsl:when test="$leader6='p'">mixed material</xsl:when>
2949 <xsl:if test="substring($controlField008,26,1)='d'">
2950 <genre authority="marc">globe</genre>
2952 <xsl:if test="marc:controlfield[@tag='007'][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
2953 <genre authority="marc">remote sensing image</genre>
2955 <xsl:if test="$typeOf008='MP'">
2956 <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"></xsl:variable>
2958 <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']">
2959 <genre authority="marc">map</genre>
2961 <xsl:when test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
2962 <genre authority="marc">atlas</genre>
2966 <xsl:if test="$typeOf008='SE'">
2967 <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"></xsl:variable>
2969 <xsl:when test="$controlField008-21='d'">
2970 <genre authority="marc">database</genre>
2972 <xsl:when test="$controlField008-21='l'">
2973 <genre authority="marc">loose-leaf</genre>
2975 <xsl:when test="$controlField008-21='m'">
2976 <genre authority="marc">series</genre>
2978 <xsl:when test="$controlField008-21='n'">
2979 <genre authority="marc">newspaper</genre>
2981 <xsl:when test="$controlField008-21='p'">
2982 <genre authority="marc">periodical</genre>
2984 <xsl:when test="$controlField008-21='w'">
2985 <genre authority="marc">web site</genre>
2989 <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
2990 <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"></xsl:variable>
2992 <xsl:when test="contains($controlField008-24,'a')">
2993 <genre authority="marc">abstract or summary</genre>
2995 <xsl:when test="contains($controlField008-24,'b')">
2996 <genre authority="marc">bibliography</genre>
2998 <xsl:when test="contains($controlField008-24,'c')">
2999 <genre authority="marc">catalog</genre>
3001 <xsl:when test="contains($controlField008-24,'d')">
3002 <genre authority="marc">dictionary</genre>
3004 <xsl:when test="contains($controlField008-24,'e')">
3005 <genre authority="marc">encyclopedia</genre>
3007 <xsl:when test="contains($controlField008-24,'f')">
3008 <genre authority="marc">handbook</genre>
3010 <xsl:when test="contains($controlField008-24,'g')">
3011 <genre authority="marc">legal article</genre>
3013 <xsl:when test="contains($controlField008-24,'i')">
3014 <genre authority="marc">index</genre>
3016 <xsl:when test="contains($controlField008-24,'k')">
3017 <genre authority="marc">discography</genre>
3019 <xsl:when test="contains($controlField008-24,'l')">
3020 <genre authority="marc">legislation</genre>
3022 <xsl:when test="contains($controlField008-24,'m')">
3023 <genre authority="marc">theses</genre>
3025 <xsl:when test="contains($controlField008-24,'n')">
3026 <genre authority="marc">survey of literature</genre>
3028 <xsl:when test="contains($controlField008-24,'o')">
3029 <genre authority="marc">review</genre>
3031 <xsl:when test="contains($controlField008-24,'p')">
3032 <genre authority="marc">programmed text</genre>
3034 <xsl:when test="contains($controlField008-24,'q')">
3035 <genre authority="marc">filmography</genre>
3037 <xsl:when test="contains($controlField008-24,'r')">
3038 <genre authority="marc">directory</genre>
3040 <xsl:when test="contains($controlField008-24,'s')">
3041 <genre authority="marc">statistics</genre>
3043 <xsl:when test="contains($controlField008-24,'t')">
3044 <genre authority="marc">technical report</genre>
3046 <xsl:when test="contains($controlField008-24,'v')">
3047 <genre authority="marc">legal case and case notes</genre>
3049 <xsl:when test="contains($controlField008-24,'w')">
3050 <genre authority="marc">law report or digest</genre>
3052 <xsl:when test="contains($controlField008-24,'z')">
3053 <genre authority="marc">treaty</genre>
3056 <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
3058 <xsl:when test="$controlField008-29='1'">
3059 <genre authority="marc">conference publication</genre>
3063 <xsl:if test="$typeOf008='CF'">
3064 <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"></xsl:variable>
3066 <xsl:when test="$controlField008-26='a'">
3067 <genre authority="marc">numeric data</genre>
3069 <xsl:when test="$controlField008-26='e'">
3070 <genre authority="marc">database</genre>
3072 <xsl:when test="$controlField008-26='f'">
3073 <genre authority="marc">font</genre>
3075 <xsl:when test="$controlField008-26='g'">
3076 <genre authority="marc">game</genre>
3080 <xsl:if test="$typeOf008='BK'">
3081 <xsl:if test="substring($controlField008,25,1)='j'">
3082 <genre authority="marc">patent</genre>
3084 <xsl:if test="substring($controlField008,31,1)='1'">
3085 <genre authority="marc">festschrift</genre>
3087 <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"></xsl:variable>
3088 <xsl:if test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
3089 <genre authority="marc">biography</genre>
3091 <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
3093 <xsl:when test="$controlField008-33='e'">
3094 <genre authority="marc">essay</genre>
3096 <xsl:when test="$controlField008-33='d'">
3097 <genre authority="marc">drama</genre>
3099 <xsl:when test="$controlField008-33='c'">
3100 <genre authority="marc">comic strip</genre>
3102 <xsl:when test="$controlField008-33='l'">
3103 <genre authority="marc">fiction</genre>
3105 <xsl:when test="$controlField008-33='h'">
3106 <genre authority="marc">humor, satire</genre>
3108 <xsl:when test="$controlField008-33='i'">
3109 <genre authority="marc">letter</genre>
3111 <xsl:when test="$controlField008-33='f'">
3112 <genre authority="marc">novel</genre>
3114 <xsl:when test="$controlField008-33='j'">
3115 <genre authority="marc">short story</genre>
3117 <xsl:when test="$controlField008-33='s'">
3118 <genre authority="marc">speech</genre>
3122 <xsl:if test="$typeOf008='MU'">
3123 <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"></xsl:variable>
3124 <xsl:if test="contains($controlField008-30-31,'b')">
3125 <genre authority="marc">biography</genre>
3127 <xsl:if test="contains($controlField008-30-31,'c')">
3128 <genre authority="marc">conference publication</genre>
3130 <xsl:if test="contains($controlField008-30-31,'d')">
3131 <genre authority="marc">drama</genre>
3133 <xsl:if test="contains($controlField008-30-31,'e')">
3134 <genre authority="marc">essay</genre>
3136 <xsl:if test="contains($controlField008-30-31,'f')">
3137 <genre authority="marc">fiction</genre>
3139 <xsl:if test="contains($controlField008-30-31,'o')">
3140 <genre authority="marc">folktale</genre>
3142 <xsl:if test="contains($controlField008-30-31,'h')">
3143 <genre authority="marc">history</genre>
3145 <xsl:if test="contains($controlField008-30-31,'k')">
3146 <genre authority="marc">humor, satire</genre>
3148 <xsl:if test="contains($controlField008-30-31,'m')">
3149 <genre authority="marc">memoir</genre>
3151 <xsl:if test="contains($controlField008-30-31,'p')">
3152 <genre authority="marc">poetry</genre>
3154 <xsl:if test="contains($controlField008-30-31,'r')">
3155 <genre authority="marc">rehearsal</genre>
3157 <xsl:if test="contains($controlField008-30-31,'g')">
3158 <genre authority="marc">reporting</genre>
3160 <xsl:if test="contains($controlField008-30-31,'s')">
3161 <genre authority="marc">sound</genre>
3163 <xsl:if test="contains($controlField008-30-31,'l')">
3164 <genre authority="marc">speech</genre>
3167 <xsl:if test="$typeOf008='VM'">
3168 <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
3170 <xsl:when test="$controlField008-33='a'">
3171 <genre authority="marc">art original</genre>
3173 <xsl:when test="$controlField008-33='b'">
3174 <genre authority="marc">kit</genre>
3176 <xsl:when test="$controlField008-33='c'">
3177 <genre authority="marc">art reproduction</genre>
3179 <xsl:when test="$controlField008-33='d'">
3180 <genre authority="marc">diorama</genre>
3182 <xsl:when test="$controlField008-33='f'">
3183 <genre authority="marc">filmstrip</genre>
3185 <xsl:when test="$controlField008-33='g'">
3186 <genre authority="marc">legal article</genre>
3188 <xsl:when test="$controlField008-33='i'">
3189 <genre authority="marc">picture</genre>
3191 <xsl:when test="$controlField008-33='k'">
3192 <genre authority="marc">graphic</genre>
3194 <xsl:when test="$controlField008-33='l'">
3195 <genre authority="marc">technical drawing</genre>
3197 <xsl:when test="$controlField008-33='m'">
3198 <genre authority="marc">motion picture</genre>
3200 <xsl:when test="$controlField008-33='n'">
3201 <genre authority="marc">chart</genre>
3203 <xsl:when test="$controlField008-33='o'">
3204 <genre authority="marc">flash card</genre>
3206 <xsl:when test="$controlField008-33='p'">
3207 <genre authority="marc">microscope slide</genre>
3209 <xsl:when test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
3210 <genre authority="marc">model</genre>
3212 <xsl:when test="$controlField008-33='r'">
3213 <genre authority="marc">realia</genre>
3215 <xsl:when test="$controlField008-33='s'">
3216 <genre authority="marc">slide</genre>
3218 <xsl:when test="$controlField008-33='t'">
3219 <genre authority="marc">transparency</genre>
3221 <xsl:when test="$controlField008-33='v'">
3222 <genre authority="marc">videorecording</genre>
3224 <xsl:when test="$controlField008-33='w'">
3225 <genre authority="marc">toy</genre>
3229 <xsl:for-each select="marc:datafield[@tag=655]">
3230 <genre authority="marc">
3231 <xsl:attribute name="authority">
3232 <xsl:value-of select="marc:subfield[@code='2']"/>
3234 <xsl:call-template name="subfieldSelect">
3235 <xsl:with-param name="codes">abvxyz</xsl:with-param>
3236 <xsl:with-param name="delimeter">-</xsl:with-param>
3237 </xsl:call-template>
3241 <xsl:variable name="MARCpublicationCode" select="normalize-space(substring($controlField008,16,3))"></xsl:variable>
3242 <xsl:if test="translate($MARCpublicationCode,'|','')">
3245 <xsl:attribute name="type">code</xsl:attribute>
3246 <xsl:attribute name="authority">marccountry</xsl:attribute>
3247 <xsl:value-of select="$MARCpublicationCode"/>
3251 <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
3254 <xsl:attribute name="type">code</xsl:attribute>
3255 <xsl:attribute name="authority">iso3166</xsl:attribute>
3256 <xsl:value-of select="."/>
3260 <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
3263 <xsl:attribute name="type">text</xsl:attribute>
3264 <xsl:call-template name="chopPunctuationFront">
3265 <xsl:with-param name="chopString">
3266 <xsl:call-template name="chopPunctuation">
3267 <xsl:with-param name="chopString" select="."/>
3268 </xsl:call-template>
3270 </xsl:call-template>
3274 <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
3275 <dateValid point="start">
3276 <xsl:value-of select="."/>
3279 <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
3280 <dateValid point="end">
3281 <xsl:value-of select="."/>
3284 <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
3286 <xsl:value-of select="."/>
3289 <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
3291 <xsl:when test="@code='b'">
3293 <xsl:call-template name="chopPunctuation">
3294 <xsl:with-param name="chopString" select="."/>
3295 <xsl:with-param name="punctuation">
3296 <xsl:text>:,;/ </xsl:text>
3298 </xsl:call-template>
3301 <xsl:when test="@code='c'">
3303 <xsl:call-template name="chopPunctuation">
3304 <xsl:with-param name="chopString" select="."/>
3305 </xsl:call-template>
3308 <xsl:when test="@code='g'">
3310 <xsl:value-of select="."/>
3315 <xsl:variable name="dataField260c">
3316 <xsl:call-template name="chopPunctuation">
3317 <xsl:with-param name="chopString" select="marc:datafield[@tag=260]/marc:subfield[@code='c']"></xsl:with-param>
3318 </xsl:call-template>
3320 <xsl:variable name="controlField008-7-10" select="normalize-space(substring($controlField008, 8, 4))"></xsl:variable>
3321 <xsl:variable name="controlField008-11-14" select="normalize-space(substring($controlField008, 12, 4))"></xsl:variable>
3322 <xsl:variable name="controlField008-6" select="normalize-space(substring($controlField008, 7, 1))"></xsl:variable>
3323 <xsl:if test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">
3324 <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">
3325 <dateIssued encoding="marc">
3326 <xsl:value-of select="$controlField008-7-10"/>
3330 <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'">
3331 <xsl:if test="$controlField008-7-10">
3332 <dateIssued encoding="marc" point="start">
3333 <xsl:value-of select="$controlField008-7-10"/>
3337 <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'">
3338 <xsl:if test="$controlField008-11-14">
3339 <dateIssued encoding="marc" point="end">
3340 <xsl:value-of select="$controlField008-11-14"/>
3344 <xsl:if test="$controlField008-6='q'">
3345 <xsl:if test="$controlField008-7-10">
3346 <dateIssued encoding="marc" point="start" qualifier="questionable">
3347 <xsl:value-of select="$controlField008-7-10"/>
3351 <xsl:if test="$controlField008-6='q'">
3352 <xsl:if test="$controlField008-11-14">
3353 <dateIssued encoding="marc" point="end" qualifier="questionable">
3354 <xsl:value-of select="$controlField008-11-14"/>
3358 <xsl:if test="$controlField008-6='t'">
3359 <xsl:if test="$controlField008-11-14">
3360 <copyrightDate encoding="marc">
3361 <xsl:value-of select="$controlField008-11-14"/>
3365 <xsl:for-each select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">
3366 <dateCaptured encoding="iso8601">
3367 <xsl:value-of select="."/>
3370 <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">
3371 <dateCaptured encoding="iso8601" point="start">
3372 <xsl:value-of select="."/>
3375 <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">
3376 <dateCaptured encoding="iso8601" point="end">
3377 <xsl:value-of select="."/>
3380 <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
3382 <xsl:value-of select="."/>
3385 <xsl:for-each select="marc:leader">
3388 <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">monographic</xsl:when>
3389 <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">continuing</xsl:when>
3393 <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
3395 <xsl:call-template name="subfieldSelect">
3396 <xsl:with-param name="codes">ab</xsl:with-param>
3397 </xsl:call-template>
3401 <xsl:variable name="controlField008-35-37" select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"></xsl:variable>
3402 <xsl:if test="$controlField008-35-37">
3404 <languageTerm authority="iso639-2b" type="code">
3405 <xsl:value-of select="substring($controlField008,36,3)"/>
3409 <xsl:for-each select="marc:datafield[@tag=041]">
3410 <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']">
3411 <xsl:variable name="langCodes" select="."/>
3413 <xsl:when test="../marc:subfield[@code='2']='rfc3066'">
3414 <!-- not stacked but could be repeated -->
3415 <xsl:call-template name="rfcLanguages">
3416 <xsl:with-param name="nodeNum">
3417 <xsl:value-of select="1"/>
3419 <xsl:with-param name="usedLanguages">
3420 <xsl:text></xsl:text>
3422 <xsl:with-param name="controlField008-35-37">
3423 <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
3425 </xsl:call-template>
3429 <xsl:variable name="allLanguages">
3430 <xsl:copy-of select="$langCodes"></xsl:copy-of>
3432 <xsl:variable name="currentLanguage">
3433 <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
3435 <xsl:call-template name="isoLanguage">
3436 <xsl:with-param name="currentLanguage">
3437 <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
3439 <xsl:with-param name="remainingLanguages">
3440 <xsl:value-of select="substring($allLanguages,4,string-length($allLanguages)-3)"></xsl:value-of>
3442 <xsl:with-param name="usedLanguages">
3443 <xsl:if test="$controlField008-35-37">
3444 <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
3447 </xsl:call-template>
3452 <xsl:variable name="physicalDescription">
3453 <!--3.2 change tmee 007/11 -->
3454 <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a']">
3455 <digitalOrigin>reformatted digital</digitalOrigin>
3457 <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='b']">
3458 <digitalOrigin>digitized microfilm</digitalOrigin>
3460 <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='d']">
3461 <digitalOrigin>digitized other analog</digitalOrigin>
3463 <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"></xsl:variable>
3464 <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
3465 <xsl:variable name="check008-23">
3466 <xsl:if test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">
3467 <xsl:value-of select="true()"></xsl:value-of>
3470 <xsl:variable name="check008-29">
3471 <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
3472 <xsl:value-of select="true()"></xsl:value-of>
3476 <xsl:when test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
3477 <form authority="marcform">braille</form>
3479 <xsl:when test="($controlField008-23=' ' and ($leader6='c' or $leader6='d')) or (($typeOf008='BK' or $typeOf008='SE') and ($controlField008-23=' ' or $controlField008='r'))">
3480 <form authority="marcform">print</form>
3482 <xsl:when test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">
3483 <form authority="marcform">electronic</form>
3485 <xsl:when test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
3486 <form authority="marcform">microfiche</form>
3488 <xsl:when test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
3489 <form authority="marcform">microfilm</form>
3493 <xsl:if test="marc:datafield[@tag=130]/marc:subfield[@code='h']">
3494 <form authority="gmd">
3495 <xsl:call-template name="chopBrackets">
3496 <xsl:with-param name="chopString">
3497 <xsl:value-of select="marc:datafield[@tag=130]/marc:subfield[@code='h']"></xsl:value-of>
3499 </xsl:call-template>
3502 <xsl:if test="marc:datafield[@tag=240]/marc:subfield[@code='h']">
3503 <form authority="gmd">
3504 <xsl:call-template name="chopBrackets">
3505 <xsl:with-param name="chopString">
3506 <xsl:value-of select="marc:datafield[@tag=240]/marc:subfield[@code='h']"></xsl:value-of>
3508 </xsl:call-template>
3511 <xsl:if test="marc:datafield[@tag=242]/marc:subfield[@code='h']">
3512 <form authority="gmd">
3513 <xsl:call-template name="chopBrackets">
3514 <xsl:with-param name="chopString">
3515 <xsl:value-of select="marc:datafield[@tag=242]/marc:subfield[@code='h']"></xsl:value-of>
3517 </xsl:call-template>
3520 <xsl:if test="marc:datafield[@tag=245]/marc:subfield[@code='h']">
3521 <form authority="gmd">
3522 <xsl:call-template name="chopBrackets">
3523 <xsl:with-param name="chopString">
3524 <xsl:value-of select="marc:datafield[@tag=245]/marc:subfield[@code='h']"></xsl:value-of>
3526 </xsl:call-template>
3529 <xsl:if test="marc:datafield[@tag=246]/marc:subfield[@code='h']">
3530 <form authority="gmd">
3531 <xsl:call-template name="chopBrackets">
3532 <xsl:with-param name="chopString">
3533 <xsl:value-of select="marc:datafield[@tag=246]/marc:subfield[@code='h']"></xsl:value-of>
3535 </xsl:call-template>
3538 <xsl:if test="marc:datafield[@tag=730]/marc:subfield[@code='h']">
3539 <form authority="gmd">
3540 <xsl:call-template name="chopBrackets">
3541 <xsl:with-param name="chopString">
3542 <xsl:value-of select="marc:datafield[@tag=730]/marc:subfield[@code='h']"></xsl:value-of>
3544 </xsl:call-template>
3547 <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
3549 <xsl:value-of select="."></xsl:value-of>
3552 <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
3554 <xsl:when test="substring(text(),14,1)='a'">
3555 <reformattingQuality>access</reformattingQuality>
3557 <xsl:when test="substring(text(),14,1)='p'">
3558 <reformattingQuality>preservation</reformattingQuality>
3560 <xsl:when test="substring(text(),14,1)='r'">
3561 <reformattingQuality>replacement</reformattingQuality>
3565 <!--3.2 change tmee 007/01 -->
3566 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='b']">
3567 <form authority="smd">chip cartridge</form>
3569 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='c']">
3570 <form authority="smd">computer optical disc cartridge</form>
3572 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='j']">
3573 <form authority="smd">magnetic disc</form>
3575 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='m']">
3576 <form authority="smd">magneto-optical disc</form>
3578 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='o']">
3579 <form authority="smd">optical disc</form>
3581 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='r']">
3582 <form authority="smd">remote</form>
3584 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='a']">
3585 <form authority="smd">tape cartridge</form>
3587 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='f']">
3588 <form authority="smd">tape cassette</form>
3590 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='h']">
3591 <form authority="smd">tape reel</form>
3594 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='a']">
3595 <form authority="smd">celestial globe</form>
3597 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='e']">
3598 <form authority="smd">earth moon globe</form>
3600 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='b']">
3601 <form authority="smd">planetary or lunar globe</form>
3603 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='c']">
3604 <form authority="smd">terrestrial globe</form>
3607 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='o'][substring(text(),2,1)='o']">
3608 <form authority="smd">kit</form>
3611 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
3612 <form authority="smd">atlas</form>
3614 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='g']">
3615 <form authority="smd">diagram</form>
3617 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
3618 <form authority="smd">map</form>
3620 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
3621 <form authority="smd">model</form>
3623 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='k']">
3624 <form authority="smd">profile</form>
3626 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
3627 <form authority="smd">remote-sensing image</form>
3629 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='s']">
3630 <form authority="smd">section</form>
3632 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='y']">
3633 <form authority="smd">view</form>
3636 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='a']">
3637 <form authority="smd">aperture card</form>
3639 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='e']">
3640 <form authority="smd">microfiche</form>
3642 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='f']">
3643 <form authority="smd">microfiche cassette</form>
3645 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='b']">
3646 <form authority="smd">microfilm cartridge</form>
3648 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='c']">
3649 <form authority="smd">microfilm cassette</form>
3651 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='d']">
3652 <form authority="smd">microfilm reel</form>
3654 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='g']">
3655 <form authority="smd">microopaque</form>
3658 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='c']">
3659 <form authority="smd">film cartridge</form>
3661 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='f']">
3662 <form authority="smd">film cassette</form>
3664 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='r']">
3665 <form authority="smd">film reel</form>
3668 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='n']">
3669 <form authority="smd">chart</form>
3671 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='c']">
3672 <form authority="smd">collage</form>
3674 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='d']">
3675 <form authority="smd">drawing</form>
3677 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='o']">
3678 <form authority="smd">flash card</form>
3680 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='e']">
3681 <form authority="smd">painting</form>
3683 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='f']">
3684 <form authority="smd">photomechanical print</form>
3686 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='g']">
3687 <form authority="smd">photonegative</form>
3689 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='h']">
3690 <form authority="smd">photoprint</form>
3692 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='i']">
3693 <form authority="smd">picture</form>
3695 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='j']">
3696 <form authority="smd">print</form>
3698 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='l']">
3699 <form authority="smd">technical drawing</form>
3702 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='q'][substring(text(),2,1)='q']">
3703 <form authority="smd">notated music</form>
3706 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='d']">
3707 <form authority="smd">filmslip</form>
3709 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='c']">
3710 <form authority="smd">filmstrip cartridge</form>
3712 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='o']">
3713 <form authority="smd">filmstrip roll</form>
3715 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='f']">
3716 <form authority="smd">other filmstrip type</form>
3718 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='s']">
3719 <form authority="smd">slide</form>
3721 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='t']">
3722 <form authority="smd">transparency</form>
3724 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='r'][substring(text(),2,1)='r']">
3725 <form authority="smd">remote-sensing image</form>
3727 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='e']">
3728 <form authority="smd">cylinder</form>
3730 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='q']">
3731 <form authority="smd">roll</form>
3733 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='g']">
3734 <form authority="smd">sound cartridge</form>
3736 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='s']">
3737 <form authority="smd">sound cassette</form>
3739 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='d']">
3740 <form authority="smd">sound disc</form>
3742 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='t']">
3743 <form authority="smd">sound-tape reel</form>
3745 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='i']">
3746 <form authority="smd">sound-track film</form>
3748 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='w']">
3749 <form authority="smd">wire recording</form>
3752 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='c']">
3753 <form authority="smd">braille</form>
3755 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='b']">
3756 <form authority="smd">combination</form>
3758 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='a']">
3759 <form authority="smd">moon</form>
3761 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='d']">
3762 <form authority="smd">tactile, with no writing system</form>
3765 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='c']">
3766 <form authority="smd">braille</form>
3768 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='b']">
3769 <form authority="smd">large print</form>
3771 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='a']">
3772 <form authority="smd">regular print</form>
3774 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='d']">
3775 <form authority="smd">text in looseleaf binder</form>
3778 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='c']">
3779 <form authority="smd">videocartridge</form>
3781 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='f']">
3782 <form authority="smd">videocassette</form>
3784 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='d']">
3785 <form authority="smd">videodisc</form>
3787 <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='r']">
3788 <form authority="smd">videoreel</form>
3791 <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">
3793 <xsl:value-of select="."></xsl:value-of>
3794 </internetMediaType>
3796 <xsl:for-each select="marc:datafield[@tag=300]">
3798 <xsl:call-template name="subfieldSelect">
3799 <xsl:with-param name="codes">abce</xsl:with-param>
3800 </xsl:call-template>
3804 <xsl:if test="string-length(normalize-space($physicalDescription))">
3805 <physicalDescription>
3806 <xsl:copy-of select="$physicalDescription"></xsl:copy-of>
3807 </physicalDescription>
3809 <xsl:for-each select="marc:datafield[@tag=520]">
3811 <xsl:call-template name="uri"></xsl:call-template>
3812 <xsl:call-template name="subfieldSelect">
3813 <xsl:with-param name="codes">ab</xsl:with-param>
3814 </xsl:call-template>
3817 <xsl:for-each select="marc:datafield[@tag=505]">
3819 <xsl:call-template name="uri"></xsl:call-template>
3820 <xsl:call-template name="subfieldSelect">
3821 <xsl:with-param name="codes">agrt</xsl:with-param>
3822 </xsl:call-template>
3825 <xsl:for-each select="marc:datafield[@tag=521]">
3827 <xsl:call-template name="subfieldSelect">
3828 <xsl:with-param name="codes">ab</xsl:with-param>
3829 </xsl:call-template>
3832 <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">
3833 <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"></xsl:variable>
3836 <xsl:when test="$controlField008-22='d'">
3837 <targetAudience authority="marctarget">adolescent</targetAudience>
3839 <xsl:when test="$controlField008-22='e'">
3840 <targetAudience authority="marctarget">adult</targetAudience>
3842 <xsl:when test="$controlField008-22='g'">
3843 <targetAudience authority="marctarget">general</targetAudience>
3845 <xsl:when test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
3846 <targetAudience authority="marctarget">juvenile</targetAudience>
3848 <xsl:when test="$controlField008-22='a'">
3849 <targetAudience authority="marctarget">preschool</targetAudience>
3851 <xsl:when test="$controlField008-22='f'">
3852 <targetAudience authority="marctarget">specialized</targetAudience>
3856 <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">
3857 <note type="statement of responsibility">
3858 <xsl:value-of select="."></xsl:value-of>
3861 <xsl:for-each select="marc:datafield[@tag=500]">
3863 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
3864 <xsl:call-template name="uri"></xsl:call-template>
3868 <!--3.2 change tmee additional note fields-->
3870 <xsl:for-each select="marc:datafield[@tag=506]">
3871 <note type="restrictions">
3872 <xsl:call-template name="uri"></xsl:call-template>
3873 <xsl:variable name="str">
3874 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3875 <xsl:value-of select="."></xsl:value-of>
3876 <xsl:text> </xsl:text>
3879 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3883 <xsl:for-each select="marc:datafield[@tag=510]">
3884 <note type="citation/reference">
3885 <xsl:call-template name="uri"></xsl:call-template>
3886 <xsl:variable name="str">
3887 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3888 <xsl:value-of select="."></xsl:value-of>
3889 <xsl:text> </xsl:text>
3892 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3897 <xsl:for-each select="marc:datafield[@tag=511]">
3898 <note type="performers">
3899 <xsl:call-template name="uri"></xsl:call-template>
3900 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
3903 <xsl:for-each select="marc:datafield[@tag=518]">
3905 <xsl:call-template name="uri"></xsl:call-template>
3906 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
3910 <xsl:for-each select="marc:datafield[@tag=530]">
3911 <note type="additional physical form">
3912 <xsl:call-template name="uri"></xsl:call-template>
3913 <xsl:variable name="str">
3914 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3915 <xsl:value-of select="."></xsl:value-of>
3916 <xsl:text> </xsl:text>
3919 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3923 <xsl:for-each select="marc:datafield[@tag=533]">
3924 <note type="reproduction">
3925 <xsl:call-template name="uri"></xsl:call-template>
3926 <xsl:variable name="str">
3927 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3928 <xsl:value-of select="."></xsl:value-of>
3929 <xsl:text> </xsl:text>
3932 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3936 <xsl:for-each select="marc:datafield[@tag=534]">
3937 <note type="original version">
3938 <xsl:call-template name="uri"></xsl:call-template>
3939 <xsl:variable name="str">
3940 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3941 <xsl:value-of select="."></xsl:value-of>
3942 <xsl:text> </xsl:text>
3945 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3949 <xsl:for-each select="marc:datafield[@tag=538]">
3950 <note type="system details">
3951 <xsl:call-template name="uri"></xsl:call-template>
3952 <xsl:variable name="str">
3953 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3954 <xsl:value-of select="."></xsl:value-of>
3955 <xsl:text> </xsl:text>
3958 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3962 <xsl:for-each select="marc:datafield[@tag=583]">
3963 <note type="action">
3964 <xsl:call-template name="uri"></xsl:call-template>
3965 <xsl:variable name="str">
3966 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3967 <xsl:value-of select="."></xsl:value-of>
3968 <xsl:text> </xsl:text>
3971 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3979 <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]">
3981 <xsl:call-template name="uri"></xsl:call-template>
3982 <xsl:variable name="str">
3983 <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
3984 <xsl:value-of select="."></xsl:value-of>
3985 <xsl:text> </xsl:text>
3988 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3991 <xsl:for-each select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
3995 <xsl:call-template name="subfieldSelect">
3996 <xsl:with-param name="codes">defg</xsl:with-param>
3997 </xsl:call-template>
4002 <xsl:for-each select="marc:datafield[@tag=043]">
4004 <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
4006 <xsl:attribute name="authority">
4007 <xsl:if test="@code='a'">
4008 <xsl:text>marcgac</xsl:text>
4010 <xsl:if test="@code='b'">
4011 <xsl:value-of select="following-sibling::marc:subfield[@code=2]"></xsl:value-of>
4013 <xsl:if test="@code='c'">
4014 <xsl:text>iso3166</xsl:text>
4017 <xsl:value-of select="self::marc:subfield"></xsl:value-of>
4022 <!-- tmee 2006/11/27 -->
4023 <xsl:for-each select="marc:datafield[@tag=255]">
4025 <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
4027 <xsl:if test="@code='a'">
4029 <xsl:value-of select="."></xsl:value-of>
4032 <xsl:if test="@code='b'">
4034 <xsl:value-of select="."></xsl:value-of>
4037 <xsl:if test="@code='c'">
4039 <xsl:value-of select="."></xsl:value-of>
4047 <xsl:apply-templates select="marc:datafield[653 >= @tag and @tag >= 600]"></xsl:apply-templates>
4048 <xsl:apply-templates select="marc:datafield[@tag=656]"></xsl:apply-templates>
4049 <xsl:for-each select="marc:datafield[@tag=752]">
4051 <hierarchicalGeographic>
4052 <xsl:for-each select="marc:subfield[@code='a']">
4054 <xsl:call-template name="chopPunctuation">
4055 <xsl:with-param name="chopString" select="."></xsl:with-param>
4056 </xsl:call-template>
4059 <xsl:for-each select="marc:subfield[@code='b']">
4061 <xsl:call-template name="chopPunctuation">
4062 <xsl:with-param name="chopString" select="."></xsl:with-param>
4063 </xsl:call-template>
4066 <xsl:for-each select="marc:subfield[@code='c']">
4068 <xsl:call-template name="chopPunctuation">
4069 <xsl:with-param name="chopString" select="."></xsl:with-param>
4070 </xsl:call-template>
4073 <xsl:for-each select="marc:subfield[@code='d']">
4075 <xsl:call-template name="chopPunctuation">
4076 <xsl:with-param name="chopString" select="."></xsl:with-param>
4077 </xsl:call-template>
4080 </hierarchicalGeographic>
4083 <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
4086 <xsl:when test="@ind1=2">
4087 <temporal encoding="iso8601" point="start">
4088 <xsl:call-template name="chopPunctuation">
4089 <xsl:with-param name="chopString">
4090 <xsl:value-of select="marc:subfield[@code='b'][1]"></xsl:value-of>
4092 </xsl:call-template>
4094 <temporal encoding="iso8601" point="end">
4095 <xsl:call-template name="chopPunctuation">
4096 <xsl:with-param name="chopString">
4097 <xsl:value-of select="marc:subfield[@code='b'][2]"></xsl:value-of>
4099 </xsl:call-template>
4103 <xsl:for-each select="marc:subfield[@code='b']">
4104 <temporal encoding="iso8601">
4105 <xsl:call-template name="chopPunctuation">
4106 <xsl:with-param name="chopString" select="."></xsl:with-param>
4107 </xsl:call-template>
4114 <xsl:for-each select="marc:datafield[@tag=050]">
4115 <xsl:for-each select="marc:subfield[@code='b']">
4116 <classification authority="lcc">
4117 <xsl:if test="../marc:subfield[@code='3']">
4118 <xsl:attribute name="displayLabel">
4119 <xsl:value-of select="../marc:subfield[@code='3']"></xsl:value-of>
4122 <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"></xsl:value-of>
4123 <xsl:text> </xsl:text>
4124 <xsl:value-of select="text()"></xsl:value-of>
4127 <xsl:for-each select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">
4128 <classification authority="lcc">
4129 <xsl:if test="../marc:subfield[@code='3']">
4130 <xsl:attribute name="displayLabel">
4131 <xsl:value-of select="../marc:subfield[@code='3']"></xsl:value-of>
4134 <xsl:value-of select="text()"></xsl:value-of>
4138 <xsl:for-each select="marc:datafield[@tag=082]">
4139 <classification authority="ddc">
4140 <xsl:if test="marc:subfield[@code='2']">
4141 <xsl:attribute name="edition">
4142 <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
4145 <xsl:call-template name="subfieldSelect">
4146 <xsl:with-param name="codes">ab</xsl:with-param>
4147 </xsl:call-template>
4150 <xsl:for-each select="marc:datafield[@tag=080]">
4151 <classification authority="udc">
4152 <xsl:call-template name="subfieldSelect">
4153 <xsl:with-param name="codes">abx</xsl:with-param>
4154 </xsl:call-template>
4157 <xsl:for-each select="marc:datafield[@tag=060]">
4158 <classification authority="nlm">
4159 <xsl:call-template name="subfieldSelect">
4160 <xsl:with-param name="codes">ab</xsl:with-param>
4161 </xsl:call-template>
4164 <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">
4165 <classification authority="sudocs">
4166 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4169 <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">
4170 <classification authority="candoc">
4171 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4174 <xsl:for-each select="marc:datafield[@tag=086]">
4176 <xsl:attribute name="authority">
4177 <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
4179 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4182 <xsl:for-each select="marc:datafield[@tag=084]">
4184 <xsl:attribute name="authority">
4185 <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
4187 <xsl:call-template name="subfieldSelect">
4188 <xsl:with-param name="codes">ab</xsl:with-param>
4189 </xsl:call-template>
4192 <xsl:for-each select="marc:datafield[@tag=440]">
4193 <relatedItem type="series">
4196 <xsl:call-template name="chopPunctuation">
4197 <xsl:with-param name="chopString">
4198 <xsl:call-template name="subfieldSelect">
4199 <xsl:with-param name="codes">av</xsl:with-param>
4200 </xsl:call-template>
4202 </xsl:call-template>
4204 <xsl:call-template name="part"></xsl:call-template>
4208 <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
4209 <relatedItem type="series">
4212 <xsl:call-template name="chopPunctuation">
4213 <xsl:with-param name="chopString">
4214 <xsl:call-template name="subfieldSelect">
4215 <xsl:with-param name="codes">av</xsl:with-param>
4216 </xsl:call-template>
4218 </xsl:call-template>
4220 <xsl:call-template name="part"></xsl:call-template>
4224 <xsl:for-each select="marc:datafield[@tag=510]">
4225 <relatedItem type="isReferencedBy">
4227 <xsl:call-template name="subfieldSelect">
4228 <xsl:with-param name="codes">abcx3</xsl:with-param>
4229 </xsl:call-template>
4233 <xsl:for-each select="marc:datafield[@tag=534]">
4234 <relatedItem type="original">
4235 <xsl:call-template name="relatedTitle"></xsl:call-template>
4236 <xsl:call-template name="relatedName"></xsl:call-template>
4237 <xsl:if test="marc:subfield[@code='b' or @code='c']">
4239 <xsl:for-each select="marc:subfield[@code='c']">
4241 <xsl:value-of select="."></xsl:value-of>
4244 <xsl:for-each select="marc:subfield[@code='b']">
4246 <xsl:value-of select="."></xsl:value-of>
4251 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4252 <xsl:for-each select="marc:subfield[@code='z']">
4253 <identifier type="isbn">
4254 <xsl:value-of select="."></xsl:value-of>
4257 <xsl:call-template name="relatedNote"></xsl:call-template>
4260 <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
4262 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4265 <xsl:call-template name="chopPunctuation">
4266 <xsl:with-param name="chopString">
4267 <xsl:call-template name="specialSubfieldSelect">
4268 <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
4269 <xsl:with-param name="axis">t</xsl:with-param>
4270 <xsl:with-param name="afterCodes">g</xsl:with-param>
4271 </xsl:call-template>
4273 </xsl:call-template>
4275 <xsl:call-template name="part"></xsl:call-template>
4277 <name type="personal">
4279 <xsl:call-template name="specialSubfieldSelect">
4280 <xsl:with-param name="anyCodes">aq</xsl:with-param>
4281 <xsl:with-param name="axis">t</xsl:with-param>
4282 <xsl:with-param name="beforeCodes">g</xsl:with-param>
4283 </xsl:call-template>
4285 <xsl:call-template name="termsOfAddress"></xsl:call-template>
4286 <xsl:call-template name="nameDate"></xsl:call-template>
4287 <xsl:call-template name="role"></xsl:call-template>
4289 <xsl:call-template name="relatedForm"></xsl:call-template>
4290 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4293 <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
4295 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4298 <xsl:call-template name="chopPunctuation">
4299 <xsl:with-param name="chopString">
4300 <xsl:call-template name="specialSubfieldSelect">
4301 <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
4302 <xsl:with-param name="axis">t</xsl:with-param>
4303 <xsl:with-param name="afterCodes">dg</xsl:with-param>
4304 </xsl:call-template>
4306 </xsl:call-template>
4308 <xsl:call-template name="relatedPartNumName"></xsl:call-template>
4310 <name type="corporate">
4311 <xsl:for-each select="marc:subfield[@code='a']">
4313 <xsl:value-of select="."></xsl:value-of>
4316 <xsl:for-each select="marc:subfield[@code='b']">
4318 <xsl:value-of select="."></xsl:value-of>
4321 <xsl:variable name="tempNamePart">
4322 <xsl:call-template name="specialSubfieldSelect">
4323 <xsl:with-param name="anyCodes">c</xsl:with-param>
4324 <xsl:with-param name="axis">t</xsl:with-param>
4325 <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
4326 </xsl:call-template>
4328 <xsl:if test="normalize-space($tempNamePart)">
4330 <xsl:value-of select="$tempNamePart"></xsl:value-of>
4333 <xsl:call-template name="role"></xsl:call-template>
4335 <xsl:call-template name="relatedForm"></xsl:call-template>
4336 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4339 <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
4341 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4344 <xsl:call-template name="chopPunctuation">
4345 <xsl:with-param name="chopString">
4346 <xsl:call-template name="specialSubfieldSelect">
4347 <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
4348 <xsl:with-param name="axis">t</xsl:with-param>
4349 <xsl:with-param name="afterCodes">g</xsl:with-param>
4350 </xsl:call-template>
4352 </xsl:call-template>
4354 <xsl:call-template name="relatedPartNumName"></xsl:call-template>
4356 <name type="conference">
4358 <xsl:call-template name="specialSubfieldSelect">
4359 <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
4360 <xsl:with-param name="axis">t</xsl:with-param>
4361 <xsl:with-param name="beforeCodes">gn</xsl:with-param>
4362 </xsl:call-template>
4365 <xsl:call-template name="relatedForm"></xsl:call-template>
4366 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4369 <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
4371 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4374 <xsl:call-template name="chopPunctuation">
4375 <xsl:with-param name="chopString">
4376 <xsl:call-template name="subfieldSelect">
4377 <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
4378 </xsl:call-template>
4380 </xsl:call-template>
4382 <xsl:call-template name="part"></xsl:call-template>
4384 <xsl:call-template name="relatedForm"></xsl:call-template>
4385 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4388 <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
4390 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4393 <xsl:call-template name="chopPunctuation">
4394 <xsl:with-param name="chopString">
4395 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4397 </xsl:call-template>
4399 <xsl:call-template name="part"></xsl:call-template>
4401 <xsl:call-template name="relatedForm"></xsl:call-template>
4404 <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">
4405 <relatedItem type="series">
4406 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4409 <xsl:for-each select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
4411 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4414 <xsl:for-each select="marc:datafield[@tag=775]">
4415 <relatedItem type="otherVersion">
4416 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4419 <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">
4420 <relatedItem type="constituent">
4421 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4424 <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">
4425 <relatedItem type="host">
4426 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4429 <xsl:for-each select="marc:datafield[@tag=776]">
4430 <relatedItem type="otherFormat">
4431 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4434 <xsl:for-each select="marc:datafield[@tag=780]">
4435 <relatedItem type="preceding">
4436 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4439 <xsl:for-each select="marc:datafield[@tag=785]">
4440 <relatedItem type="succeeding">
4441 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4444 <xsl:for-each select="marc:datafield[@tag=786]">
4445 <relatedItem type="original">
4446 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4449 <xsl:for-each select="marc:datafield[@tag=800]">
4450 <relatedItem type="series">
4453 <xsl:call-template name="chopPunctuation">
4454 <xsl:with-param name="chopString">
4455 <xsl:call-template name="specialSubfieldSelect">
4456 <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
4457 <xsl:with-param name="axis">t</xsl:with-param>
4458 <xsl:with-param name="afterCodes">g</xsl:with-param>
4459 </xsl:call-template>
4461 </xsl:call-template>
4463 <xsl:call-template name="part"></xsl:call-template>
4465 <name type="personal">
4467 <xsl:call-template name="chopPunctuation">
4468 <xsl:with-param name="chopString">
4469 <xsl:call-template name="specialSubfieldSelect">
4470 <xsl:with-param name="anyCodes">aq</xsl:with-param>
4471 <xsl:with-param name="axis">t</xsl:with-param>
4472 <xsl:with-param name="beforeCodes">g</xsl:with-param>
4473 </xsl:call-template>
4475 </xsl:call-template>
4477 <xsl:call-template name="termsOfAddress"></xsl:call-template>
4478 <xsl:call-template name="nameDate"></xsl:call-template>
4479 <xsl:call-template name="role"></xsl:call-template>
4481 <xsl:call-template name="relatedForm"></xsl:call-template>
4484 <xsl:for-each select="marc:datafield[@tag=810]">
4485 <relatedItem type="series">
4488 <xsl:call-template name="chopPunctuation">
4489 <xsl:with-param name="chopString">
4490 <xsl:call-template name="specialSubfieldSelect">
4491 <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
4492 <xsl:with-param name="axis">t</xsl:with-param>
4493 <xsl:with-param name="afterCodes">dg</xsl:with-param>
4494 </xsl:call-template>
4496 </xsl:call-template>
4498 <xsl:call-template name="relatedPartNumName"></xsl:call-template>
4500 <name type="corporate">
4501 <xsl:for-each select="marc:subfield[@code='a']">
4503 <xsl:value-of select="."></xsl:value-of>
4506 <xsl:for-each select="marc:subfield[@code='b']">
4508 <xsl:value-of select="."></xsl:value-of>
4512 <xsl:call-template name="specialSubfieldSelect">
4513 <xsl:with-param name="anyCodes">c</xsl:with-param>
4514 <xsl:with-param name="axis">t</xsl:with-param>
4515 <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
4516 </xsl:call-template>
4518 <xsl:call-template name="role"></xsl:call-template>
4520 <xsl:call-template name="relatedForm"></xsl:call-template>
4523 <xsl:for-each select="marc:datafield[@tag=811]">
4524 <relatedItem type="series">
4527 <xsl:call-template name="chopPunctuation">
4528 <xsl:with-param name="chopString">
4529 <xsl:call-template name="specialSubfieldSelect">
4530 <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
4531 <xsl:with-param name="axis">t</xsl:with-param>
4532 <xsl:with-param name="afterCodes">g</xsl:with-param>
4533 </xsl:call-template>
4535 </xsl:call-template>
4537 <xsl:call-template name="relatedPartNumName"/>
4539 <name type="conference">
4541 <xsl:call-template name="specialSubfieldSelect">
4542 <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
4543 <xsl:with-param name="axis">t</xsl:with-param>
4544 <xsl:with-param name="beforeCodes">gn</xsl:with-param>
4545 </xsl:call-template>
4547 <xsl:call-template name="role"/>
4549 <xsl:call-template name="relatedForm"/>
4552 <xsl:for-each select="marc:datafield[@tag='830']">
4553 <relatedItem type="series">
4556 <xsl:call-template name="chopPunctuation">
4557 <xsl:with-param name="chopString">
4558 <xsl:call-template name="subfieldSelect">
4559 <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
4560 </xsl:call-template>
4562 </xsl:call-template>
4564 <xsl:call-template name="part"/>
4566 <xsl:call-template name="relatedForm"/>
4569 <xsl:for-each select="marc:datafield[@tag='856'][@ind2='2']/marc:subfield[@code='q']">
4572 <xsl:value-of select="."/>
4573 </internetMediaType>
4576 <xsl:for-each select="marc:datafield[@tag='020']">
4577 <xsl:call-template name="isInvalid">
4578 <xsl:with-param name="type">isbn</xsl:with-param>
4579 </xsl:call-template>
4580 <xsl:if test="marc:subfield[@code='a']">
4581 <identifier type="isbn">
4582 <xsl:value-of select="marc:subfield[@code='a']"/>
4586 <xsl:for-each select="marc:datafield[@tag='024'][@ind1='0']">
4587 <xsl:call-template name="isInvalid">
4588 <xsl:with-param name="type">isrc</xsl:with-param>
4589 </xsl:call-template>
4590 <xsl:if test="marc:subfield[@code='a']">
4591 <identifier type="isrc">
4592 <xsl:value-of select="marc:subfield[@code='a']"/>
4596 <xsl:for-each select="marc:datafield[@tag='024'][@ind1='2']">
4597 <xsl:call-template name="isInvalid">
4598 <xsl:with-param name="type">ismn</xsl:with-param>
4599 </xsl:call-template>
4600 <xsl:if test="marc:subfield[@code='a']">
4601 <identifier type="ismn">
4602 <xsl:value-of select="marc:subfield[@code='a']"/>
4606 <xsl:for-each select="marc:datafield[@tag='024'][@ind1='4']">
4607 <xsl:call-template name="isInvalid">
4608 <xsl:with-param name="type">sici</xsl:with-param>
4609 </xsl:call-template>
4610 <identifier type="sici">
4611 <xsl:call-template name="subfieldSelect">
4612 <xsl:with-param name="codes">ab</xsl:with-param>
4613 </xsl:call-template>
4616 <xsl:for-each select="marc:datafield[@tag='022']">
4617 <xsl:call-template name="isInvalid">
4618 <xsl:with-param name="type">issn</xsl:with-param>
4619 </xsl:call-template>
4620 <identifier type="issn">
4621 <xsl:value-of select="marc:subfield[@code='a']"/>
4624 <xsl:for-each select="marc:datafield[@tag='010']">
4625 <xsl:call-template name="isInvalid">
4626 <xsl:with-param name="type">lccn</xsl:with-param>
4627 </xsl:call-template>
4628 <identifier type="lccn">
4629 <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
4632 <xsl:for-each select="marc:datafield[@tag='028']">
4634 <xsl:attribute name="type">
4636 <xsl:when test="@ind1='0'">issue number</xsl:when>
4637 <xsl:when test="@ind1='1'">matrix number</xsl:when>
4638 <xsl:when test="@ind1='2'">music plate</xsl:when>
4639 <xsl:when test="@ind1='3'">music publisher</xsl:when>
4640 <xsl:when test="@ind1='4'">videorecording identifier</xsl:when>
4643 <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 028 -->
4644 <xsl:call-template name="subfieldSelect">
4645 <xsl:with-param name="codes">
4647 <xsl:when test="@ind1='0'">ba</xsl:when>
4648 <xsl:otherwise>ab</xsl:otherwise>
4651 </xsl:call-template>
4654 <xsl:for-each select="marc:datafield[@tag='037']">
4655 <identifier type="stock number">
4656 <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 037 -->
4657 <xsl:call-template name="subfieldSelect">
4658 <xsl:with-param name="codes">ab</xsl:with-param>
4659 </xsl:call-template>
4662 <xsl:for-each select="marc:datafield[@tag='856'][marc:subfield[@code='u']]">
4664 <xsl:attribute name="type">
4666 <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:doi') or starts-with(marc:subfield[@code='u'],'doi')">doi</xsl:when>
4667 <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>
4668 <xsl:otherwise>uri</xsl:otherwise>
4672 <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') ">
4673 <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
4676 <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
4680 <xsl:if test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl')">
4681 <identifier type="hdl">
4682 <xsl:if test="marc:subfield[@code='y' or @code='3' or @code='z']">
4683 <xsl:attribute name="displayLabel">
4684 <xsl:call-template name="subfieldSelect">
4685 <xsl:with-param name="codes">y3z</xsl:with-param>
4686 </xsl:call-template>
4689 <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
4693 <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]">
4694 <identifier type="upc">
4695 <xsl:call-template name="isInvalid"/>
4696 <xsl:value-of select="marc:subfield[@code='a']"/>
4699 <!-- 1/04 fix added $y -->
4700 <xsl:for-each select="marc:datafield[@tag=856][marc:subfield[@code='u']]">
4703 <xsl:if test="marc:subfield[@code='y' or @code='3']">
4704 <xsl:attribute name="displayLabel">
4705 <xsl:call-template name="subfieldSelect">
4706 <xsl:with-param name="codes">y3</xsl:with-param>
4707 </xsl:call-template>
4710 <xsl:if test="marc:subfield[@code='z' ]">
4711 <xsl:attribute name="note">
4712 <xsl:call-template name="subfieldSelect">
4713 <xsl:with-param name="codes">z</xsl:with-param>
4714 </xsl:call-template>
4717 <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
4723 <!-- 3.2 change tmee 856z -->
4726 <xsl:for-each select="marc:datafield[@tag=852]">
4729 <xsl:call-template name="displayLabel"></xsl:call-template>
4730 <xsl:call-template name="subfieldSelect">
4731 <xsl:with-param name="codes">abje</xsl:with-param>
4732 </xsl:call-template>
4736 <xsl:for-each select="marc:datafield[@tag=506]">
4737 <accessCondition type="restrictionOnAccess">
4738 <xsl:call-template name="subfieldSelect">
4739 <xsl:with-param name="codes">abcd35</xsl:with-param>
4740 </xsl:call-template>
4743 <xsl:for-each select="marc:datafield[@tag=540]">
4744 <accessCondition type="useAndReproduction">
4745 <xsl:call-template name="subfieldSelect">
4746 <xsl:with-param name="codes">abcde35</xsl:with-param>
4747 </xsl:call-template>
4751 <xsl:for-each select="marc:datafield[@tag=040]">
4752 <recordContentSource authority="marcorg">
4753 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4754 </recordContentSource>
4756 <xsl:for-each select="marc:controlfield[@tag=008]">
4757 <recordCreationDate encoding="marc">
4758 <xsl:value-of select="substring(.,1,6)"></xsl:value-of>
4759 </recordCreationDate>
4761 <xsl:for-each select="marc:controlfield[@tag=005]">
4762 <recordChangeDate encoding="iso8601">
4763 <xsl:value-of select="."></xsl:value-of>
4766 <xsl:for-each select="marc:controlfield[@tag=001]">
4768 <xsl:if test="../marc:controlfield[@tag=003]">
4769 <xsl:attribute name="source">
4770 <xsl:value-of select="../marc:controlfield[@tag=003]"></xsl:value-of>
4773 <xsl:value-of select="."></xsl:value-of>
4776 <xsl:for-each select="marc:datafield[@tag=040]/marc:subfield[@code='b']">
4777 <languageOfCataloging>
4778 <languageTerm authority="iso639-2b" type="code">
4779 <xsl:value-of select="."></xsl:value-of>
4781 </languageOfCataloging>
4785 <xsl:template name="displayForm">
4786 <xsl:for-each select="marc:subfield[@code='c']">
4788 <xsl:value-of select="."></xsl:value-of>
4792 <xsl:template name="affiliation">
4793 <xsl:for-each select="marc:subfield[@code='u']">
4795 <xsl:value-of select="."></xsl:value-of>
4799 <xsl:template name="uri">
4800 <xsl:for-each select="marc:subfield[@code='u']">
4801 <xsl:attribute name="xlink:href">
4802 <xsl:value-of select="."></xsl:value-of>
4806 <xsl:template name="role">
4807 <xsl:for-each select="marc:subfield[@code='e']">
4809 <roleTerm type="text">
4810 <xsl:value-of select="."></xsl:value-of>
4814 <xsl:for-each select="marc:subfield[@code='4']">
4816 <roleTerm authority="marcrelator" type="code">
4817 <xsl:value-of select="."></xsl:value-of>
4822 <xsl:template name="part">
4823 <xsl:variable name="partNumber">
4824 <xsl:call-template name="specialSubfieldSelect">
4825 <xsl:with-param name="axis">n</xsl:with-param>
4826 <xsl:with-param name="anyCodes">n</xsl:with-param>
4827 <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
4828 </xsl:call-template>
4830 <xsl:variable name="partName">
4831 <xsl:call-template name="specialSubfieldSelect">
4832 <xsl:with-param name="axis">p</xsl:with-param>
4833 <xsl:with-param name="anyCodes">p</xsl:with-param>
4834 <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
4835 </xsl:call-template>
4837 <xsl:if test="string-length(normalize-space($partNumber))">
4839 <xsl:call-template name="chopPunctuation">
4840 <xsl:with-param name="chopString" select="$partNumber"></xsl:with-param>
4841 </xsl:call-template>
4844 <xsl:if test="string-length(normalize-space($partName))">
4846 <xsl:call-template name="chopPunctuation">
4847 <xsl:with-param name="chopString" select="$partName"></xsl:with-param>
4848 </xsl:call-template>
4852 <xsl:template name="relatedPart">
4853 <xsl:if test="@tag=773">
4854 <xsl:for-each select="marc:subfield[@code='g']">
4857 <xsl:value-of select="."></xsl:value-of>
4861 <xsl:for-each select="marc:subfield[@code='q']">
4863 <xsl:call-template name="parsePart"></xsl:call-template>
4868 <xsl:template name="relatedPartNumName">
4869 <xsl:variable name="partNumber">
4870 <xsl:call-template name="specialSubfieldSelect">
4871 <xsl:with-param name="axis">g</xsl:with-param>
4872 <xsl:with-param name="anyCodes">g</xsl:with-param>
4873 <xsl:with-param name="afterCodes">pst</xsl:with-param>
4874 </xsl:call-template>
4876 <xsl:variable name="partName">
4877 <xsl:call-template name="specialSubfieldSelect">
4878 <xsl:with-param name="axis">p</xsl:with-param>
4879 <xsl:with-param name="anyCodes">p</xsl:with-param>
4880 <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
4881 </xsl:call-template>
4883 <xsl:if test="string-length(normalize-space($partNumber))">
4885 <xsl:value-of select="$partNumber"></xsl:value-of>
4888 <xsl:if test="string-length(normalize-space($partName))">
4890 <xsl:value-of select="$partName"></xsl:value-of>
4894 <xsl:template name="relatedName">
4895 <xsl:for-each select="marc:subfield[@code='a']">
4898 <xsl:value-of select="."></xsl:value-of>
4903 <xsl:template name="relatedForm">
4904 <xsl:for-each select="marc:subfield[@code='h']">
4905 <physicalDescription>
4907 <xsl:value-of select="."></xsl:value-of>
4909 </physicalDescription>
4912 <xsl:template name="relatedExtent">
4913 <xsl:for-each select="marc:subfield[@code='h']">
4914 <physicalDescription>
4916 <xsl:value-of select="."></xsl:value-of>
4918 </physicalDescription>
4921 <xsl:template name="relatedNote">
4922 <xsl:for-each select="marc:subfield[@code='n']">
4924 <xsl:value-of select="."></xsl:value-of>
4928 <xsl:template name="relatedSubject">
4929 <xsl:for-each select="marc:subfield[@code='j']">
4931 <temporal encoding="iso8601">
4932 <xsl:call-template name="chopPunctuation">
4933 <xsl:with-param name="chopString" select="."></xsl:with-param>
4934 </xsl:call-template>
4939 <xsl:template name="relatedIdentifierISSN">
4940 <xsl:for-each select="marc:subfield[@code='x']">
4941 <identifier type="issn">
4942 <xsl:value-of select="."></xsl:value-of>
4946 <xsl:template name="relatedIdentifierLocal">
4947 <xsl:for-each select="marc:subfield[@code='w']">
4948 <identifier type="local">
4949 <xsl:value-of select="."></xsl:value-of>
4953 <xsl:template name="relatedIdentifier">
4954 <xsl:for-each select="marc:subfield[@code='o']">
4956 <xsl:value-of select="."></xsl:value-of>
4960 <xsl:template name="relatedItem76X-78X">
4961 <xsl:call-template name="displayLabel"></xsl:call-template>
4962 <xsl:call-template name="relatedTitle76X-78X"></xsl:call-template>
4963 <xsl:call-template name="relatedName"></xsl:call-template>
4964 <xsl:call-template name="relatedOriginInfo"></xsl:call-template>
4965 <xsl:call-template name="relatedLanguage"></xsl:call-template>
4966 <xsl:call-template name="relatedExtent"></xsl:call-template>
4967 <xsl:call-template name="relatedNote"></xsl:call-template>
4968 <xsl:call-template name="relatedSubject"></xsl:call-template>
4969 <xsl:call-template name="relatedIdentifier"></xsl:call-template>
4970 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4971 <xsl:call-template name="relatedIdentifierLocal"></xsl:call-template>
4972 <xsl:call-template name="relatedPart"></xsl:call-template>
4974 <xsl:template name="subjectGeographicZ">
4976 <xsl:call-template name="chopPunctuation">
4977 <xsl:with-param name="chopString" select="."></xsl:with-param>
4978 </xsl:call-template>
4981 <xsl:template name="subjectTemporalY">
4983 <xsl:call-template name="chopPunctuation">
4984 <xsl:with-param name="chopString" select="."></xsl:with-param>
4985 </xsl:call-template>
4988 <xsl:template name="subjectTopic">
4990 <xsl:call-template name="chopPunctuation">
4991 <xsl:with-param name="chopString" select="."></xsl:with-param>
4992 </xsl:call-template>
4995 <!-- 3.2 change tmee 6xx $v genre -->
4996 <xsl:template name="subjectGenre">
4998 <xsl:call-template name="chopPunctuation">
4999 <xsl:with-param name="chopString" select="."></xsl:with-param>
5000 </xsl:call-template>
5004 <xsl:template name="nameABCDN">
5005 <xsl:for-each select="marc:subfield[@code='a']">
5007 <xsl:call-template name="chopPunctuation">
5008 <xsl:with-param name="chopString" select="."></xsl:with-param>
5009 </xsl:call-template>
5012 <xsl:for-each select="marc:subfield[@code='b']">
5014 <xsl:value-of select="."></xsl:value-of>
5017 <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
5019 <xsl:call-template name="subfieldSelect">
5020 <xsl:with-param name="codes">cdn</xsl:with-param>
5021 </xsl:call-template>
5025 <xsl:template name="nameABCDQ">
5027 <xsl:call-template name="chopPunctuation">
5028 <xsl:with-param name="chopString">
5029 <xsl:call-template name="subfieldSelect">
5030 <xsl:with-param name="codes">aq</xsl:with-param>
5031 </xsl:call-template>
5033 <xsl:with-param name="punctuation">
5034 <xsl:text>:,;/ </xsl:text>
5036 </xsl:call-template>
5038 <xsl:call-template name="termsOfAddress"></xsl:call-template>
5039 <xsl:call-template name="nameDate"></xsl:call-template>
5041 <xsl:template name="nameACDEQ">
5043 <xsl:call-template name="subfieldSelect">
5044 <xsl:with-param name="codes">acdeq</xsl:with-param>
5045 </xsl:call-template>
5048 <xsl:template name="constituentOrRelatedType">
5049 <xsl:if test="@ind2=2">
5050 <xsl:attribute name="type">constituent</xsl:attribute>
5053 <xsl:template name="relatedTitle">
5054 <xsl:for-each select="marc:subfield[@code='t']">
5057 <xsl:call-template name="chopPunctuation">
5058 <xsl:with-param name="chopString">
5059 <xsl:value-of select="."></xsl:value-of>
5061 </xsl:call-template>
5066 <xsl:template name="relatedTitle76X-78X">
5067 <xsl:for-each select="marc:subfield[@code='t']">
5070 <xsl:call-template name="chopPunctuation">
5071 <xsl:with-param name="chopString">
5072 <xsl:value-of select="."></xsl:value-of>
5074 </xsl:call-template>
5076 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
5077 <xsl:call-template name="relatedPartNumName"></xsl:call-template>
5081 <xsl:for-each select="marc:subfield[@code='p']">
5082 <titleInfo type="abbreviated">
5084 <xsl:call-template name="chopPunctuation">
5085 <xsl:with-param name="chopString">
5086 <xsl:value-of select="."></xsl:value-of>
5088 </xsl:call-template>
5090 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
5091 <xsl:call-template name="relatedPartNumName"></xsl:call-template>
5095 <xsl:for-each select="marc:subfield[@code='s']">
5096 <titleInfo type="uniform">
5098 <xsl:call-template name="chopPunctuation">
5099 <xsl:with-param name="chopString">
5100 <xsl:value-of select="."></xsl:value-of>
5102 </xsl:call-template>
5104 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
5105 <xsl:call-template name="relatedPartNumName"></xsl:call-template>
5110 <xsl:template name="relatedOriginInfo">
5111 <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
5113 <xsl:if test="@tag=775">
5114 <xsl:for-each select="marc:subfield[@code='f']">
5117 <xsl:attribute name="type">code</xsl:attribute>
5118 <xsl:attribute name="authority">marcgac</xsl:attribute>
5119 <xsl:value-of select="."></xsl:value-of>
5124 <xsl:for-each select="marc:subfield[@code='d']">
5126 <xsl:value-of select="."></xsl:value-of>
5129 <xsl:for-each select="marc:subfield[@code='b']">
5131 <xsl:value-of select="."></xsl:value-of>
5137 <xsl:template name="relatedLanguage">
5138 <xsl:for-each select="marc:subfield[@code='e']">
5139 <xsl:call-template name="getLanguage">
5140 <xsl:with-param name="langString">
5141 <xsl:value-of select="."></xsl:value-of>
5143 </xsl:call-template>
5146 <xsl:template name="nameDate">
5147 <xsl:for-each select="marc:subfield[@code='d']">
5148 <namePart type="date">
5149 <xsl:call-template name="chopPunctuation">
5150 <xsl:with-param name="chopString" select="."></xsl:with-param>
5151 </xsl:call-template>
5155 <xsl:template name="subjectAuthority">
5156 <xsl:if test="@ind2!=4">
5157 <xsl:if test="@ind2!=' '">
5158 <xsl:if test="@ind2!=8">
5159 <xsl:if test="@ind2!=9">
5160 <xsl:attribute name="authority">
5162 <xsl:when test="@ind2=0">lcsh</xsl:when>
5163 <xsl:when test="@ind2=1">lcshac</xsl:when>
5164 <xsl:when test="@ind2=2">mesh</xsl:when>
5166 <xsl:when test="@ind2=3">nal</xsl:when>
5167 <xsl:when test="@ind2=5">csh</xsl:when>
5168 <xsl:when test="@ind2=6">rvm</xsl:when>
5169 <xsl:when test="@ind2=7">
5170 <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
5179 <xsl:template name="subjectAnyOrder">
5180 <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
5182 <xsl:when test="@code='v'">
5183 <xsl:call-template name="subjectGenre"></xsl:call-template>
5185 <xsl:when test="@code='x'">
5186 <xsl:call-template name="subjectTopic"></xsl:call-template>
5188 <xsl:when test="@code='y'">
5189 <xsl:call-template name="subjectTemporalY"></xsl:call-template>
5191 <xsl:when test="@code='z'">
5192 <xsl:call-template name="subjectGeographicZ"></xsl:call-template>
5197 <xsl:template name="specialSubfieldSelect">
5198 <xsl:param name="anyCodes"></xsl:param>
5199 <xsl:param name="axis"></xsl:param>
5200 <xsl:param name="beforeCodes"></xsl:param>
5201 <xsl:param name="afterCodes"></xsl:param>
5202 <xsl:variable name="str">
5203 <xsl:for-each select="marc:subfield">
5204 <xsl:if test="contains($anyCodes, @code) or (contains($beforeCodes,@code) and following-sibling::marc:subfield[@code=$axis]) or (contains($afterCodes,@code) and preceding-sibling::marc:subfield[@code=$axis])">
5205 <xsl:value-of select="text()"></xsl:value-of>
5206 <xsl:text> </xsl:text>
5210 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
5213 <!-- 3.2 change tmee 6xx $v genre -->
5214 <xsl:template match="marc:datafield[@tag=600]">
5216 <xsl:call-template name="subjectAuthority"></xsl:call-template>
5217 <name type="personal">
5218 <xsl:call-template name="termsOfAddress"></xsl:call-template>
5220 <xsl:call-template name="chopPunctuation">
5221 <xsl:with-param name="chopString">
5222 <xsl:call-template name="subfieldSelect">
5223 <xsl:with-param name="codes">aq</xsl:with-param>
5224 </xsl:call-template>
5226 </xsl:call-template>
5228 <xsl:call-template name="nameDate"></xsl:call-template>
5229 <xsl:call-template name="affiliation"></xsl:call-template>
5230 <xsl:call-template name="role"></xsl:call-template>
5232 <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5235 <xsl:template match="marc:datafield[@tag=610]">
5237 <xsl:call-template name="subjectAuthority"></xsl:call-template>
5238 <name type="corporate">
5239 <xsl:for-each select="marc:subfield[@code='a']">
5241 <xsl:value-of select="."></xsl:value-of>
5244 <xsl:for-each select="marc:subfield[@code='b']">
5246 <xsl:value-of select="."></xsl:value-of>
5249 <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
5251 <xsl:call-template name="subfieldSelect">
5252 <xsl:with-param name="codes">cdnp</xsl:with-param>
5253 </xsl:call-template>
5256 <xsl:call-template name="role"></xsl:call-template>
5258 <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5261 <xsl:template match="marc:datafield[@tag=611]">
5263 <xsl:call-template name="subjectAuthority"></xsl:call-template>
5264 <name type="conference">
5266 <xsl:call-template name="subfieldSelect">
5267 <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
5268 </xsl:call-template>
5270 <xsl:for-each select="marc:subfield[@code='4']">
5272 <roleTerm authority="marcrelator" type="code">
5273 <xsl:value-of select="."></xsl:value-of>
5278 <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5281 <xsl:template match="marc:datafield[@tag=630]">
5283 <xsl:call-template name="subjectAuthority"></xsl:call-template>
5286 <xsl:call-template name="chopPunctuation">
5287 <xsl:with-param name="chopString">
5288 <xsl:call-template name="subfieldSelect">
5289 <xsl:with-param name="codes">adfhklor</xsl:with-param>
5290 </xsl:call-template>
5292 </xsl:call-template>
5293 <xsl:call-template name="part"></xsl:call-template>
5296 <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5299 <xsl:template match="marc:datafield[@tag=650]">
5301 <xsl:call-template name="subjectAuthority"></xsl:call-template>
5303 <xsl:call-template name="chopPunctuation">
5304 <xsl:with-param name="chopString">
5305 <xsl:call-template name="subfieldSelect">
5306 <xsl:with-param name="codes">abcd</xsl:with-param>
5307 </xsl:call-template>
5309 </xsl:call-template>
5311 <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5314 <xsl:template match="marc:datafield[@tag=651]">
5316 <xsl:call-template name="subjectAuthority"></xsl:call-template>
5317 <xsl:for-each select="marc:subfield[@code='a']">
5319 <xsl:call-template name="chopPunctuation">
5320 <xsl:with-param name="chopString" select="."></xsl:with-param>
5321 </xsl:call-template>
5324 <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5327 <xsl:template match="marc:datafield[@tag=653]">
5329 <xsl:for-each select="marc:subfield[@code='a']">
5331 <xsl:value-of select="."></xsl:value-of>
5336 <xsl:template match="marc:datafield[@tag=656]">
5338 <xsl:if test="marc:subfield[@code=2]">
5339 <xsl:attribute name="authority">
5340 <xsl:value-of select="marc:subfield[@code=2]"></xsl:value-of>
5344 <xsl:call-template name="chopPunctuation">
5345 <xsl:with-param name="chopString">
5346 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
5348 </xsl:call-template>
5352 <xsl:template name="termsOfAddress">
5353 <xsl:if test="marc:subfield[@code='b' or @code='c']">
5354 <namePart type="termsOfAddress">
5355 <xsl:call-template name="chopPunctuation">
5356 <xsl:with-param name="chopString">
5357 <xsl:call-template name="subfieldSelect">
5358 <xsl:with-param name="codes">bc</xsl:with-param>
5359 </xsl:call-template>
5361 </xsl:call-template>
5365 <xsl:template name="displayLabel">
5366 <xsl:if test="marc:subfield[@code='i']">
5367 <xsl:attribute name="displayLabel">
5368 <xsl:value-of select="marc:subfield[@code='i']"></xsl:value-of>
5371 <xsl:if test="marc:subfield[@code='3']">
5372 <xsl:attribute name="displayLabel">
5373 <xsl:value-of select="marc:subfield[@code='3']"></xsl:value-of>
5377 <xsl:template name="isInvalid">
5378 <xsl:param name="type"/>
5379 <xsl:if test="marc:subfield[@code='z'] or marc:subfield[@code='y']">
5381 <xsl:attribute name="type">
5382 <xsl:value-of select="$type"/>
5384 <xsl:attribute name="invalid">
5385 <xsl:text>yes</xsl:text>
5387 <xsl:if test="marc:subfield[@code='z']">
5388 <xsl:value-of select="marc:subfield[@code='z']"/>
5390 <xsl:if test="marc:subfield[@code='y']">
5391 <xsl:value-of select="marc:subfield[@code='y']"/>
5396 <xsl:template name="subtitle">
5397 <xsl:if test="marc:subfield[@code='b']">
5399 <xsl:call-template name="chopPunctuation">
5400 <xsl:with-param name="chopString">
5401 <xsl:value-of select="marc:subfield[@code='b']"/>
5402 <!--<xsl:call-template name="subfieldSelect">
5403 <xsl:with-param name="codes">b</xsl:with-param>
5404 </xsl:call-template>-->
5406 </xsl:call-template>
5410 <xsl:template name="script">
5411 <xsl:param name="scriptCode"></xsl:param>
5412 <xsl:attribute name="script">
5414 <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
5415 <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
5416 <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
5417 <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
5418 <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
5419 <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
5423 <xsl:template name="parsePart">
5424 <!-- assumes 773$q= 1:2:3<4
5425 with up to 3 levels and one optional start page
5427 <xsl:variable name="level1">
5429 <xsl:when test="contains(text(),':')">
5431 <xsl:value-of select="substring-before(text(),':')"></xsl:value-of>
5433 <xsl:when test="not(contains(text(),':'))">
5435 <xsl:if test="contains(text(),'<')">
5437 <xsl:value-of select="substring-before(text(),'<')"></xsl:value-of>
5439 <xsl:if test="not(contains(text(),'<'))">
5441 <xsl:value-of select="text()"></xsl:value-of>
5446 <xsl:variable name="sici2">
5448 <xsl:when test="starts-with(substring-after(text(),$level1),':')">
5449 <xsl:value-of select="substring(substring-after(text(),$level1),2)"></xsl:value-of>
5452 <xsl:value-of select="substring-after(text(),$level1)"></xsl:value-of>
5456 <xsl:variable name="level2">
5458 <xsl:when test="contains($sici2,':')">
5460 <xsl:value-of select="substring-before($sici2,':')"></xsl:value-of>
5462 <xsl:when test="contains($sici2,'<')">
5464 <xsl:value-of select="substring-before($sici2,'<')"></xsl:value-of>
5467 <xsl:value-of select="$sici2"></xsl:value-of>
5472 <xsl:variable name="sici3">
5474 <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
5475 <xsl:value-of select="substring(substring-after($sici2,$level2),2)"></xsl:value-of>
5478 <xsl:value-of select="substring-after($sici2,$level2)"></xsl:value-of>
5482 <xsl:variable name="level3">
5484 <xsl:when test="contains($sici3,'<')">
5486 <xsl:value-of select="substring-before($sici3,'<')"></xsl:value-of>
5489 <xsl:value-of select="$sici3"></xsl:value-of>
5494 <xsl:variable name="page">
5495 <xsl:if test="contains(text(),'<')">
5496 <xsl:value-of select="substring-after(text(),'<')"></xsl:value-of>
5499 <xsl:if test="$level1">
5502 <xsl:value-of select="$level1"></xsl:value-of>
5506 <xsl:if test="$level2">
5509 <xsl:value-of select="$level2"></xsl:value-of>
5513 <xsl:if test="$level3">
5516 <xsl:value-of select="$level3"></xsl:value-of>
5520 <xsl:if test="$page">
5521 <extent unit="page">
5523 <xsl:value-of select="$page"></xsl:value-of>
5528 <xsl:template name="getLanguage">
5529 <xsl:param name="langString"></xsl:param>
5530 <xsl:param name="controlField008-35-37"></xsl:param>
5531 <xsl:variable name="length" select="string-length($langString)"></xsl:variable>
5533 <xsl:when test="$length=0"></xsl:when>
5534 <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
5535 <xsl:call-template name="getLanguage">
5536 <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
5537 <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
5538 </xsl:call-template>
5542 <languageTerm authority="iso639-2b" type="code">
5543 <xsl:value-of select="substring($langString,1,3)"></xsl:value-of>
5546 <xsl:call-template name="getLanguage">
5547 <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
5548 <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
5549 </xsl:call-template>
5553 <xsl:template name="isoLanguage">
5554 <xsl:param name="currentLanguage"></xsl:param>
5555 <xsl:param name="usedLanguages"></xsl:param>
5556 <xsl:param name="remainingLanguages"></xsl:param>
5558 <xsl:when test="string-length($currentLanguage)=0"></xsl:when>
5559 <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
5561 <xsl:if test="@code!='a'">
5562 <xsl:attribute name="objectPart">
5564 <xsl:when test="@code='b'">summary or subtitle</xsl:when>
5565 <xsl:when test="@code='d'">sung or spoken text</xsl:when>
5566 <xsl:when test="@code='e'">libretto</xsl:when>
5567 <xsl:when test="@code='f'">table of contents</xsl:when>
5568 <xsl:when test="@code='g'">accompanying material</xsl:when>
5569 <xsl:when test="@code='h'">translation</xsl:when>
5573 <languageTerm authority="iso639-2b" type="code">
5574 <xsl:value-of select="$currentLanguage"></xsl:value-of>
5577 <xsl:call-template name="isoLanguage">
5578 <xsl:with-param name="currentLanguage">
5579 <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
5581 <xsl:with-param name="usedLanguages">
5582 <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
5584 <xsl:with-param name="remainingLanguages">
5585 <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
5587 </xsl:call-template>
5590 <xsl:call-template name="isoLanguage">
5591 <xsl:with-param name="currentLanguage">
5592 <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
5594 <xsl:with-param name="usedLanguages">
5595 <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
5597 <xsl:with-param name="remainingLanguages">
5598 <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
5600 </xsl:call-template>
5604 <xsl:template name="chopBrackets">
5605 <xsl:param name="chopString"></xsl:param>
5606 <xsl:variable name="string">
5607 <xsl:call-template name="chopPunctuation">
5608 <xsl:with-param name="chopString" select="$chopString"></xsl:with-param>
5609 </xsl:call-template>
5611 <xsl:if test="substring($string, 1,1)='['">
5612 <xsl:value-of select="substring($string,2, string-length($string)-2)"></xsl:value-of>
5614 <xsl:if test="substring($string, 1,1)!='['">
5615 <xsl:value-of select="$string"></xsl:value-of>
5618 <xsl:template name="rfcLanguages">
5619 <xsl:param name="nodeNum"></xsl:param>
5620 <xsl:param name="usedLanguages"></xsl:param>
5621 <xsl:param name="controlField008-35-37"></xsl:param>
5622 <xsl:variable name="currentLanguage" select="."></xsl:variable>
5624 <xsl:when test="not($currentLanguage)"></xsl:when>
5625 <xsl:when test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
5626 <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
5628 <xsl:if test="@code!='a'">
5629 <xsl:attribute name="objectPart">
5631 <xsl:when test="@code='b'">summary or subtitle</xsl:when>
5632 <xsl:when test="@code='d'">sung or spoken text</xsl:when>
5633 <xsl:when test="@code='e'">libretto</xsl:when>
5634 <xsl:when test="@code='f'">table of contents</xsl:when>
5635 <xsl:when test="@code='g'">accompanying material</xsl:when>
5636 <xsl:when test="@code='h'">translation</xsl:when>
5640 <languageTerm authority="rfc3066" type="code">
5641 <xsl:value-of select="$currentLanguage"/>
5650 <xsl:template name="datafield">
5651 <xsl:param name="tag"/>
5652 <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
5653 <xsl:param name="ind2"><xsl:text> </xsl:text></xsl:param>
5654 <xsl:param name="subfields"/>
5655 <xsl:element name="marc:datafield">
5656 <xsl:attribute name="tag">
5657 <xsl:value-of select="$tag"/>
5659 <xsl:attribute name="ind1">
5660 <xsl:value-of select="$ind1"/>
5662 <xsl:attribute name="ind2">
5663 <xsl:value-of select="$ind2"/>
5665 <xsl:copy-of select="$subfields"/>
5669 <xsl:template name="subfieldSelect">
5670 <xsl:param name="codes"/>
5671 <xsl:param name="delimeter"><xsl:text> </xsl:text></xsl:param>
5672 <xsl:variable name="str">
5673 <xsl:for-each select="marc:subfield">
5674 <xsl:if test="contains($codes, @code)">
5675 <xsl:value-of select="text()"/><xsl:value-of select="$delimeter"/>
5679 <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
5682 <xsl:template name="buildSpaces">
5683 <xsl:param name="spaces"/>
5684 <xsl:param name="char"><xsl:text> </xsl:text></xsl:param>
5685 <xsl:if test="$spaces>0">
5686 <xsl:value-of select="$char"/>
5687 <xsl:call-template name="buildSpaces">
5688 <xsl:with-param name="spaces" select="$spaces - 1"/>
5689 <xsl:with-param name="char" select="$char"/>
5690 </xsl:call-template>
5694 <xsl:template name="chopPunctuation">
5695 <xsl:param name="chopString"/>
5696 <xsl:param name="punctuation"><xsl:text>.:,;/ </xsl:text></xsl:param>
5697 <xsl:variable name="length" select="string-length($chopString)"/>
5699 <xsl:when test="$length=0"/>
5700 <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
5701 <xsl:call-template name="chopPunctuation">
5702 <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
5703 <xsl:with-param name="punctuation" select="$punctuation"/>
5704 </xsl:call-template>
5706 <xsl:when test="not($chopString)"/>
5707 <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
5711 <xsl:template name="chopPunctuationFront">
5712 <xsl:param name="chopString"/>
5713 <xsl:variable name="length" select="string-length($chopString)"/>
5715 <xsl:when test="$length=0"/>
5716 <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
5717 <xsl:call-template name="chopPunctuationFront">
5718 <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"/>
5719 </xsl:call-template>
5721 <xsl:when test="not($chopString)"/>
5722 <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
5725 </xsl:stylesheet>$$ WHERE name = 'mods32';
5729 INSERT INTO config.circ_matrix_ruleset (matchpoint,duration_rule,recurring_fine_rule,max_fine_rule)
5730 SELECT 1, d.id, f.id, m.id
5731 FROM config.rule_circ_duration d
5732 JOIN config.rule_recuring_fine f ON (f.name = d.name)
5733 JOIN config.rule_max_fine m ON (f.name = m.name)
5734 WHERE m.name = 'default';