]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/1.2.4-1.4-upgrade-db.sql
Add limit_count and offset_count columns to query.stored_query table.
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 1.2.4-1.4-upgrade-db.sql
1 /*
2  * Copyright (C) 2008  Equinox Software, Inc.
3  * Mike Rylander <miker@esilibrary.com>
4  *
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.
9  *
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.
14  *
15  */
16
17
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
19
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+)';
24
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+)';
28
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+)';
32
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+)';
36
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+)';
40
41 UPDATE metabib.full_rec
42 SET value = REGEXP_REPLACE(value, E'(\\w+)\\/(\\w+)', E'\\1 \\2','g')
43 WHERE value ~ E'(\\w+)\\/(\\w+)';
44
45 \set ON_ERROR_STOP 1
46
47 BEGIN;
48
49 -- To avoid any updates while we're doin' our thing...
50 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
51
52 CREATE TABLE config.upgrade_log (
53     version         TEXT    PRIMARY KEY,
54     install_date    TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
55 );
56 INSERT INTO config.upgrade_log (version) VALUES ('1.4.0.0');
57
58 SELECT set_curcfg('default');
59
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);
62 $$ LANGUAGE SQL;
63
64 CREATE OR REPLACE FUNCTION public.extract_marc_field ( TEXT, BIGINT, TEXT ) RETURNS TEXT AS $$
65         SELECT public.extract_marc_field($1,$2,$3,'');
66 $$ LANGUAGE SQL;
67
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,
72     description TEXT
73 );
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');
78
79
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,
85     string          TEXT        NOT NULL
86 );
87 CREATE UNIQUE INDEX i18n_identity ON config.i18n_core (fq_field,identity_value,translation);
88  
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$
90 DECLARE
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;
94     fallback    TEXT;
95     keyfield    TEXT := keyclass || '.' || keycol;
96 BEGIN
97
98     -- Try the full locale
99     SELECT  * INTO result
100       FROM  config.i18n_core
101       WHERE fq_field = keyfield
102             AND identity_value = keyvalue
103             AND translation = locale;
104
105     -- Try just the language
106     IF NOT FOUND THEN
107         SELECT  * INTO result
108           FROM  config.i18n_core
109           WHERE fq_field = keyfield
110                 AND identity_value = keyvalue
111                 AND translation = language;
112     END IF;
113
114     -- Fall back to the string we passed in in the first place
115     IF NOT FOUND THEN
116         EXECUTE
117             'SELECT ' ||
118                 keycol ||
119             ' FROM ' || keytable ||
120             ' WHERE ' || identcol || ' = ' || quote_literal(keyvalue)
121                 INTO fallback;
122         RETURN fallback;
123     END IF;
124
125     RETURN result.string;
126 END;
127 $func$ LANGUAGE PLPGSQL;
128
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 $$
132     SELECT $2;
133 $$ LANGUAGE SQL;
134
135 CREATE OR REPLACE FUNCTION oils_i18n_gettext( TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$
136     SELECT $2;
137 $$ LANGUAGE SQL;
138
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', '' );
141
142
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';
146
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';
157
158 /* And they all want mods32: as their prefix */
159 UPDATE config.metabib_field SET xpath = regexp_replace(xpath, 'mods:', 'mods32:', 'g');
160
161
162 ALTER TABLE config.copy_status ADD COLUMN opac_visible BOOL NOT NULL DEFAULT FALSE;
163 UPDATE config.copy_status SET opac_visible = holdable;
164
165 CREATE TABLE config.bib_level_map (
166         code    TEXT    PRIMARY KEY,
167         value   TEXT    NOT NULL
168 );
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'));
176
177 CREATE TABLE config.z3950_source (
178     name                TEXT    PRIMARY KEY,
179     label               TEXT    NOT NULL UNIQUE,
180     host                TEXT    NOT NULL,
181     port                INT     NOT NULL,
182     db                  TEXT    NOT NULL,
183     record_format       TEXT    NOT NULL DEFAULT 'FI',
184     transmission_format TEXT    NOT NULL DEFAULT 'usmarc',
185     auth                BOOL    NOT NULL DEFAULT TRUE
186 );
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);
191
192
193 CREATE TABLE config.z3950_attr (
194     id          SERIAL  PRIMARY KEY,
195     source      TEXT    NOT NULL REFERENCES config.z3950_source (name) DEFERRABLE INITIALLY DEFERRED,
196     name        TEXT    NOT NULL,
197     label       TEXT    NOT NULL,
198     code        INT     NOT NULL,
199     format      INT     NOT NULL,
200     truncation  INT     NOT NULL DEFAULT 0,
201     CONSTRAINT z_code_format_once_per_source UNIQUE (code,format,source)
202 );
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);
221
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);
241
242
243
244 CREATE TABLE actor.org_lasso (
245     id      SERIAL  PRIMARY KEY,
246     name        TEXT    UNIQUE
247 );
248
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
253 );
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);
256  
257
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)
266 );
267 CREATE INDEX uopm_usr_idx ON permission.usr_object_perm_map (usr);
268
269
270 CREATE OR REPLACE FUNCTION permission.grp_ancestors ( INT ) RETURNS SETOF permission.grp_tree AS $$
271         SELECT  a.*
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
275         ORDER BY
276                 CASE WHEN a.parent IS NULL
277                         THEN 0
278                         ELSE 1
279                 END, a.name;
280 $$ LANGUAGE SQL STABLE;
281
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 $$
283 DECLARE
284         r_usr   actor.usr%ROWTYPE;
285         res     BOOL;
286 BEGIN
287
288         SELECT * INTO r_usr FROM actor.usr WHERE id = iuser;
289
290         IF r_usr.active = FALSE THEN
291                 RETURN FALSE;
292         END IF;
293
294         IF r_usr.super_user = TRUE THEN
295                 RETURN TRUE;
296         END IF;
297
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;
299
300         IF FOUND THEN
301                 RETURN TRUE;
302         END IF;
303
304         IF target_ou > -1 THEN
305                 RETURN permission.usr_has_perm( iuser, tperm, target_ou);
306         END IF;
307
308         RETURN FALSE;
309
310 END;
311 $$ LANGUAGE PLPGSQL;
312
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 );
315 $$ LANGUAGE SQL;
316
317 CREATE OR REPLACE FUNCTION permission.grp_descendants ( INT ) RETURNS SETOF permission.grp_tree AS $$
318     SELECT  a.*
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;
324
325 CREATE OR REPLACE FUNCTION permission.grp_full_path ( INT ) RETURNS SETOF permission.grp_tree AS $$
326     SELECT  *
327       FROM  permission.grp_ancestors($1)
328             UNION
329     SELECT  *
330       FROM  permission.grp_descendants($1);
331 $$ LANGUAGE SQL STABLE;
332
333 CREATE OR REPLACE FUNCTION permission.grp_combined_ancestors ( INT, INT ) RETURNS SETOF permission.grp_tree AS $$
334     SELECT  *
335       FROM  permission.grp_ancestors($1)
336             UNION
337     SELECT  *
338       FROM  permission.grp_ancestors($2);
339 $$ LANGUAGE SQL STABLE;
340
341 CREATE OR REPLACE FUNCTION permission.grp_common_ancestors ( INT, INT ) RETURNS SETOF permission.grp_tree AS $$
342     SELECT  *
343       FROM  permission.grp_ancestors($1)
344             INTERSECT
345     SELECT  *
346       FROM  permission.grp_ancestors($2);
347 $$ LANGUAGE SQL STABLE;
348
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)
352             EXCEPT
353         SELECT id FROM permission.grp_common_ancestors($1, $2)
354     ) z;
355 $$ LANGUAGE SQL STABLE;
356
357 INSERT INTO permission.usr_work_ou_map (usr, work_ou)
358  SELECT DISTINCT u.id, u.home_ou
359   FROM  actor.usr u
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)
362   WHERE m.id IS NULL
363         AND g.id IN (
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'
367         );
368
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);
371  
372
373 CREATE OR REPLACE FUNCTION public.naco_normalize( TEXT, TEXT ) RETURNS TEXT AS $func$
374     use Unicode::Normalize;
375
376         my $txt = lc(shift);
377         my $sf = shift;
378
379     $txt = NFD($txt);
380         $txt =~ s/\pM+//go;     # Remove diacritics
381
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
385
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
388
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
392
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);
400                         } else {
401                                 $txt =~ s/,/ /go;
402                         }
403                 }
404         } else {
405                 $txt =~ s/,/ /go;
406         }
407
408         $txt =~ s/\s+/ /go;     # Compress multiple spaces
409         $txt =~ s/^\s+//o;      # Remove leading space
410         $txt =~ s/\s+$//o;      # Remove trailing space
411
412         return $txt;
413 $func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
414
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;
418
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');
421 $$ LANGUAGE SQL;
422
423 CREATE OR REPLACE FUNCTION public.lowercase( TEXT ) RETURNS TEXT AS $$
424     return lc(shift);
425 $$ LANGUAGE PLPERLU;
426
427 CREATE OR REPLACE FUNCTION public.uppercase( TEXT ) RETURNS TEXT AS $$
428     return uc(shift);
429 $$ LANGUAGE PLPERLU;
430
431 CREATE OR REPLACE FUNCTION public.remove_diacritics( TEXT ) RETURNS TEXT AS $$
432     use Unicode::Normalize;
433
434     my $x = NFD(shift);
435     $x =~ s/\pM+//go;
436     return $x;
437
438 $$ LANGUAGE PLPERLU;
439
440 CREATE OR REPLACE FUNCTION public.entityize( TEXT ) RETURNS TEXT AS $$
441     use Unicode::Normalize;
442
443     my $x = NFC(shift);
444     $x =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
445     return $x;
446
447 $$ LANGUAGE PLPERLU;
448
449
450 CREATE OR REPLACE FUNCTION public.call_number_dewey( TEXT ) RETURNS TEXT AS $$
451         my $txt = shift;
452         $txt =~ s/^\s+//o;
453         $txt =~ s/[\[\]\{\}\(\)`'"#<>\*\?\-\+\$\\]+//og;
454         $txt =~ s/\s+$//o;
455         if ($txt =~ /(\d{3}(?:\.\d+)?)/o) {
456                 return $1;
457         } else {
458                 return (split /\s+/, $txt)[0];
459         }
460 $$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
461
462
463 CREATE OR REPLACE FUNCTION actor.org_unit_descendants ( INT ) RETURNS SETOF actor.org_unit AS $$
464         SELECT  a.*
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;
470  
471 CREATE OR REPLACE FUNCTION actor.org_unit_ancestors ( INT ) RETURNS SETOF actor.org_unit AS $$
472         SELECT  a.*
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;
478  
479 CREATE OR REPLACE FUNCTION actor.org_unit_descendants ( INT,INT ) RETURNS SETOF actor.org_unit AS $$
480         SELECT  a.*
481           FROM  connectby('actor.org_unit'::text,'id'::text,'parent_ou'::text,'name'::text,
482                                 (SELECT x.id
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
486                 ,100,'.'::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;
491  
492 ALTER TABLE metabib.rec_descriptor ADD COLUMN date1 TEXT;
493 ALTER TABLE metabib.rec_descriptor ADD COLUMN date2 TEXT;
494
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';
500
501
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;
507
508
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;
512
513 CREATE OR REPLACE FUNCTION asset.merge_record_assets( target_record BIGINT, source_record BIGINT ) RETURNS INT AS $func$
514 DECLARE
515         moved_cns INT := 0;
516         source_cn asset.call_number%ROWTYPE;
517         target_cn asset.call_number%ROWTYPE;
518 BEGIN
519         FOR source_cn IN SELECT * FROM asset.call_number WHERE record = source_record LOOP
520
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;
526
527                 IF FOUND THEN
528                         UPDATE  asset.copy
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;
533                 ELSE
534                         UPDATE  asset.call_number
535                           SET   record = target_record
536                           WHERE id = source_cn.id;
537                 END IF;
538
539                 moved_cns := moved_cns + 1;
540         END LOOP;
541
542         RETURN moved_cns;
543 END;
544 $func$ LANGUAGE plpgsql;
545  
546
547 ALTER TABLE money.billable_xact ADD COLUMN unrecovered BOOL;
548
549 CREATE OR REPLACE VIEW money.billable_xact_summary AS
550         SELECT  xact.id,
551                 xact.usr,
552                 xact.xact_start,
553                 xact.xact_finish,
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
566                 LEFT JOIN (
567                         SELECT  billing.xact,
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
572                           FROM  money.billing
573                           WHERE billing.voided IS FALSE
574                           GROUP BY billing.xact
575                         ) debit ON xact.id = debit.xact
576                 LEFT JOIN (
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;
587  
588 ALTER TABLE action.circulation ADD COLUMN create_time TIMESTAMP WITH TIME ZONE DEFAULT NOW();
589
590
591 CREATE TABLE action.aged_circulation (
592         usr_post_code           TEXT,
593         usr_home_ou             INT     NOT NULL,
594         usr_profile             INT     NOT NULL,
595         usr_birth_year          INT,
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
602
603 );
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);
611
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
620                         UNION ALL
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);
633
634 CREATE OR REPLACE FUNCTION action.age_circ_on_delete () RETURNS TRIGGER AS $$
635 BEGIN
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)
643           SELECT
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;
651
652         RETURN OLD;
653 END;
654 $$ LANGUAGE 'plpgsql';
655
656 CREATE TRIGGER action_circulation_aging_tgr
657         BEFORE DELETE ON action.circulation
658         FOR EACH ROW
659         EXECUTE PROCEDURE action.age_circ_on_delete ();
660
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
663    FROM asset."copy" cp
664    LEFT JOIN extend_reporter.legacy_circ_count c USING (id)
665    LEFT JOIN "action".all_circulation circ ON circ.target_copy = cp.id
666   GROUP BY cp.id;
667
668
669
670 CREATE OR REPLACE FUNCTION search.staged_fts (
671
672     param_search_ou INT,
673     param_depth     INT,
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[],
680     param_types     TEXT[],
681     param_forms     TEXT[],
682     param_vformats  TEXT[],
683     param_bib_level TEXT[],
684     param_before    TEXT,
685     param_after     TEXT,
686     param_during    TEXT,
687     param_between   TEXT[],
688     param_pref_lang TEXT,
689     param_pref_lang_multiplier REAL,
690     param_sort      TEXT,
691     param_sort_desc BOOL,
692     metarecord      BOOL,
693     staff           BOOL,
694     param_rel_limit INT,
695     param_chk_limit INT,
696     param_skip_chk  INT
697  
698 ) RETURNS SETOF search.search_result AS $func$
699 DECLARE
700
701     current_res         search.search_result%ROWTYPE;
702     query_part          search.search_args%ROWTYPE;
703     phrase_query_part   search.search_args%ROWTYPE;
704     rank_adjust_id      INT;
705     core_rel_limit      INT;
706     core_chk_limit      INT;
707     core_skip_chk       INT;
708     rank_adjust         search.relevance_adjustment%ROWTYPE;
709     query_table         TEXT;
710     tmp_text            TEXT;
711     tmp_int             INT;
712     current_rank        TEXT;
713     ranks               TEXT[] := '{}';
714     query_table_alias   TEXT;
715     from_alias_array    TEXT[] := '{}';
716     used_ranks          TEXT[] := '{}';
717     mb_field            INT;
718     mb_field_list       INT[];
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;
725
726     core_result         RECORD;
727     core_cursor         REFCURSOR;
728     core_rel_query      TEXT;
729     vis_limit_query     TEXT;
730     inner_where_clause  TEXT;
731
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;
737
738 BEGIN
739
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 );
743
744     IF metarecord THEN
745         select_clause := select_clause || ' m.metarecord as id, array_accum(distinct m.source) as records,';
746     ELSE
747         select_clause := select_clause || ' m.source as id, array_accum(distinct m.source) as records,';
748     END IF;
749
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
752
753         inner_where_clause := 'index_vector @@ ' || query_part.term;
754
755         IF query_part.field_name IS NOT NULL THEN
756
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;
761
762             IF FOUND THEN
763                 inner_where_clause := inner_where_clause ||
764                     ' AND ' || 'field = ' || mb_field;
765             END IF;
766
767         END IF;
768
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;
774
775         current_rank := query_part.term || ' * ' || query_part.table_alias || '_weight.weight';
776
777         IF query_part.field_name IS NOT NULL THEN
778
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;
783
784         ELSE
785
786            SELECT  array_accum(distinct id) INTO mb_field_list
787              FROM  config.metabib_field
788              WHERE field_class = query_part.field_class;
789
790         END IF;
791
792         FOR rank_adjust IN SELECT * FROM search.relevance_adjustment WHERE active AND field IN ( SELECT * FROM search.explode_array( mb_field_list ) ) LOOP
793
794             IF NOT rank_adjust.bump_type = ANY (used_ranks) THEN
795
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'
800                       ORDER BY id
801                       LIMIT 1;
802
803                     tmp_text := query_part.table_alias || '.value ILIKE ' || quote_literal( tmp_text || '%' );
804
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';
809
810                     tmp_text := query_part.table_alias || '.value ILIKE ' || quote_literal( '%' || tmp_text || '%' );
811
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';
816
817                     tmp_text := query_part.table_alias || '.value  ~ ' || quote_literal( '^' || tmp_text || E'\\W*$' );
818
819                 END IF;
820
821
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 )';
825                 END IF;
826
827                 used_ranks := array_append( used_ranks, rank_adjust.bump_type );
828
829             END IF;
830
831         END LOOP;
832
833         ranks := array_append( ranks, current_rank );
834         used_ranks := '{}';
835
836         FOR phrase_query_part IN
837             SELECT  * 
838               FROM  search.parse_search_args(param_searches)
839               WHERE term_type = 'phrase'
840                     AND table_alias = query_part.table_alias LOOP
841
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'\\]' );
850
851             inner_where_clause := inner_where_clause || ' AND ' || 'value  ~* ' || quote_literal( E'(^|\\W+)' || regexp_replace(tmp_text, E'\\s+',E'\\\\s+','g') || E'(\\W+|\$)' );
852
853         END LOOP;
854
855         query_table := search.pick_table(query_part.field_class);
856
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)';
863
864         from_alias_array := array_append(from_alias_array, query_part.table_alias);
865
866     END LOOP;
867
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 ';
871
872         -- ranks := array_append( ranks, current_rank );
873     END IF;
874
875     current_rank := ' AVG( ( (' || array_to_string( ranks, ') + (' ) || ') ) * ' || current_rank || ' ) ';
876     select_clause := select_clause || current_rank || ' AS rel,';
877
878     sort_desc = param_sort_desc;
879
880     IF param_sort = 'pubdate' THEN
881
882         tmp_text := '999999';
883         IF param_sort_desc THEN tmp_text := '0'; END IF;
884
885         current_rank := $$ COALESCE( FIRST(NULLIF(REGEXP_REPLACE(mrd.date1, E'\\D+', '9', 'g'),'')), $$ || quote_literal(tmp_text) || $$ )::INT $$;
886
887     ELSIF param_sort = 'title' THEN
888
889         tmp_text := 'zzzzzz';
890         IF param_sort_desc THEN tmp_text := '    '; END IF;
891
892         current_rank := $$
893             ( COALESCE( FIRST ((
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
897                     AND frt.tag = '245'
898                     AND frt.subfield = 'a'
899                   LIMIT 1
900             )),$$ || quote_literal(tmp_text) || $$))
901         $$;
902
903     ELSIF param_sort = 'author' THEN
904
905         tmp_text := 'zzzzzz';
906         IF param_sort_desc THEN tmp_text := '    '; END IF;
907
908         current_rank := $$
909             ( COALESCE( FIRST ((
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
916                   LIMIT 1
917             )),$$ || quote_literal(tmp_text) || $$))
918         $$;
919
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)) )$$;
924     ELSE
925         sort_desc := NOT COALESCE(param_sort_desc, FALSE);
926     END IF;
927
928     select_clause := select_clause || current_rank || ' AS rank';
929
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, $$','$$) || $$') $$;
933     END IF;
934
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, $$','$$) || $$') $$;
937     END IF;
938
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, $$','$$) || $$') $$;
941     END IF;
942
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, $$','$$) || $$') $$;
945     END IF;
946
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, $$','$$) || $$') $$;
949     END IF;
950
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, $$','$$) || $$') $$;
953     END IF;
954
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, $$','$$) || $$') $$;
957     END IF;
958
959     IF param_before IS NOT NULL AND param_before <> '' THEN
960         where_clause = where_clause || $$ AND mrd.date1 <= $$ || quote_literal(param_before) || ' ';
961     END IF;
962
963     IF param_after IS NOT NULL AND param_after <> '' THEN
964         where_clause = where_clause || $$ AND mrd.date1 >= $$ || quote_literal(param_after) || ' ';
965     END IF;
966
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 $$;
969     END IF;
970
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 '$$) || $$' $$;
973     END IF;
974
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;
978
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 );
982         ELSE
983             SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou );
984         END IF;
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.
989     END IF;
990
991     OPEN core_cursor FOR EXECUTE core_rel_query;
992
993     LOOP
994
995         FETCH core_cursor INTO core_result;
996         EXIT WHEN NOT FOUND;
997
998
999         IF total_count % 1000 = 0 THEN
1000             -- RAISE NOTICE ' % total, % checked so far ... ', total_count, check_count;
1001         END IF;
1002
1003         IF core_chk_limit > 0 AND total_count - core_skip_chk + 1 >= core_chk_limit THEN
1004             total_count := total_count + 1;
1005             CONTINUE;
1006         END IF;
1007
1008         total_count := total_count + 1;
1009
1010         CONTINUE WHEN param_skip_chk IS NOT NULL and total_count < param_skip_chk;
1011
1012         check_count := check_count + 1;
1013
1014         PERFORM 1 FROM biblio.record_entry b WHERE NOT b.deleted AND b.id IN ( SELECT * FROM search.explode_array( core_result.records ) );
1015         IF NOT FOUND THEN
1016             -- RAISE NOTICE ' % were all deleted ... ', core_result.records;
1017             deleted_count := deleted_count + 1;
1018             CONTINUE;
1019         END IF;
1020
1021         PERFORM 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 ) );
1026
1027         IF FOUND THEN
1028             -- RAISE NOTICE ' % were all transcendant ... ', core_result.records;
1029             visible_count := visible_count + 1;
1030
1031             current_res.id = core_result.id;
1032             current_res.rel = core_result.rel;
1033
1034             tmp_int := 1;
1035             IF metarecord THEN
1036                 SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
1037             END IF;
1038
1039             IF tmp_int = 1 THEN
1040                 current_res.record = core_result.records[1];
1041             ELSE
1042                 current_res.record = NULL;
1043             END IF;
1044
1045             RETURN NEXT current_res;
1046
1047             CONTINUE;
1048         END IF;
1049
1050         IF param_statuses IS NOT NULL AND array_upper(param_statuses, 1) > 0 THEN
1051
1052             PERFORM 1
1053               FROM  asset.call_number cn
1054                     JOIN asset.copy cp ON (cp.call_number = cn.id)
1055               WHERE NOT cn.deleted
1056                     AND NOT cp.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 ) )
1060               LIMIT 1;
1061
1062             IF NOT FOUND THEN
1063                 -- RAISE NOTICE ' % were all status-excluded ... ', core_result.records;
1064                 excluded_count := excluded_count + 1;
1065                 CONTINUE;
1066             END IF;
1067
1068         END IF;
1069
1070         IF param_locations IS NOT NULL AND array_upper(param_locations, 1) > 0 THEN
1071
1072             PERFORM 1
1073               FROM  asset.call_number cn
1074                     JOIN asset.copy cp ON (cp.call_number = cn.id)
1075               WHERE NOT cn.deleted
1076                     AND NOT cp.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 ) )
1080               LIMIT 1;
1081
1082             IF NOT FOUND THEN
1083                 -- RAISE NOTICE ' % were all copy_location-excluded ... ', core_result.records;
1084                 excluded_count := excluded_count + 1;
1085                 CONTINUE;
1086             END IF;
1087
1088         END IF;
1089
1090         IF staff IS NULL OR NOT staff THEN
1091
1092             PERFORM 1
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
1099                     AND NOT cp.deleted
1100                     AND cs.opac_visible
1101                     AND cl.opac_visible
1102                     AND cp.opac_visible
1103                     AND a.opac_visible
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 ) )
1106               LIMIT 1;
1107
1108             IF NOT FOUND THEN
1109                 -- RAISE NOTICE ' % were all visibility-excluded ... ', core_result.records;
1110                 excluded_count := excluded_count + 1;
1111                 CONTINUE;
1112             END IF;
1113
1114         ELSE
1115
1116             PERFORM 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
1122                     AND NOT cp.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 ) )
1125               LIMIT 1;
1126
1127             IF NOT FOUND THEN
1128
1129                 PERFORM 1
1130                   FROM  asset.call_number cn
1131                   WHERE cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
1132                   LIMIT 1;
1133
1134                 IF FOUND THEN
1135                     -- RAISE NOTICE ' % were all visibility-excluded ... ', core_result.records;
1136                     excluded_count := excluded_count + 1;
1137                     CONTINUE;
1138                 END IF;
1139
1140             END IF;
1141
1142         END IF;
1143
1144         visible_count := visible_count + 1;
1145
1146         current_res.id = core_result.id;
1147         current_res.rel = core_result.rel;
1148
1149         tmp_int := 1;
1150         IF metarecord THEN
1151             SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
1152         END IF;
1153
1154         IF tmp_int = 1 THEN
1155             current_res.record = core_result.records[1];
1156         ELSE
1157             current_res.record = NULL;
1158         END IF;
1159
1160         RETURN NEXT current_res;
1161
1162         IF visible_count % 1000 = 0 THEN
1163             -- RAISE NOTICE ' % visible so far ... ', visible_count;
1164         END IF;
1165
1166     END LOOP;
1167
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;
1176
1177     CLOSE core_cursor;
1178
1179     RETURN NEXT current_res;
1180
1181 END;
1182 $func$ LANGUAGE PLPGSQL;
1183
1184 -- This index, right here, is the reason for this change.
1185 DROP INDEX IF EXISTS metabib.metabib_full_rec_value_idx;
1186
1187 -- So, on to it.
1188 -- Move the table out of the way ...
1189 ALTER TABLE metabib.full_rec RENAME TO real_full_rec;
1190
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;
1194 $$ LANGUAGE SQL;
1195
1196 CREATE OR REPLACE FUNCTION reporter.enable_materialized_simple_record_trigger () RETURNS VOID AS $$
1197
1198     TRUNCATE TABLE reporter.materialized_simple_record;
1199
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;
1203
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();
1207
1208 $$ LANGUAGE SQL;
1209
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
1212     SELECT  id,
1213             record,
1214             tag,
1215             ind1,
1216             ind2,
1217             subfield,
1218             SUBSTRING(value,1,1024) AS value,
1219             index_vector
1220       FROM  metabib.real_full_rec;
1221
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
1225     DO INSTEAD
1226     INSERT INTO metabib.real_full_rec VALUES (
1227         COALESCE(NEW.id, NEXTVAL('metabib.full_rec_id_seq'::REGCLASS)),
1228         NEW.record,
1229         NEW.tag,
1230         NEW.ind1,
1231         NEW.ind2,
1232         NEW.subfield,
1233         NEW.value,
1234         NEW.index_vector
1235     );
1236
1237 CREATE OR REPLACE RULE metabib_full_rec_update_rule
1238     AS ON UPDATE TO metabib.full_rec
1239     DO INSTEAD
1240     UPDATE  metabib.real_full_rec SET
1241         id = NEW.id,
1242         record = NEW.record,
1243         tag = NEW.tag,
1244         ind1 = NEW.ind1,
1245         ind2 = NEW.ind2,
1246         subfield = NEW.subfield,
1247         value = NEW.value,
1248         index_vector = NEW.index_vector
1249       WHERE id = OLD.id;
1250
1251 CREATE OR REPLACE RULE metabib_full_rec_delete_rule
1252     AS ON DELETE TO metabib.full_rec
1253     DO INSTEAD
1254     DELETE FROM metabib.real_full_rec WHERE id = OLD.id;
1255
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));
1258
1259
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;
1262 $BODY$
1263 LANGUAGE 'sql' IMMUTABLE;
1264
1265 -- NOTE: current config.item_type should get sip2_media_type and magnetic_media columns
1266
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
1275 );
1276
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 = '';
1279
1280 INSERT INTO config.circ_modifier (code, name, description, sip2_media_type )
1281     SELECT DISTINCT
1282             UPPER(circ_modifier),
1283             UPPER(circ_modifier),
1284             LOWER(circ_modifier),
1285             '001'
1286       FROM  asset.copy
1287       WHERE circ_modifier IS NOT NULL;
1288
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;
1291
1292 -- config table to hold the vr_format names
1293 CREATE TABLE config.videorecording_format_map (
1294         code    TEXT    PRIMARY KEY,
1295         value   TEXT    NOT NULL
1296 );
1297
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');
1316
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,
1326         ref_flag                BOOL,
1327         is_renewal      BOOL,
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)
1331 );
1332 INSERT INTO config.circ_matrix_matchpoint (org_unit,grp) VALUES (1,1);
1333
1334
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 ??
1344 );
1345
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
1352 );
1353
1354
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
1361 );
1362
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$
1364 DECLARE
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;
1371 BEGIN
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;
1376
1377         LOOP 
1378                 -- for each potential matchpoint for this ou and group ...
1379                 FOR current_mp IN
1380                         SELECT  m.*
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
1394
1395                         IF current_mp.circ_modifier IS NOT NULL THEN
1396                                 CONTINUE WHEN current_mp.circ_modifier <> item_object.circ_modifier;
1397                         END IF;
1398
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;
1402                                 ELSE
1403                                         CONTINUE WHEN current_mp.marc_type <> rec_descriptor.item_type;
1404                                 END IF;
1405                         END IF;
1406
1407                         IF current_mp.marc_form IS NOT NULL THEN
1408                                 CONTINUE WHEN current_mp.marc_form <> rec_descriptor.item_form;
1409                         END IF;
1410
1411                         IF current_mp.marc_vr_format IS NOT NULL THEN
1412                                 CONTINUE WHEN current_mp.marc_vr_format <> rec_descriptor.vr_format;
1413                         END IF;
1414
1415                         IF current_mp.ref_flag IS NOT NULL THEN
1416                                 CONTINUE WHEN current_mp.ref_flag <> item_object.ref;
1417                         END IF;
1418
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);
1421                         END IF;
1422
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);
1425                         END IF;
1426
1427
1428                         -- everything was undefined or matched
1429                         matchpoint = current_mp;
1430
1431                         EXIT WHEN matchpoint.id IS NOT NULL;
1432                 END LOOP;
1433
1434                 EXIT WHEN current_group.parent IS NULL OR matchpoint.id IS NOT NULL;
1435
1436                 SELECT INTO current_group * FROM permission.grp_tree WHERE id = current_group.parent;
1437         END LOOP;
1438
1439         RETURN matchpoint.id;
1440 END;
1441 $func$ LANGUAGE plpgsql;
1442
1443
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$
1446 DECLARE
1447         matchpoint_id           INT;
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;
1455         items_out               INT;
1456         items_overdue           INT;
1457         overdue_orgs            INT[];
1458         current_fines           NUMERIC(8,2) := 0.0;
1459         tmp_fines               NUMERIC(8,2);
1460         tmp_groc                RECORD;
1461         tmp_circ                RECORD;
1462         done                    BOOL := FALSE;
1463 BEGIN
1464         result.success := TRUE;
1465
1466         -- Fail if the user is BARRED
1467         SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1468
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;
1473                 done := TRUE;
1474                 RETURN NEXT result;
1475                 RETURN;
1476         END IF;
1477
1478         IF user_object.barred IS TRUE THEN
1479                 result.fail_part := 'actor.usr.barred';
1480                 result.success := FALSE;
1481                 done := TRUE;
1482                 RETURN NEXT result;
1483         END IF;
1484
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;
1490                 done := TRUE;
1491                 RETURN NEXT result;
1492         END IF;
1493
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;
1498                 done := TRUE;
1499                 RETURN NEXT result;
1500         ELSIF renewal AND item_object.status <> 1 THEN
1501                 result.fail_part := 'asset.copy.status';
1502                 result.success := FALSE;
1503                 done := TRUE;
1504                 RETURN NEXT result;
1505         END IF;
1506
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;
1512                 done := TRUE;
1513                 RETURN NEXT result;
1514         END IF;
1515
1516         SELECT INTO matchpoint_id action.find_circ_matrix_matchpoint(circ_ou, match_item, match_user, renewal);
1517         result.matchpoint := matchpoint_id;
1518
1519         SELECT INTO circ_test * from config.circ_matrix_test WHERE matchpoint = result.matchpoint;
1520
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 );
1523         END IF; 
1524
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;
1529                 done := TRUE;
1530                 RETURN NEXT result;
1531         END IF;
1532
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;
1537                 done := TRUE;
1538                 RETURN NEXT result;
1539         END IF;
1540
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;
1552                         done := TRUE;
1553                         RETURN NEXT result;
1554                 END IF;
1555         END IF;
1556
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;
1570                         done := TRUE;
1571                         RETURN NEXT result;
1572                 END IF;
1573         END LOOP;
1574
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;
1587                         done := TRUE;
1588                         RETURN NEXT result;
1589                 END IF;
1590         END IF;
1591
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);
1599                 END LOOP;
1600
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);
1606                 END LOOP;
1607
1608                 IF current_fines >= circ_test.max_fines THEN
1609                         result.fail_part := 'config.circ_matrix_test.max_fines';
1610                         result.success := FALSE;
1611                         RETURN NEXT result;
1612                         done := TRUE;
1613                 END IF;
1614         END IF;
1615
1616         -- If we passed everything, return the successful matchpoint id
1617         IF NOT done THEN
1618                 RETURN NEXT result;
1619         END IF;
1620
1621         RETURN;
1622 END;
1623 $func$ LANGUAGE plpgsql;
1624
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;
1628
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;
1632
1633
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,
1648         ref_flag                BOOL,
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)
1650 );
1651 INSERT INTO config.hold_matrix_matchpoint (requestor_grp) VALUES (1);
1652
1653
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
1664 );
1665
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$
1667 DECLARE
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;
1677         tmp_weight              FLOAT;
1678         current_mp              config.hold_matrix_matchpoint%ROWTYPE;
1679         matchpoint              config.hold_matrix_matchpoint%ROWTYPE;
1680 BEGIN
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;
1688
1689         LOOP 
1690                 -- for each potential matchpoint for this ou and group ...
1691                 FOR current_mp IN
1692                         SELECT  m.*
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
1700
1701                         current_mp_weight := 5.0;
1702
1703                         IF current_mp.circ_modifier IS NOT NULL THEN
1704                                 CONTINUE WHEN current_mp.circ_modifier <> item_object.circ_modifier;
1705                         END IF;
1706
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;
1710                                 ELSE
1711                                         CONTINUE WHEN current_mp.marc_type <> rec_descriptor.item_type;
1712                                 END IF;
1713                         END IF;
1714
1715                         IF current_mp.marc_form IS NOT NULL THEN
1716                                 CONTINUE WHEN current_mp.marc_form <> rec_descriptor.item_form;
1717                         END IF;
1718
1719                         IF current_mp.marc_vr_format IS NOT NULL THEN
1720                                 CONTINUE WHEN current_mp.marc_vr_format <> rec_descriptor.vr_format;
1721                         END IF;
1722
1723                         IF current_mp.ref_flag IS NOT NULL THEN
1724                                 CONTINUE WHEN current_mp.ref_flag <> item_object.ref;
1725                         END IF;
1726
1727
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;
1732                         END IF; 
1733
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;
1737                         END IF; 
1738
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;
1742                         END IF; 
1743
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;
1747                         END IF; 
1748
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;
1752                         END IF; 
1753
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;
1758                         END IF;
1759
1760                 END LOOP;
1761
1762                 EXIT WHEN current_requestor_group.parent IS NULL OR matchpoint.id IS NOT NULL;
1763
1764                 SELECT INTO current_requestor_group * FROM permission.grp_tree WHERE id = current_requestor_group.parent;
1765         END LOOP;
1766
1767         RETURN matchpoint.id;
1768 END;
1769 $func$ LANGUAGE plpgsql;
1770
1771
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$
1773 DECLARE
1774         matchpoint_id           INT;
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;
1782         hold_count              INT;
1783         hold_transit_prox       INT;
1784         frozen_hold_count       INT;
1785         patron_penalties        INT;
1786         done                    BOOL := FALSE;
1787 BEGIN
1788         SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
1789
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;
1794                 done := TRUE;
1795                 RETURN NEXT result;
1796                 RETURN;
1797         END IF;
1798
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;
1803                 done := TRUE;
1804                 RETURN NEXT result;
1805                 RETURN;
1806         END IF;
1807
1808         SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
1809
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;
1814                 done := TRUE;
1815                 RETURN NEXT result;
1816                 RETURN;
1817         END IF;
1818
1819         SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(pickup_ou, request_ou, match_item, match_user, match_requestor);
1820
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;
1825                 done := TRUE;
1826                 RETURN NEXT result;
1827                 RETURN;
1828         END IF;
1829
1830         SELECT INTO hold_test * FROM config.hold_matrix_test WHERE matchpoint = matchpoint_id;
1831
1832         result.matchpoint := matchpoint_id;
1833         result.success := TRUE;
1834
1835         IF hold_test.holdable IS FALSE THEN
1836                 result.fail_part := 'config.hold_matrix_test.holdable';
1837                 result.success := FALSE;
1838                 done := TRUE;
1839                 RETURN NEXT result;
1840         END IF;
1841
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;
1846                 ELSE
1847                         SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
1848                 END IF;
1849
1850                 PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = pickup_ou;
1851
1852                 IF NOT FOUND THEN
1853                         result.fail_part := 'transit_range';
1854                         result.success := FALSE;
1855                         done := TRUE;
1856                         RETURN NEXT result;
1857                 END IF;
1858         END IF;
1859
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;
1864
1865                 IF items_out > 0 THEN
1866                         result.fail_part := 'config.hold_matrix_test.stop_blocked_user';
1867                         result.success := FALSE;
1868                         done := TRUE;
1869                         RETURN NEXT result;
1870                 END IF;
1871         END IF;
1872
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;
1880
1881                 IF items_out >= hold_test.max_holds THEN
1882                         result.fail_part := 'config.hold_matrix_test.max_holds';
1883                         result.success := FALSE;
1884                         done := TRUE;
1885                         RETURN NEXT result;
1886                 END IF;
1887         END IF;
1888
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;
1891
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;
1895                         ELSE
1896                                 SELECT INTO hold_transit_prox prox FROM actor.org_unit_prox WHERE from_org = item_object.circ_lib AND to_org = pickup_ou;
1897                         END IF;
1898
1899                         IF hold_transit_prox > age_protect_object.prox THEN
1900                                 result.fail_part := 'config.rule_age_hold_protect.prox';
1901                                 result.success := FALSE;
1902                                 done := TRUE;
1903                                 RETURN NEXT result;
1904                         END IF;
1905                 END IF;
1906         END IF;
1907
1908         IF NOT done THEN
1909                 RETURN NEXT result;
1910         END IF;
1911
1912         RETURN;
1913 END;
1914 $func$ LANGUAGE plpgsql;
1915
1916 CREATE SCHEMA vandelay;
1917
1918 CREATE TABLE vandelay.queue (
1919         id                              BIGSERIAL       PRIMARY KEY,
1920         owner                   INT                     NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
1921         name                    TEXT            NOT NULL,
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)
1925 );
1926
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')),
1932     marc                TEXT                        NOT NULL
1933 );
1934
1935
1936
1937 /* Bib stuff at the top */
1938 ----------------------------------------------------
1939
1940 CREATE TABLE vandelay.bib_attr_definition (
1941         id                      SERIAL  PRIMARY KEY,
1942         code            TEXT    UNIQUE NOT NULL,
1943         description     TEXT,
1944         xpath           TEXT    NOT NULL,
1945         remove          TEXT    NOT NULL DEFAULT '',
1946         ident           BOOL    NOT NULL DEFAULT FALSE
1947 );
1948
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,
1954     name            TEXT        NOT NULL,
1955     tag             TEXT        NOT NULL,
1956     keep            BOOL        NOT NULL DEFAULT FALSE,
1957     owning_lib      TEXT,
1958     circ_lib        TEXT,
1959     call_number     TEXT,
1960     copy_number     TEXT,
1961     status          TEXT,
1962     location        TEXT,
1963     circulate       TEXT,
1964     deposit         TEXT,
1965     deposit_amount  TEXT,
1966     ref             TEXT,
1967     holdable        TEXT,
1968     price           TEXT,
1969     barcode         TEXT,
1970     circ_modifier   TEXT,
1971     circ_as_type    TEXT,
1972     alert_message   TEXT,
1973     opac_visible    TEXT,
1974     pub_note_title  TEXT,
1975     pub_note        TEXT,
1976     priv_note_title TEXT,
1977     priv_note       TEXT,
1978         CONSTRAINT vand_import_item_attr_def_idx UNIQUE (owner,name)
1979 );
1980
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);
1987
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);
1994
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
2000 );
2001
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
2008 );
2009
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,
2015     owning_lib      INT,
2016     circ_lib        INT,
2017     call_number     TEXT,
2018     copy_number     INT,
2019     status          INT,
2020     location        INT,
2021     circulate       BOOL,
2022     deposit         BOOL,
2023     deposit_amount  NUMERIC(8,2),
2024     ref             BOOL,
2025     holdable        BOOL,
2026     price           NUMERIC(8,2),
2027     barcode         TEXT,
2028     circ_modifier   TEXT,
2029     circ_as_type    TEXT,
2030     alert_message   TEXT,
2031     pub_note        TEXT,
2032     priv_note       TEXT,
2033     opac_visible    BOOL
2034 );
2035  
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)
2041 );
2042
2043 CREATE OR REPLACE FUNCTION vandelay.strip_field ( xml TEXT, field TEXT ) RETURNS TEXT AS $_$
2044
2045     use MARC::Record;
2046     use MARC::File::XML;
2047
2048     my $xml = shift;
2049     my $field_spec = shift;
2050
2051     my $r = MARC::Record->new_from_xml( $xml );
2052     $r->delete_field( $_ ) for ( $r->field( $field_spec ) );
2053
2054     $xml = $r->as_xml_record;
2055     $xml =~ s/^<\?.+?\?>$//mo;
2056     $xml =~ s/\n//sgo;
2057     $xml =~ s/>\s+</></sgo;
2058
2059     return $xml;
2060
2061 $_$ LANGUAGE PLPERLU;
2062
2063
2064 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
2065 DECLARE
2066
2067     owning_lib      TEXT;
2068     circ_lib        TEXT;
2069     call_number     TEXT;
2070     copy_number     TEXT;
2071     status          TEXT;
2072     location        TEXT;
2073     circulate       TEXT;
2074     deposit         TEXT;
2075     deposit_amount  TEXT;
2076     ref             TEXT;
2077     holdable        TEXT;
2078     price           TEXT;
2079     barcode         TEXT;
2080     circ_modifier   TEXT;
2081     circ_as_type    TEXT;
2082     alert_message   TEXT;
2083     opac_visible    TEXT;
2084     pub_note        TEXT;
2085     priv_note       TEXT;
2086
2087     attr_def        RECORD;
2088     tmp_attr_set    RECORD;
2089     attr_set        vandelay.import_item%ROWTYPE;
2090
2091     xpath           TEXT;
2092
2093 BEGIN
2094
2095     SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
2096
2097     IF FOUND THEN
2098
2099         attr_set.definition := attr_def.id; 
2100     
2101         -- Build the combined XPath
2102     
2103         owning_lib :=
2104             CASE
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
2108             END;
2109     
2110         circ_lib :=
2111             CASE
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
2115             END;
2116     
2117         call_number :=
2118             CASE
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
2122             END;
2123     
2124         copy_number :=
2125             CASE
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
2129             END;
2130     
2131         status :=
2132             CASE
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
2136             END;
2137     
2138         location :=
2139             CASE
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
2143             END;
2144     
2145         circulate :=
2146             CASE
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
2150             END;
2151     
2152         deposit :=
2153             CASE
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
2157             END;
2158     
2159         deposit_amount :=
2160             CASE
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
2164             END;
2165     
2166         ref :=
2167             CASE
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
2171             END;
2172     
2173         holdable :=
2174             CASE
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
2178             END;
2179     
2180         price :=
2181             CASE
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
2185             END;
2186     
2187         barcode :=
2188             CASE
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
2192             END;
2193     
2194         circ_modifier :=
2195             CASE
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
2199             END;
2200     
2201         circ_as_type :=
2202             CASE
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
2206             END;
2207     
2208         alert_message :=
2209             CASE
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
2213             END;
2214     
2215         opac_visible :=
2216             CASE
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
2220             END;
2221
2222         pub_note :=
2223             CASE
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
2227             END;
2228         priv_note :=
2229             CASE
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
2233             END;
2234     
2235     
2236         xpath := 
2237             owning_lib      || '|' || 
2238             circ_lib        || '|' || 
2239             call_number     || '|' || 
2240             copy_number     || '|' || 
2241             status          || '|' || 
2242             location        || '|' || 
2243             circulate       || '|' || 
2244             deposit         || '|' || 
2245             deposit_amount  || '|' || 
2246             ref             || '|' || 
2247             holdable        || '|' || 
2248             price           || '|' || 
2249             barcode         || '|' || 
2250             circ_modifier   || '|' || 
2251             circ_as_type    || '|' || 
2252             alert_message   || '|' || 
2253             pub_note        || '|' || 
2254             priv_note       || '|' || 
2255             opac_visible;
2256
2257         -- RAISE NOTICE 'XPath: %', xpath;
2258         
2259         FOR tmp_attr_set IN
2260                 SELECT  *
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 )
2265         LOOP
2266     
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');
2269
2270             tmp_attr_set.pr := NULLIF( tmp_attr_set.pr, '' );
2271             tmp_attr_set.dep_amount := NULLIF( tmp_attr_set.dep_amount, '' );
2272     
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
2276     
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
2281     
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
2285
2286             attr_set.deposit        :=
2287                 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
2288                 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
2289
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
2293
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
2297
2298             attr_set.ref            :=
2299                 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
2300                 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
2301     
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),
2305     
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,
2314     
2315             RETURN NEXT attr_set;
2316     
2317         END LOOP;
2318     
2319     END IF;
2320
2321 END;
2322 $$ LANGUAGE PLPGSQL;
2323
2324
2325 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_marc ( ) RETURNS TRIGGER AS $$
2326 DECLARE
2327     value   TEXT;
2328     atype   TEXT;
2329     adef    RECORD;
2330 BEGIN
2331     FOR adef IN SELECT * FROM vandelay.bib_attr_definition LOOP
2332
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);
2336         END IF;
2337
2338     END LOOP;
2339
2340     RETURN NULL;
2341 END;
2342 $$ LANGUAGE PLPGSQL;
2343
2344 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_items ( ) RETURNS TRIGGER AS $func$
2345 DECLARE
2346     queue_rec   RECORD;
2347     item_rule   RECORD;
2348     item_data   vandelay.import_item%ROWTYPE;
2349 BEGIN
2350
2351     SELECT * INTO queue_rec FROM vandelay.bib_queue WHERE id = NEW.queue;
2352
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 (
2356                 record,
2357                 definition,
2358                 owning_lib,
2359                 circ_lib,
2360                 call_number,
2361                 copy_number,
2362                 status,
2363                 location,
2364                 circulate,
2365                 deposit,
2366                 deposit_amount,
2367                 ref,
2368                 holdable,
2369                 price,
2370                 barcode,
2371                 circ_modifier,
2372                 circ_as_type,
2373                 alert_message,
2374                 pub_note,
2375                 priv_note,
2376                 opac_visible
2377             ) VALUES (
2378                 NEW.id,
2379                 item_data.definition,
2380                 item_data.owning_lib,
2381                 item_data.circ_lib,
2382                 item_data.call_number,
2383                 item_data.copy_number,
2384                 item_data.status,
2385                 item_data.location,
2386                 item_data.circulate,
2387                 item_data.deposit,
2388                 item_data.deposit_amount,
2389                 item_data.ref,
2390                 item_data.holdable,
2391                 item_data.price,
2392                 item_data.barcode,
2393                 item_data.circ_modifier,
2394                 item_data.circ_as_type,
2395                 item_data.alert_message,
2396                 item_data.pub_note,
2397                 item_data.priv_note,
2398                 item_data.opac_visible
2399             );
2400         END LOOP;
2401     END LOOP;
2402
2403     RETURN NULL;
2404 END;
2405 $func$ LANGUAGE PLPGSQL;
2406
2407 CREATE OR REPLACE FUNCTION vandelay.match_bib_record ( ) RETURNS TRIGGER AS $func$
2408 DECLARE
2409     attr    RECORD;
2410     eg_rec  RECORD;
2411 BEGIN
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
2413
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);
2418                         END LOOP;
2419                 END IF;
2420
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;
2425                                 IF FOUND THEN
2426                                 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('isbn', attr.id, NEW.id, eg_rec.record);
2427                                 END IF;
2428                         END LOOP;
2429
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);
2433                 END LOOP;
2434                 END IF;
2435
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);
2440                 END LOOP;
2441                 END IF;
2442
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);
2446         END LOOP;
2447
2448     END LOOP;
2449
2450     RETURN NULL;
2451 END;
2452 $func$ LANGUAGE PLPGSQL;
2453
2454 CREATE OR REPLACE FUNCTION vandelay.cleanup_bib_marc ( ) RETURNS TRIGGER AS $$
2455 BEGIN
2456     DELETE FROM vandelay.queued_bib_record_attr WHERE record = OLD.id;
2457     DELETE FROM vandelay.import_item WHERE record = OLD.id;
2458
2459     IF TG_OP = 'UPDATE' THEN
2460         RETURN NEW;
2461     END IF;
2462     RETURN OLD;
2463 END;
2464 $$ LANGUAGE PLPGSQL;
2465
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();
2469
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();
2473
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();
2477
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();
2481
2482
2483 /* Authority stuff down here */
2484 ---------------------------------------
2485 CREATE TABLE vandelay.authority_attr_definition (
2486         id                      SERIAL  PRIMARY KEY,
2487         code            TEXT    UNIQUE NOT NULL,
2488         description     TEXT,
2489         xpath           TEXT    NOT NULL,
2490         remove          TEXT    NOT NULL DEFAULT '',
2491         ident           BOOL    NOT NULL DEFAULT FALSE
2492 );
2493
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);
2499
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);
2505
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
2511 );
2512
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
2518 );
2519
2520 CREATE OR REPLACE FUNCTION vandelay.ingest_authority_marc ( ) RETURNS TRIGGER AS $$
2521 DECLARE
2522     value   TEXT;
2523     atype   TEXT;
2524     adef    RECORD;
2525 BEGIN
2526     FOR adef IN SELECT * FROM vandelay.authority_attr_definition LOOP
2527
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);
2531         END IF;
2532
2533     END LOOP;
2534
2535     RETURN NULL;
2536 END;
2537 $$ LANGUAGE PLPGSQL;
2538
2539 CREATE OR REPLACE FUNCTION vandelay.cleanup_authority_marc ( ) RETURNS TRIGGER AS $$
2540 BEGIN
2541     DELETE FROM vandelay.queued_authority_record_attr WHERE record = OLD.id;
2542     IF TG_OP = 'UPDATE' THEN
2543         RETURN NEW;
2544     END IF;
2545     RETURN OLD;
2546 END;
2547 $$ LANGUAGE PLPGSQL;
2548
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();
2552
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();
2556
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]');
2571
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
2576 ) VALUES (
2577     1,
2578     'Evergreen 852 export format',
2579     '852',
2580     '[@code = "b"][1]',
2581     '[@code = "b"][2]',
2582     'c',
2583     'j',
2584     'g',
2585     'p',
2586     'y',
2587     't',
2588     '[@code = "x" and text() = "circulating"]',
2589     '[@code = "x" and text() = "reference"]',
2590     '[@code = "x" and text() = "holdable"]',
2591     '[@code = "x" and text() = "visible"]',
2592     'z'
2593 );
2594
2595 INSERT INTO vandelay.import_item_attr_definition (
2596     owner,
2597     name,
2598     tag,
2599     owning_lib,
2600     location,
2601     call_number,
2602     circ_modifier,
2603     barcode,
2604     price,
2605     status
2606 ) VALUES (
2607     1,
2608     'Unicorn Import format -- 999',
2609     '999',
2610     'm',
2611     'l',
2612     'a',
2613     't',
2614     'i',
2615     'p',
2616     'k'
2617 );
2618
2619 CREATE OR REPLACE VIEW extend_reporter.global_bibs_by_holding_update AS
2620   SELECT DISTINCT ON (id) id, holding_update, update_type
2621     FROM (SELECT  b.id,
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
2628                   AND b.id > 0
2629             GROUP BY b.id
2630               UNION
2631           SELECT  b.id,
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)
2637             WHERE cp.deleted
2638                   AND b.id > 0
2639             GROUP BY b.id)x
2640     ORDER BY id, holding_update;
2641
2642 INSERT INTO vandelay.authority_attr_definition ( code, description, xpath, ident ) VALUES ('rec_identifier','Identifier','//*[@tag="001"]', TRUE);
2643
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"/>
2647 <!--
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
2650
2651 Revision 1.13 - Changed order of output under cartographics to reflect schema  2006/11/28 tmee
2652         
2653 Revision 1.12 - Updated to reflect MODS 3.2 Mapping  2006/10/11 tmee
2654                 
2655 Revision 1.11 - The attribute objectPart moved from <languageTerm> to <language>
2656       2006/04/08  jrad
2657
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)
2660                                 2006/02/06  ggar
2661
2662 Revision 1.9 subfield $y was added to field 242 2004/09/02 10:57 jrad
2663
2664 Revision 1.8 Subject chopPunctuation expanded and attribute fixes 2004/08/12 jrad
2665
2666 Revision 1.7 2004/03/25 08:29 jrad
2667
2668 Revision 1.6 various validation fixes 2004/02/20 ntra
2669
2670 Revision 1.5  2003/10/02 16:18:58  ntra
2671 MODS2 to MODS3 updates, language unstacking and 
2672 de-duping, chopPunctuation expanded
2673
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
2676
2677 Revision 1.2  2003/03/24 19:37:42  ckeith
2678 Added Log Comment
2679
2680 -->
2681         <xsl:template match="/">
2682                 <xsl:choose>
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"/>
2688                                                 </mods>
2689                                         </xsl:for-each>
2690                                 </modsCollection>
2691                         </xsl:when>
2692                         <xsl:otherwise>
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"/>
2696                                         </xsl:for-each>
2697                                 </mods>
2698                         </xsl:otherwise>
2699                 </xsl:choose>
2700         </xsl:template>
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">
2707                         <xsl:choose>
2708                                 <xsl:when test="$leader6='a'">
2709                                         <xsl:choose>
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>
2712                                         </xsl:choose>
2713                                 </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>
2720                         </xsl:choose>
2721                 </xsl:variable>
2722                 <xsl:for-each select="marc:datafield[@tag='245']">
2723                         <titleInfo>
2724                                 <xsl:variable name="title">
2725                                         <xsl:choose>
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>
2731                                                 </xsl:when>
2732                                                 <xsl:otherwise>
2733                                                         <xsl:call-template name="subfieldSelect">
2734                                                                 <xsl:with-param name="codes">abfgk</xsl:with-param>
2735                                                         </xsl:call-template>
2736                                                 </xsl:otherwise>
2737                                         </xsl:choose>
2738                                 </xsl:variable>
2739                                 <xsl:variable name="titleChop">
2740                                         <xsl:call-template name="chopPunctuation">
2741                                                 <xsl:with-param name="chopString">
2742                                                         <xsl:value-of select="$title"/>
2743                                                 </xsl:with-param>
2744                                         </xsl:call-template>
2745                                 </xsl:variable>
2746                                 <xsl:choose>
2747                                         <xsl:when test="@ind2>0">
2748                                                 <nonSort>
2749                                                         <xsl:value-of select="substring($titleChop,1,@ind2)"/>
2750                                                 </nonSort>
2751                                                 <title>
2752                                                         <xsl:value-of select="substring($titleChop,@ind2+1)"/>
2753                                                 </title>
2754                                         </xsl:when>
2755                                         <xsl:otherwise>
2756                                                 <title>
2757                                                         <xsl:value-of select="$titleChop"/>
2758                                                 </title>
2759                                         </xsl:otherwise>
2760                                 </xsl:choose>
2761                                 <xsl:if test="marc:subfield[@code='b']">
2762                                         <subTitle>
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>
2770                                                         </xsl:with-param>
2771                                                 </xsl:call-template>
2772                                         </subTitle>
2773                                 </xsl:if>
2774                                 <xsl:call-template name="part"></xsl:call-template>
2775                         </titleInfo>
2776                 </xsl:for-each>
2777                 <xsl:for-each select="marc:datafield[@tag='210']">
2778                         <titleInfo type="abbreviated">
2779                                 <title>
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>
2785                                                 </xsl:with-param>
2786                                         </xsl:call-template>
2787                                 </title>
2788                                 <xsl:call-template name="subtitle"/>
2789                         </titleInfo>
2790                 </xsl:for-each>
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()"/>
2797                                         </xsl:attribute>
2798                                 </xsl:for-each>
2799                                 <title>
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>
2806                                                 </xsl:with-param>
2807                                         </xsl:call-template>
2808                                 </title>
2809                                 <!-- 1/04 fix -->
2810                                 <xsl:call-template name="subtitle"/>
2811                                 <xsl:call-template name="part"/>
2812                         </titleInfo>
2813                 </xsl:for-each>
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()"/>
2819                                         </xsl:attribute>
2820                                 </xsl:for-each>
2821                                 <title>
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>
2828                                                 </xsl:with-param>
2829                                         </xsl:call-template>
2830                                 </title>
2831                                 <xsl:call-template name="subtitle"/>
2832                                 <xsl:call-template name="part"/>
2833                         </titleInfo>
2834                 </xsl:for-each>
2835                 <xsl:for-each select="marc:datafield[@tag='130']|marc:datafield[@tag='240']|marc:datafield[@tag='730'][@ind2!='2']">
2836                         <titleInfo type="uniform">
2837                                 <title>
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>
2843                                                         </xsl:if>
2844                                                 </xsl:for-each>
2845                                         </xsl:variable>
2846                                         <xsl:call-template name="chopPunctuation">
2847                                                 <xsl:with-param name="chopString">
2848                                                         <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
2849                                                 </xsl:with-param>
2850                                         </xsl:call-template>
2851                                 </title>
2852                                 <xsl:call-template name="part"/>
2853                         </titleInfo>
2854                 </xsl:for-each>
2855                 <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
2856                         <titleInfo type="alternative">
2857                                 <title>
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>
2863                                                 </xsl:with-param>
2864                                         </xsl:call-template>
2865                                 </title>
2866                                 <xsl:call-template name="part"/>
2867                         </titleInfo>
2868                 </xsl:for-each>
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"/>
2873                                 <role>
2874                                         <roleTerm authority="marcrelator" type="text">creator</roleTerm>
2875                                 </role>
2876                                 <xsl:call-template name="role"/>
2877                         </name>
2878                 </xsl:for-each>
2879                 <xsl:for-each select="marc:datafield[@tag='110']">
2880                         <name type="corporate">
2881                                 <xsl:call-template name="nameABCDN"/>
2882                                 <role>
2883                                         <roleTerm authority="marcrelator" type="text">creator</roleTerm>
2884                                 </role>
2885                                 <xsl:call-template name="role"/>
2886                         </name>
2887                 </xsl:for-each>
2888                 <xsl:for-each select="marc:datafield[@tag='111']">
2889                         <name type="conference">
2890                                 <xsl:call-template name="nameACDEQ"/>
2891                                 <role>
2892                                         <roleTerm authority="marcrelator" type="text">creator</roleTerm>
2893                                 </role>
2894                                 <xsl:call-template name="role"/>
2895                         </name>
2896                 </xsl:for-each>
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"/>
2902                         </name>
2903                 </xsl:for-each>
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"/>
2908                         </name>
2909                 </xsl:for-each>
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"/>
2914                         </name>
2915                 </xsl:for-each>
2916                 <xsl:for-each select="marc:datafield[@tag='720'][not(marc:subfield[@code='t'])]">
2917                         <name>
2918                                 <xsl:if test="@ind1=1">
2919                                         <xsl:attribute name="type">
2920                                                 <xsl:text>personal</xsl:text>
2921                                         </xsl:attribute>
2922                                 </xsl:if>
2923                                 <namePart>
2924                                         <xsl:value-of select="marc:subfield[@code='a']"/>
2925                                 </namePart>
2926                                 <xsl:call-template name="role"/>
2927                         </name>
2928                 </xsl:for-each>
2929                 <typeOfResource>
2930                         <xsl:if test="$leader7='c'">
2931                                 <xsl:attribute name="collection">yes</xsl:attribute>
2932                         </xsl:if>
2933                         <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
2934                                 <xsl:attribute name="manuscript">yes</xsl:attribute>
2935                         </xsl:if>
2936                         <xsl:choose>
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>
2947                         </xsl:choose>
2948                 </typeOfResource>
2949                 <xsl:if test="substring($controlField008,26,1)='d'">
2950                         <genre authority="marc">globe</genre>
2951                 </xsl:if>
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>
2954                 </xsl:if>
2955                 <xsl:if test="$typeOf008='MP'">
2956                         <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"></xsl:variable>
2957                         <xsl:choose>
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>
2960                                 </xsl:when>
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>
2963                                 </xsl:when>
2964                         </xsl:choose>
2965                 </xsl:if>
2966                 <xsl:if test="$typeOf008='SE'">
2967                         <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"></xsl:variable>
2968                         <xsl:choose>
2969                                 <xsl:when test="$controlField008-21='d'">
2970                                         <genre authority="marc">database</genre>
2971                                 </xsl:when>
2972                                 <xsl:when test="$controlField008-21='l'">
2973                                         <genre authority="marc">loose-leaf</genre>
2974                                 </xsl:when>
2975                                 <xsl:when test="$controlField008-21='m'">
2976                                         <genre authority="marc">series</genre>
2977                                 </xsl:when>
2978                                 <xsl:when test="$controlField008-21='n'">
2979                                         <genre authority="marc">newspaper</genre>
2980                                 </xsl:when>
2981                                 <xsl:when test="$controlField008-21='p'">
2982                                         <genre authority="marc">periodical</genre>
2983                                 </xsl:when>
2984                                 <xsl:when test="$controlField008-21='w'">
2985                                         <genre authority="marc">web site</genre>
2986                                 </xsl:when>
2987                         </xsl:choose>
2988                 </xsl:if>
2989                 <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
2990                         <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"></xsl:variable>
2991                         <xsl:choose>
2992                                 <xsl:when test="contains($controlField008-24,'a')">
2993                                         <genre authority="marc">abstract or summary</genre>
2994                                 </xsl:when>
2995                                 <xsl:when test="contains($controlField008-24,'b')">
2996                                         <genre authority="marc">bibliography</genre>
2997                                 </xsl:when>
2998                                 <xsl:when test="contains($controlField008-24,'c')">
2999                                         <genre authority="marc">catalog</genre>
3000                                 </xsl:when>
3001                                 <xsl:when test="contains($controlField008-24,'d')">
3002                                         <genre authority="marc">dictionary</genre>
3003                                 </xsl:when>
3004                                 <xsl:when test="contains($controlField008-24,'e')">
3005                                         <genre authority="marc">encyclopedia</genre>
3006                                 </xsl:when>
3007                                 <xsl:when test="contains($controlField008-24,'f')">
3008                                         <genre authority="marc">handbook</genre>
3009                                 </xsl:when>
3010                                 <xsl:when test="contains($controlField008-24,'g')">
3011                                         <genre authority="marc">legal article</genre>
3012                                 </xsl:when>
3013                                 <xsl:when test="contains($controlField008-24,'i')">
3014                                         <genre authority="marc">index</genre>
3015                                 </xsl:when>
3016                                 <xsl:when test="contains($controlField008-24,'k')">
3017                                         <genre authority="marc">discography</genre>
3018                                 </xsl:when>
3019                                 <xsl:when test="contains($controlField008-24,'l')">
3020                                         <genre authority="marc">legislation</genre>
3021                                 </xsl:when>
3022                                 <xsl:when test="contains($controlField008-24,'m')">
3023                                         <genre authority="marc">theses</genre>
3024                                 </xsl:when>
3025                                 <xsl:when test="contains($controlField008-24,'n')">
3026                                         <genre authority="marc">survey of literature</genre>
3027                                 </xsl:when>
3028                                 <xsl:when test="contains($controlField008-24,'o')">
3029                                         <genre authority="marc">review</genre>
3030                                 </xsl:when>
3031                                 <xsl:when test="contains($controlField008-24,'p')">
3032                                         <genre authority="marc">programmed text</genre>
3033                                 </xsl:when>
3034                                 <xsl:when test="contains($controlField008-24,'q')">
3035                                         <genre authority="marc">filmography</genre>
3036                                 </xsl:when>
3037                                 <xsl:when test="contains($controlField008-24,'r')">
3038                                         <genre authority="marc">directory</genre>
3039                                 </xsl:when>
3040                                 <xsl:when test="contains($controlField008-24,'s')">
3041                                         <genre authority="marc">statistics</genre>
3042                                 </xsl:when>
3043                                 <xsl:when test="contains($controlField008-24,'t')">
3044                                         <genre authority="marc">technical report</genre>
3045                                 </xsl:when>
3046                                 <xsl:when test="contains($controlField008-24,'v')">
3047                                         <genre authority="marc">legal case and case notes</genre>
3048                                 </xsl:when>
3049                                 <xsl:when test="contains($controlField008-24,'w')">
3050                                         <genre authority="marc">law report or digest</genre>
3051                                 </xsl:when>
3052                                 <xsl:when test="contains($controlField008-24,'z')">
3053                                         <genre authority="marc">treaty</genre>
3054                                 </xsl:when>
3055                         </xsl:choose>
3056                         <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
3057                         <xsl:choose>
3058                                 <xsl:when test="$controlField008-29='1'">
3059                                         <genre authority="marc">conference publication</genre>
3060                                 </xsl:when>
3061                         </xsl:choose>
3062                 </xsl:if>
3063                 <xsl:if test="$typeOf008='CF'">
3064                         <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"></xsl:variable>
3065                         <xsl:choose>
3066                                 <xsl:when test="$controlField008-26='a'">
3067                                         <genre authority="marc">numeric data</genre>
3068                                 </xsl:when>
3069                                 <xsl:when test="$controlField008-26='e'">
3070                                         <genre authority="marc">database</genre>
3071                                 </xsl:when>
3072                                 <xsl:when test="$controlField008-26='f'">
3073                                         <genre authority="marc">font</genre>
3074                                 </xsl:when>
3075                                 <xsl:when test="$controlField008-26='g'">
3076                                         <genre authority="marc">game</genre>
3077                                 </xsl:when>
3078                         </xsl:choose>
3079                 </xsl:if>
3080                 <xsl:if test="$typeOf008='BK'">
3081                         <xsl:if test="substring($controlField008,25,1)='j'">
3082                                 <genre authority="marc">patent</genre>
3083                         </xsl:if>
3084                         <xsl:if test="substring($controlField008,31,1)='1'">
3085                                 <genre authority="marc">festschrift</genre>
3086                         </xsl:if>
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>
3090                         </xsl:if>
3091                         <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
3092                         <xsl:choose>
3093                                 <xsl:when test="$controlField008-33='e'">
3094                                         <genre authority="marc">essay</genre>
3095                                 </xsl:when>
3096                                 <xsl:when test="$controlField008-33='d'">
3097                                         <genre authority="marc">drama</genre>
3098                                 </xsl:when>
3099                                 <xsl:when test="$controlField008-33='c'">
3100                                         <genre authority="marc">comic strip</genre>
3101                                 </xsl:when>
3102                                 <xsl:when test="$controlField008-33='l'">
3103                                         <genre authority="marc">fiction</genre>
3104                                 </xsl:when>
3105                                 <xsl:when test="$controlField008-33='h'">
3106                                         <genre authority="marc">humor, satire</genre>
3107                                 </xsl:when>
3108                                 <xsl:when test="$controlField008-33='i'">
3109                                         <genre authority="marc">letter</genre>
3110                                 </xsl:when>
3111                                 <xsl:when test="$controlField008-33='f'">
3112                                         <genre authority="marc">novel</genre>
3113                                 </xsl:when>
3114                                 <xsl:when test="$controlField008-33='j'">
3115                                         <genre authority="marc">short story</genre>
3116                                 </xsl:when>
3117                                 <xsl:when test="$controlField008-33='s'">
3118                                         <genre authority="marc">speech</genre>
3119                                 </xsl:when>
3120                         </xsl:choose>
3121                 </xsl:if>
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>
3126                         </xsl:if>
3127                         <xsl:if test="contains($controlField008-30-31,'c')">
3128                                 <genre authority="marc">conference publication</genre>
3129                         </xsl:if>
3130                         <xsl:if test="contains($controlField008-30-31,'d')">
3131                                 <genre authority="marc">drama</genre>
3132                         </xsl:if>
3133                         <xsl:if test="contains($controlField008-30-31,'e')">
3134                                 <genre authority="marc">essay</genre>
3135                         </xsl:if>
3136                         <xsl:if test="contains($controlField008-30-31,'f')">
3137                                 <genre authority="marc">fiction</genre>
3138                         </xsl:if>
3139                         <xsl:if test="contains($controlField008-30-31,'o')">
3140                                 <genre authority="marc">folktale</genre>
3141                         </xsl:if>
3142                         <xsl:if test="contains($controlField008-30-31,'h')">
3143                                 <genre authority="marc">history</genre>
3144                         </xsl:if>
3145                         <xsl:if test="contains($controlField008-30-31,'k')">
3146                                 <genre authority="marc">humor, satire</genre>
3147                         </xsl:if>
3148                         <xsl:if test="contains($controlField008-30-31,'m')">
3149                                 <genre authority="marc">memoir</genre>
3150                         </xsl:if>
3151                         <xsl:if test="contains($controlField008-30-31,'p')">
3152                                 <genre authority="marc">poetry</genre>
3153                         </xsl:if>
3154                         <xsl:if test="contains($controlField008-30-31,'r')">
3155                                 <genre authority="marc">rehearsal</genre>
3156                         </xsl:if>
3157                         <xsl:if test="contains($controlField008-30-31,'g')">
3158                                 <genre authority="marc">reporting</genre>
3159                         </xsl:if>
3160                         <xsl:if test="contains($controlField008-30-31,'s')">
3161                                 <genre authority="marc">sound</genre>
3162                         </xsl:if>
3163                         <xsl:if test="contains($controlField008-30-31,'l')">
3164                                 <genre authority="marc">speech</genre>
3165                         </xsl:if>
3166                 </xsl:if>
3167                 <xsl:if test="$typeOf008='VM'">
3168                         <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
3169                         <xsl:choose>
3170                                 <xsl:when test="$controlField008-33='a'">
3171                                         <genre authority="marc">art original</genre>
3172                                 </xsl:when>
3173                                 <xsl:when test="$controlField008-33='b'">
3174                                         <genre authority="marc">kit</genre>
3175                                 </xsl:when>
3176                                 <xsl:when test="$controlField008-33='c'">
3177                                         <genre authority="marc">art reproduction</genre>
3178                                 </xsl:when>
3179                                 <xsl:when test="$controlField008-33='d'">
3180                                         <genre authority="marc">diorama</genre>
3181                                 </xsl:when>
3182                                 <xsl:when test="$controlField008-33='f'">
3183                                         <genre authority="marc">filmstrip</genre>
3184                                 </xsl:when>
3185                                 <xsl:when test="$controlField008-33='g'">
3186                                         <genre authority="marc">legal article</genre>
3187                                 </xsl:when>
3188                                 <xsl:when test="$controlField008-33='i'">
3189                                         <genre authority="marc">picture</genre>
3190                                 </xsl:when>
3191                                 <xsl:when test="$controlField008-33='k'">
3192                                         <genre authority="marc">graphic</genre>
3193                                 </xsl:when>
3194                                 <xsl:when test="$controlField008-33='l'">
3195                                         <genre authority="marc">technical drawing</genre>
3196                                 </xsl:when>
3197                                 <xsl:when test="$controlField008-33='m'">
3198                                         <genre authority="marc">motion picture</genre>
3199                                 </xsl:when>
3200                                 <xsl:when test="$controlField008-33='n'">
3201                                         <genre authority="marc">chart</genre>
3202                                 </xsl:when>
3203                                 <xsl:when test="$controlField008-33='o'">
3204                                         <genre authority="marc">flash card</genre>
3205                                 </xsl:when>
3206                                 <xsl:when test="$controlField008-33='p'">
3207                                         <genre authority="marc">microscope slide</genre>
3208                                 </xsl:when>
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>
3211                                 </xsl:when>
3212                                 <xsl:when test="$controlField008-33='r'">
3213                                         <genre authority="marc">realia</genre>
3214                                 </xsl:when>
3215                                 <xsl:when test="$controlField008-33='s'">
3216                                         <genre authority="marc">slide</genre>
3217                                 </xsl:when>
3218                                 <xsl:when test="$controlField008-33='t'">
3219                                         <genre authority="marc">transparency</genre>
3220                                 </xsl:when>
3221                                 <xsl:when test="$controlField008-33='v'">
3222                                         <genre authority="marc">videorecording</genre>
3223                                 </xsl:when>
3224                                 <xsl:when test="$controlField008-33='w'">
3225                                         <genre authority="marc">toy</genre>
3226                                 </xsl:when>
3227                         </xsl:choose>
3228                 </xsl:if>
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']"/>
3233                                 </xsl:attribute>
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>
3238                         </genre>
3239                 </xsl:for-each>
3240                 <originInfo>
3241                         <xsl:variable name="MARCpublicationCode" select="normalize-space(substring($controlField008,16,3))"></xsl:variable>
3242                         <xsl:if test="translate($MARCpublicationCode,'|','')">
3243                                 <place>
3244                                         <placeTerm>
3245                                                 <xsl:attribute name="type">code</xsl:attribute>
3246                                                 <xsl:attribute name="authority">marccountry</xsl:attribute>
3247                                                 <xsl:value-of select="$MARCpublicationCode"/>
3248                                         </placeTerm>
3249                                 </place>
3250                         </xsl:if>
3251                         <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
3252                                 <place>
3253                                         <placeTerm>
3254                                                 <xsl:attribute name="type">code</xsl:attribute>
3255                                                 <xsl:attribute name="authority">iso3166</xsl:attribute>
3256                                                 <xsl:value-of select="."/>
3257                                         </placeTerm>
3258                                 </place>
3259                         </xsl:for-each>
3260                         <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
3261                                 <place>
3262                                         <placeTerm>
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>
3269                                                         </xsl:with-param>
3270                                                 </xsl:call-template>
3271                                         </placeTerm>
3272                                 </place>
3273                         </xsl:for-each>
3274                         <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
3275                                 <dateValid point="start">
3276                                         <xsl:value-of select="."/>
3277                                 </dateValid>
3278                         </xsl:for-each>
3279                         <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
3280                                 <dateValid point="end">
3281                                         <xsl:value-of select="."/>
3282                                 </dateValid>
3283                         </xsl:for-each>
3284                         <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
3285                                 <dateModified>
3286                                         <xsl:value-of select="."/>
3287                                 </dateModified>
3288                         </xsl:for-each>
3289                         <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
3290                                 <xsl:choose>
3291                                         <xsl:when test="@code='b'">
3292                                                 <publisher>
3293                                                         <xsl:call-template name="chopPunctuation">
3294                                                                 <xsl:with-param name="chopString" select="."/>
3295                                                                 <xsl:with-param name="punctuation">
3296                                                                         <xsl:text>:,;/ </xsl:text>
3297                                                                 </xsl:with-param>
3298                                                         </xsl:call-template>
3299                                                 </publisher>
3300                                         </xsl:when>
3301                                         <xsl:when test="@code='c'">
3302                                                 <dateIssued>
3303                                                         <xsl:call-template name="chopPunctuation">
3304                                                                 <xsl:with-param name="chopString" select="."/>
3305                                                         </xsl:call-template>
3306                                                 </dateIssued>
3307                                         </xsl:when>
3308                                         <xsl:when test="@code='g'">
3309                                                 <dateCreated>
3310                                                         <xsl:value-of select="."/>
3311                                                 </dateCreated>
3312                                         </xsl:when>
3313                                 </xsl:choose>
3314                         </xsl:for-each>
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>
3319                         </xsl:variable>
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"/>
3327                                         </dateIssued>
3328                                 </xsl:if>
3329                         </xsl:if>
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"/>
3334                                         </dateIssued>
3335                                 </xsl:if>
3336                         </xsl:if>
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"/>
3341                                         </dateIssued>
3342                                 </xsl:if>
3343                         </xsl:if>
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"/>
3348                                         </dateIssued>
3349                                 </xsl:if>
3350                         </xsl:if>
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"/>
3355                                         </dateIssued>
3356                                 </xsl:if>
3357                         </xsl:if>
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"/>
3362                                         </copyrightDate>
3363                                 </xsl:if>
3364                         </xsl:if>
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="."/>
3368                                 </dateCaptured>
3369                         </xsl:for-each>
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="."/>
3373                                 </dateCaptured>
3374                         </xsl:for-each>
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="."/>
3378                                 </dateCaptured>
3379                         </xsl:for-each>
3380                         <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
3381                                 <edition>
3382                                         <xsl:value-of select="."/>
3383                                 </edition>
3384                         </xsl:for-each>
3385                         <xsl:for-each select="marc:leader">
3386                                 <issuance>
3387                                         <xsl:choose>
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>
3390                                         </xsl:choose>
3391                                 </issuance>
3392                         </xsl:for-each>
3393                         <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
3394                                 <frequency>
3395                                         <xsl:call-template name="subfieldSelect">
3396                                                 <xsl:with-param name="codes">ab</xsl:with-param>
3397                                         </xsl:call-template>
3398                                 </frequency>
3399                         </xsl:for-each>
3400                 </originInfo>
3401                 <xsl:variable name="controlField008-35-37" select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"></xsl:variable>
3402                 <xsl:if test="$controlField008-35-37">
3403                         <language>
3404                                 <languageTerm authority="iso639-2b" type="code">
3405                                         <xsl:value-of select="substring($controlField008,36,3)"/>
3406                                 </languageTerm>
3407                         </language>
3408                 </xsl:if>
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="."/>
3412                                 <xsl:choose>
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"/>
3418                                                         </xsl:with-param>
3419                                                         <xsl:with-param name="usedLanguages">
3420                                                                 <xsl:text></xsl:text>
3421                                                         </xsl:with-param>
3422                                                         <xsl:with-param name="controlField008-35-37">
3423                                                                 <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
3424                                                         </xsl:with-param>
3425                                                 </xsl:call-template>
3426                                         </xsl:when>
3427                                         <xsl:otherwise>
3428                                                 <!-- iso -->
3429                                                 <xsl:variable name="allLanguages">
3430                                                         <xsl:copy-of select="$langCodes"></xsl:copy-of>
3431                                                 </xsl:variable>
3432                                                 <xsl:variable name="currentLanguage">
3433                                                         <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
3434                                                 </xsl:variable>
3435                                                 <xsl:call-template name="isoLanguage">
3436                                                         <xsl:with-param name="currentLanguage">
3437                                                                 <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
3438                                                         </xsl:with-param>
3439                                                         <xsl:with-param name="remainingLanguages">
3440                                                                 <xsl:value-of select="substring($allLanguages,4,string-length($allLanguages)-3)"></xsl:value-of>
3441                                                         </xsl:with-param>
3442                                                         <xsl:with-param name="usedLanguages">
3443                                                                 <xsl:if test="$controlField008-35-37">
3444                                                                         <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
3445                                                                 </xsl:if>
3446                                                         </xsl:with-param>
3447                                                 </xsl:call-template>
3448                                         </xsl:otherwise>
3449                                 </xsl:choose>
3450                         </xsl:for-each>
3451                 </xsl:for-each>
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>
3456                         </xsl:if>
3457                         <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='b']">
3458                                 <digitalOrigin>digitized microfilm</digitalOrigin>
3459                         </xsl:if>
3460                         <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='d']">
3461                                 <digitalOrigin>digitized other analog</digitalOrigin>
3462                         </xsl:if>
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>
3468                                 </xsl:if>
3469                         </xsl:variable>
3470                         <xsl:variable name="check008-29">
3471                                 <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
3472                                         <xsl:value-of select="true()"></xsl:value-of>
3473                                 </xsl:if>
3474                         </xsl:variable>
3475                         <xsl:choose>
3476                                 <xsl:when test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
3477                                         <form authority="marcform">braille</form>
3478                                 </xsl:when>
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>
3481                                 </xsl:when>
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>
3484                                 </xsl:when>
3485                                 <xsl:when test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
3486                                         <form authority="marcform">microfiche</form>
3487                                 </xsl:when>
3488                                 <xsl:when test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
3489                                         <form authority="marcform">microfilm</form>
3490                                 </xsl:when>
3491                         </xsl:choose>
3492                         <!-- 1/04 fix -->
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>
3498                                                 </xsl:with-param>
3499                                         </xsl:call-template>
3500                                 </form>
3501                         </xsl:if>
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>
3507                                                 </xsl:with-param>
3508                                         </xsl:call-template>
3509                                 </form>
3510                         </xsl:if>
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>
3516                                                 </xsl:with-param>
3517                                         </xsl:call-template>
3518                                 </form>
3519                         </xsl:if>
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>
3525                                                 </xsl:with-param>
3526                                         </xsl:call-template>
3527                                 </form>
3528                         </xsl:if>
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>
3534                                                 </xsl:with-param>
3535                                         </xsl:call-template>
3536                                 </form>
3537                         </xsl:if>
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>
3543                                                 </xsl:with-param>
3544                                         </xsl:call-template>
3545                                 </form>
3546                         </xsl:if>
3547                         <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
3548                                 <form>
3549                                         <xsl:value-of select="."></xsl:value-of>
3550                                 </form>
3551                         </xsl:for-each>
3552                         <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
3553                                 <xsl:choose>
3554                                         <xsl:when test="substring(text(),14,1)='a'">
3555                                                 <reformattingQuality>access</reformattingQuality>
3556                                         </xsl:when>
3557                                         <xsl:when test="substring(text(),14,1)='p'">
3558                                                 <reformattingQuality>preservation</reformattingQuality>
3559                                         </xsl:when>
3560                                         <xsl:when test="substring(text(),14,1)='r'">
3561                                                 <reformattingQuality>replacement</reformattingQuality>
3562                                         </xsl:when>
3563                                 </xsl:choose>
3564                         </xsl:for-each>
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>
3568                         </xsl:if>
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>
3571                         </xsl:if>
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>
3574                         </xsl:if>
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>
3577                         </xsl:if>
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>
3580                         </xsl:if>
3581                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='r']">
3582                                 <form authority="smd">remote</form>
3583                         </xsl:if>
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>
3586                         </xsl:if>
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>
3589                         </xsl:if>
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>
3592                         </xsl:if>
3593                         
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>
3596                         </xsl:if>
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>
3599                         </xsl:if>
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>
3602                         </xsl:if>
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>
3605                         </xsl:if>
3606                         
3607                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='o'][substring(text(),2,1)='o']">
3608                                 <form authority="smd">kit</form>
3609                         </xsl:if>
3610                         
3611                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
3612                                 <form authority="smd">atlas</form>
3613                         </xsl:if>
3614                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='g']">
3615                                 <form authority="smd">diagram</form>
3616                         </xsl:if>
3617                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
3618                                 <form authority="smd">map</form>
3619                         </xsl:if>
3620                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
3621                                 <form authority="smd">model</form>
3622                         </xsl:if>
3623                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='k']">
3624                                 <form authority="smd">profile</form>
3625                         </xsl:if>
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>
3628                         </xsl:if>
3629                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='s']">
3630                                 <form authority="smd">section</form>
3631                         </xsl:if>
3632                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='y']">
3633                                 <form authority="smd">view</form>
3634                         </xsl:if>
3635                         
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>
3638                         </xsl:if>
3639                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='e']">
3640                                 <form authority="smd">microfiche</form>
3641                         </xsl:if>
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>
3644                         </xsl:if>
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>
3647                         </xsl:if>
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>
3650                         </xsl:if>
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>
3653                         </xsl:if>
3654                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='g']">
3655                                 <form authority="smd">microopaque</form>
3656                         </xsl:if>
3657                         
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>
3660                         </xsl:if>
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>
3663                         </xsl:if>
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>
3666                         </xsl:if>
3667                         
3668                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='n']">
3669                                 <form authority="smd">chart</form>
3670                         </xsl:if>
3671                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='c']">
3672                                 <form authority="smd">collage</form>
3673                         </xsl:if>
3674                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='d']">
3675                                 <form authority="smd">drawing</form>
3676                         </xsl:if>
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>
3679                         </xsl:if>
3680                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='e']">
3681                                 <form authority="smd">painting</form>
3682                         </xsl:if>
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>
3685                         </xsl:if>
3686                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='g']">
3687                                 <form authority="smd">photonegative</form>
3688                         </xsl:if>
3689                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='h']">
3690                                 <form authority="smd">photoprint</form>
3691                         </xsl:if>
3692                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='i']">
3693                                 <form authority="smd">picture</form>
3694                         </xsl:if>
3695                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='j']">
3696                                 <form authority="smd">print</form>
3697                         </xsl:if>
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>
3700                         </xsl:if>
3701                         
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>
3704                         </xsl:if>
3705                         
3706                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='d']">
3707                                 <form authority="smd">filmslip</form>
3708                         </xsl:if>
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>
3711                         </xsl:if>
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>
3714                         </xsl:if>
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>
3717                         </xsl:if>
3718                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='s']">
3719                                 <form authority="smd">slide</form>
3720                         </xsl:if>
3721                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='t']">
3722                                 <form authority="smd">transparency</form>
3723                         </xsl:if>
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>
3726                         </xsl:if>
3727                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='e']">
3728                                 <form authority="smd">cylinder</form>
3729                         </xsl:if>
3730                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='q']">
3731                                 <form authority="smd">roll</form>
3732                         </xsl:if>
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>
3735                         </xsl:if>
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>
3738                         </xsl:if>
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>
3741                         </xsl:if>
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>
3744                         </xsl:if>
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>
3747                         </xsl:if>
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>
3750                         </xsl:if>
3751                         
3752                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='c']">
3753                                 <form authority="smd">braille</form>
3754                         </xsl:if>
3755                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='b']">
3756                                 <form authority="smd">combination</form>
3757                         </xsl:if>
3758                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='a']">
3759                                 <form authority="smd">moon</form>
3760                         </xsl:if>
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>
3763                         </xsl:if>
3764                         
3765                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='c']">
3766                                 <form authority="smd">braille</form>
3767                         </xsl:if>
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>
3770                         </xsl:if>
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>
3773                         </xsl:if>
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>
3776                         </xsl:if>
3777                         
3778                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='c']">
3779                                 <form authority="smd">videocartridge</form>
3780                         </xsl:if>
3781                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='f']">
3782                                 <form authority="smd">videocassette</form>
3783                         </xsl:if>
3784                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='d']">
3785                                 <form authority="smd">videodisc</form>
3786                         </xsl:if>
3787                         <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='r']">
3788                                 <form authority="smd">videoreel</form>
3789                         </xsl:if>
3790                         
3791                         <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">
3792                                 <internetMediaType>
3793                                         <xsl:value-of select="."></xsl:value-of>
3794                                 </internetMediaType>
3795                         </xsl:for-each>
3796                         <xsl:for-each select="marc:datafield[@tag=300]">
3797                                 <extent>
3798                                         <xsl:call-template name="subfieldSelect">
3799                                                 <xsl:with-param name="codes">abce</xsl:with-param>
3800                                         </xsl:call-template>
3801                                 </extent>
3802                         </xsl:for-each>
3803                 </xsl:variable>
3804                 <xsl:if test="string-length(normalize-space($physicalDescription))">
3805                         <physicalDescription>
3806                                 <xsl:copy-of select="$physicalDescription"></xsl:copy-of>
3807                         </physicalDescription>
3808                 </xsl:if>
3809                 <xsl:for-each select="marc:datafield[@tag=520]">
3810                         <abstract>
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>
3815                         </abstract>
3816                 </xsl:for-each>
3817                 <xsl:for-each select="marc:datafield[@tag=505]">
3818                         <tableOfContents>
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>
3823                         </tableOfContents>
3824                 </xsl:for-each>
3825                 <xsl:for-each select="marc:datafield[@tag=521]">
3826                         <targetAudience>
3827                                 <xsl:call-template name="subfieldSelect">
3828                                         <xsl:with-param name="codes">ab</xsl:with-param>
3829                                 </xsl:call-template>
3830                         </targetAudience>
3831                 </xsl:for-each>
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>
3834                         <xsl:choose>
3835                                 <!-- 01/04 fix -->
3836                                 <xsl:when test="$controlField008-22='d'">
3837                                         <targetAudience authority="marctarget">adolescent</targetAudience>
3838                                 </xsl:when>
3839                                 <xsl:when test="$controlField008-22='e'">
3840                                         <targetAudience authority="marctarget">adult</targetAudience>
3841                                 </xsl:when>
3842                                 <xsl:when test="$controlField008-22='g'">
3843                                         <targetAudience authority="marctarget">general</targetAudience>
3844                                 </xsl:when>
3845                                 <xsl:when test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
3846                                         <targetAudience authority="marctarget">juvenile</targetAudience>
3847                                 </xsl:when>
3848                                 <xsl:when test="$controlField008-22='a'">
3849                                         <targetAudience authority="marctarget">preschool</targetAudience>
3850                                 </xsl:when>
3851                                 <xsl:when test="$controlField008-22='f'">
3852                                         <targetAudience authority="marctarget">specialized</targetAudience>
3853                                 </xsl:when>
3854                         </xsl:choose>
3855                 </xsl:if>
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>
3859                         </note>
3860                 </xsl:for-each>
3861                 <xsl:for-each select="marc:datafield[@tag=500]">
3862                         <note>
3863                                 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
3864                                 <xsl:call-template name="uri"></xsl:call-template>
3865                         </note>
3866                 </xsl:for-each>
3867                 
3868                 <!--3.2 change tmee additional note fields-->
3869                 
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>
3877                                         </xsl:for-each>
3878                                 </xsl:variable>
3879                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3880                         </note>
3881                 </xsl:for-each>
3882                 
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>
3890                                         </xsl:for-each>
3891                                 </xsl:variable>
3892                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3893                         </note>
3894                 </xsl:for-each>
3895                 
3896                         
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>
3901                         </note>
3902                 </xsl:for-each>
3903                 <xsl:for-each select="marc:datafield[@tag=518]">
3904                         <note type="venue">
3905                                 <xsl:call-template name="uri"></xsl:call-template>
3906                                 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
3907                         </note>
3908                 </xsl:for-each>
3909                 
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>
3917                                         </xsl:for-each>
3918                                 </xsl:variable>
3919                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3920                         </note>
3921                 </xsl:for-each>
3922                 
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>
3930                                         </xsl:for-each>
3931                                 </xsl:variable>
3932                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3933                         </note>
3934                 </xsl:for-each>
3935                 
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>
3943                                         </xsl:for-each>
3944                                 </xsl:variable>
3945                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3946                         </note>
3947                 </xsl:for-each>
3948                 
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>
3956                                         </xsl:for-each>
3957                                 </xsl:variable>
3958                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3959                         </note>
3960                 </xsl:for-each>
3961                 
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>
3969                                         </xsl:for-each>
3970                                 </xsl:variable>
3971                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3972                         </note>
3973                 </xsl:for-each>
3974                 
3975
3976                 
3977                 
3978                 
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]">
3980                         <note>
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>
3986                                         </xsl:for-each>
3987                                 </xsl:variable>
3988                                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
3989                         </note>
3990                 </xsl:for-each>
3991                 <xsl:for-each select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
3992                         <subject>
3993                                 <cartographics>
3994                                         <coordinates>
3995                                                 <xsl:call-template name="subfieldSelect">
3996                                                         <xsl:with-param name="codes">defg</xsl:with-param>
3997                                                 </xsl:call-template>
3998                                         </coordinates>
3999                                 </cartographics>
4000                         </subject>
4001                 </xsl:for-each>
4002                 <xsl:for-each select="marc:datafield[@tag=043]">
4003                         <subject>
4004                                 <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
4005                                         <geographicCode>
4006                                                 <xsl:attribute name="authority">
4007                                                         <xsl:if test="@code='a'">
4008                                                                 <xsl:text>marcgac</xsl:text>
4009                                                         </xsl:if>
4010                                                         <xsl:if test="@code='b'">
4011                                                                 <xsl:value-of select="following-sibling::marc:subfield[@code=2]"></xsl:value-of>
4012                                                         </xsl:if>
4013                                                         <xsl:if test="@code='c'">
4014                                                                 <xsl:text>iso3166</xsl:text>
4015                                                         </xsl:if>
4016                                                 </xsl:attribute>
4017                                                 <xsl:value-of select="self::marc:subfield"></xsl:value-of>
4018                                         </geographicCode>
4019                                 </xsl:for-each>
4020                         </subject>
4021                 </xsl:for-each>
4022                 <!-- tmee 2006/11/27 -->
4023                 <xsl:for-each select="marc:datafield[@tag=255]">
4024                         <subject>
4025                                 <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
4026                                 <cartographics>
4027                                         <xsl:if test="@code='a'">
4028                                                 <scale>
4029                                                         <xsl:value-of select="."></xsl:value-of>
4030                                                 </scale>
4031                                         </xsl:if>
4032                                         <xsl:if test="@code='b'">
4033                                                 <projection>
4034                                                         <xsl:value-of select="."></xsl:value-of>
4035                                                 </projection>
4036                                         </xsl:if>
4037                                         <xsl:if test="@code='c'">
4038                                                 <coordinates>
4039                                                         <xsl:value-of select="."></xsl:value-of>
4040                                                 </coordinates>
4041                                         </xsl:if>
4042                                 </cartographics>
4043                                 </xsl:for-each>
4044                         </subject>
4045                 </xsl:for-each>
4046                                 
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]">
4050                         <subject>
4051                                 <hierarchicalGeographic>
4052                                         <xsl:for-each select="marc:subfield[@code='a']">
4053                                                 <country>
4054                                                         <xsl:call-template name="chopPunctuation">
4055                                                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4056                                                         </xsl:call-template>
4057                                                 </country>
4058                                         </xsl:for-each>
4059                                         <xsl:for-each select="marc:subfield[@code='b']">
4060                                                 <state>
4061                                                         <xsl:call-template name="chopPunctuation">
4062                                                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4063                                                         </xsl:call-template>
4064                                                 </state>
4065                                         </xsl:for-each>
4066                                         <xsl:for-each select="marc:subfield[@code='c']">
4067                                                 <county>
4068                                                         <xsl:call-template name="chopPunctuation">
4069                                                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4070                                                         </xsl:call-template>
4071                                                 </county>
4072                                         </xsl:for-each>
4073                                         <xsl:for-each select="marc:subfield[@code='d']">
4074                                                 <city>
4075                                                         <xsl:call-template name="chopPunctuation">
4076                                                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4077                                                         </xsl:call-template>
4078                                                 </city>
4079                                         </xsl:for-each>
4080                                 </hierarchicalGeographic>
4081                         </subject>
4082                 </xsl:for-each>
4083                 <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
4084                         <subject>
4085                                 <xsl:choose>
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>
4091                                                                 </xsl:with-param>
4092                                                         </xsl:call-template>
4093                                                 </temporal>
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>
4098                                                                 </xsl:with-param>
4099                                                         </xsl:call-template>
4100                                                 </temporal>
4101                                         </xsl:when>
4102                                         <xsl:otherwise>
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>
4108                                                         </temporal>
4109                                                 </xsl:for-each>
4110                                         </xsl:otherwise>
4111                                 </xsl:choose>
4112                         </subject>
4113                 </xsl:for-each>
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>
4120                                                 </xsl:attribute>
4121                                         </xsl:if>
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>
4125                                 </classification>
4126                         </xsl:for-each>
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>
4132                                                 </xsl:attribute>
4133                                         </xsl:if>
4134                                         <xsl:value-of select="text()"></xsl:value-of>
4135                                 </classification>
4136                         </xsl:for-each>
4137                 </xsl:for-each>
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>
4143                                         </xsl:attribute>
4144                                 </xsl:if>
4145                                 <xsl:call-template name="subfieldSelect">
4146                                         <xsl:with-param name="codes">ab</xsl:with-param>
4147                                 </xsl:call-template>
4148                         </classification>
4149                 </xsl:for-each>
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>
4155                         </classification>
4156                 </xsl:for-each>
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>
4162                         </classification>
4163                 </xsl:for-each>
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>
4167                         </classification>
4168                 </xsl:for-each>
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>
4172                         </classification>
4173                 </xsl:for-each>
4174                 <xsl:for-each select="marc:datafield[@tag=086]">
4175                         <classification>
4176                                 <xsl:attribute name="authority">
4177                                         <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
4178                                 </xsl:attribute>
4179                                 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4180                         </classification>
4181                 </xsl:for-each>
4182                 <xsl:for-each select="marc:datafield[@tag=084]">
4183                         <classification>
4184                                 <xsl:attribute name="authority">
4185                                         <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
4186                                 </xsl:attribute>
4187                                 <xsl:call-template name="subfieldSelect">
4188                                         <xsl:with-param name="codes">ab</xsl:with-param>
4189                                 </xsl:call-template>
4190                         </classification>
4191                 </xsl:for-each>
4192                 <xsl:for-each select="marc:datafield[@tag=440]">
4193                         <relatedItem type="series">
4194                                 <titleInfo>
4195                                         <title>
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>
4201                                                         </xsl:with-param>
4202                                                 </xsl:call-template>
4203                                         </title>
4204                                         <xsl:call-template name="part"></xsl:call-template>
4205                                 </titleInfo>
4206                         </relatedItem>
4207                 </xsl:for-each>
4208                 <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
4209                         <relatedItem type="series">
4210                                 <titleInfo>
4211                                         <title>
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>
4217                                                         </xsl:with-param>
4218                                                 </xsl:call-template>
4219                                         </title>
4220                                         <xsl:call-template name="part"></xsl:call-template>
4221                                 </titleInfo>
4222                         </relatedItem>
4223                 </xsl:for-each>
4224                 <xsl:for-each select="marc:datafield[@tag=510]">
4225                         <relatedItem type="isReferencedBy">
4226                                 <note>
4227                                         <xsl:call-template name="subfieldSelect">
4228                                                 <xsl:with-param name="codes">abcx3</xsl:with-param>
4229                                         </xsl:call-template>
4230                                 </note>
4231                         </relatedItem>
4232                 </xsl:for-each>
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']">
4238                                         <originInfo>
4239                                                 <xsl:for-each select="marc:subfield[@code='c']">
4240                                                         <publisher>
4241                                                                 <xsl:value-of select="."></xsl:value-of>
4242                                                         </publisher>
4243                                                 </xsl:for-each>
4244                                                 <xsl:for-each select="marc:subfield[@code='b']">
4245                                                         <edition>
4246                                                                 <xsl:value-of select="."></xsl:value-of>
4247                                                         </edition>
4248                                                 </xsl:for-each>
4249                                         </originInfo>
4250                                 </xsl:if>
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>
4255                                         </identifier>
4256                                 </xsl:for-each>
4257                                 <xsl:call-template name="relatedNote"></xsl:call-template>
4258                         </relatedItem>
4259                 </xsl:for-each>
4260                 <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
4261                         <relatedItem>
4262                                 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4263                                 <titleInfo>
4264                                         <title>
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>
4272                                                         </xsl:with-param>
4273                                                 </xsl:call-template>
4274                                         </title>
4275                                         <xsl:call-template name="part"></xsl:call-template>
4276                                 </titleInfo>
4277                                 <name type="personal">
4278                                         <namePart>
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>
4284                                         </namePart>
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>
4288                                 </name>
4289                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4290                                 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4291                         </relatedItem>
4292                 </xsl:for-each>
4293                 <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
4294                         <relatedItem>
4295                                 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4296                                 <titleInfo>
4297                                         <title>
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>
4305                                                         </xsl:with-param>
4306                                                 </xsl:call-template>
4307                                         </title>
4308                                         <xsl:call-template name="relatedPartNumName"></xsl:call-template>
4309                                 </titleInfo>
4310                                 <name type="corporate">
4311                                         <xsl:for-each select="marc:subfield[@code='a']">
4312                                                 <namePart>
4313                                                         <xsl:value-of select="."></xsl:value-of>
4314                                                 </namePart>
4315                                         </xsl:for-each>
4316                                         <xsl:for-each select="marc:subfield[@code='b']">
4317                                                 <namePart>
4318                                                         <xsl:value-of select="."></xsl:value-of>
4319                                                 </namePart>
4320                                         </xsl:for-each>
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>
4327                                         </xsl:variable>
4328                                         <xsl:if test="normalize-space($tempNamePart)">
4329                                                 <namePart>
4330                                                         <xsl:value-of select="$tempNamePart"></xsl:value-of>
4331                                                 </namePart>
4332                                         </xsl:if>
4333                                         <xsl:call-template name="role"></xsl:call-template>
4334                                 </name>
4335                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4336                                 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4337                         </relatedItem>
4338                 </xsl:for-each>
4339                 <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
4340                         <relatedItem>
4341                                 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4342                                 <titleInfo>
4343                                         <title>
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>
4351                                                         </xsl:with-param>
4352                                                 </xsl:call-template>
4353                                         </title>
4354                                         <xsl:call-template name="relatedPartNumName"></xsl:call-template>
4355                                 </titleInfo>
4356                                 <name type="conference">
4357                                         <namePart>
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>
4363                                         </namePart>
4364                                 </name>
4365                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4366                                 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4367                         </relatedItem>
4368                 </xsl:for-each>
4369                 <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
4370                         <relatedItem>
4371                                 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4372                                 <titleInfo>
4373                                         <title>
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>
4379                                                         </xsl:with-param>
4380                                                 </xsl:call-template>
4381                                         </title>
4382                                         <xsl:call-template name="part"></xsl:call-template>
4383                                 </titleInfo>
4384                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4385                                 <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
4386                         </relatedItem>
4387                 </xsl:for-each>
4388                 <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
4389                         <relatedItem>
4390                                 <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
4391                                 <titleInfo>
4392                                         <title>
4393                                                 <xsl:call-template name="chopPunctuation">
4394                                                         <xsl:with-param name="chopString">
4395                                                                 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
4396                                                         </xsl:with-param>
4397                                                 </xsl:call-template>
4398                                         </title>
4399                                         <xsl:call-template name="part"></xsl:call-template>
4400                                 </titleInfo>
4401                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4402                         </relatedItem>
4403                 </xsl:for-each>
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>
4407                         </relatedItem>
4408                 </xsl:for-each>
4409                 <xsl:for-each select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
4410                         <relatedItem>
4411                                 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4412                         </relatedItem>
4413                 </xsl:for-each>
4414                 <xsl:for-each select="marc:datafield[@tag=775]">
4415                         <relatedItem type="otherVersion">
4416                                 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4417                         </relatedItem>
4418                 </xsl:for-each>
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>
4422                         </relatedItem>
4423                 </xsl:for-each>
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>
4427                         </relatedItem>
4428                 </xsl:for-each>
4429                 <xsl:for-each select="marc:datafield[@tag=776]">
4430                         <relatedItem type="otherFormat">
4431                                 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4432                         </relatedItem>
4433                 </xsl:for-each>
4434                 <xsl:for-each select="marc:datafield[@tag=780]">
4435                         <relatedItem type="preceding">
4436                                 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4437                         </relatedItem>
4438                 </xsl:for-each>
4439                 <xsl:for-each select="marc:datafield[@tag=785]">
4440                         <relatedItem type="succeeding">
4441                                 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4442                         </relatedItem>
4443                 </xsl:for-each>
4444                 <xsl:for-each select="marc:datafield[@tag=786]">
4445                         <relatedItem type="original">
4446                                 <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
4447                         </relatedItem>
4448                 </xsl:for-each>
4449                 <xsl:for-each select="marc:datafield[@tag=800]">
4450                         <relatedItem type="series">
4451                                 <titleInfo>
4452                                         <title>
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>
4460                                                         </xsl:with-param>
4461                                                 </xsl:call-template>
4462                                         </title>
4463                                         <xsl:call-template name="part"></xsl:call-template>
4464                                 </titleInfo>
4465                                 <name type="personal">
4466                                         <namePart>
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>
4474                                                         </xsl:with-param>
4475                                                 </xsl:call-template>
4476                                         </namePart>
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>
4480                                 </name>
4481                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4482                         </relatedItem>
4483                 </xsl:for-each>
4484                 <xsl:for-each select="marc:datafield[@tag=810]">
4485                         <relatedItem type="series">
4486                                 <titleInfo>
4487                                         <title>
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>
4495                                                         </xsl:with-param>
4496                                                 </xsl:call-template>
4497                                         </title>
4498                                         <xsl:call-template name="relatedPartNumName"></xsl:call-template>
4499                                 </titleInfo>
4500                                 <name type="corporate">
4501                                         <xsl:for-each select="marc:subfield[@code='a']">
4502                                                 <namePart>
4503                                                         <xsl:value-of select="."></xsl:value-of>
4504                                                 </namePart>
4505                                         </xsl:for-each>
4506                                         <xsl:for-each select="marc:subfield[@code='b']">
4507                                                 <namePart>
4508                                                         <xsl:value-of select="."></xsl:value-of>
4509                                                 </namePart>
4510                                         </xsl:for-each>
4511                                         <namePart>
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>
4517                                         </namePart>
4518                                         <xsl:call-template name="role"></xsl:call-template>
4519                                 </name>
4520                                 <xsl:call-template name="relatedForm"></xsl:call-template>
4521                         </relatedItem>
4522                 </xsl:for-each>
4523                 <xsl:for-each select="marc:datafield[@tag=811]">
4524                         <relatedItem type="series">
4525                                 <titleInfo>
4526                                         <title>
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>
4534                                                         </xsl:with-param>
4535                                                 </xsl:call-template>
4536                                         </title>
4537                                         <xsl:call-template name="relatedPartNumName"/>
4538                                 </titleInfo>
4539                                 <name type="conference">
4540                                         <namePart>
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>
4546                                         </namePart>
4547                                         <xsl:call-template name="role"/>
4548                                 </name>
4549                                 <xsl:call-template name="relatedForm"/>
4550                         </relatedItem>
4551                 </xsl:for-each>
4552                 <xsl:for-each select="marc:datafield[@tag='830']">
4553                         <relatedItem type="series">
4554                                 <titleInfo>
4555                                         <title>
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>
4561                                                         </xsl:with-param>
4562                                                 </xsl:call-template>
4563                                         </title>
4564                                         <xsl:call-template name="part"/>
4565                                 </titleInfo>
4566                                 <xsl:call-template name="relatedForm"/>
4567                         </relatedItem>
4568                 </xsl:for-each>
4569                 <xsl:for-each select="marc:datafield[@tag='856'][@ind2='2']/marc:subfield[@code='q']">
4570                         <relatedItem>
4571                                 <internetMediaType>
4572                                         <xsl:value-of select="."/>
4573                                 </internetMediaType>
4574                         </relatedItem>
4575                 </xsl:for-each>
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']"/>
4583                                 </identifier>
4584                         </xsl:if>
4585                 </xsl:for-each>
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']"/>
4593                                 </identifier>
4594                         </xsl:if>
4595                 </xsl:for-each>
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']"/>
4603                                 </identifier>
4604                         </xsl:if>
4605                 </xsl:for-each>
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>
4614                         </identifier>
4615                 </xsl:for-each>
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']"/>
4622                         </identifier>
4623                 </xsl:for-each>
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'])"/>
4630                         </identifier>
4631                 </xsl:for-each>
4632                 <xsl:for-each select="marc:datafield[@tag='028']">
4633                         <identifier>
4634                                 <xsl:attribute name="type">
4635                                         <xsl:choose>
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>
4641                                         </xsl:choose>
4642                                 </xsl:attribute>
4643                                 <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 028 -->
4644                                 <xsl:call-template name="subfieldSelect">
4645                                         <xsl:with-param name="codes">
4646                                                 <xsl:choose>
4647                                                         <xsl:when test="@ind1='0'">ba</xsl:when>
4648                                                         <xsl:otherwise>ab</xsl:otherwise>
4649                                                 </xsl:choose>
4650                                         </xsl:with-param>
4651                                 </xsl:call-template>
4652                         </identifier>
4653                 </xsl:for-each>
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>
4660                         </identifier>
4661                 </xsl:for-each>
4662                 <xsl:for-each select="marc:datafield[@tag='856'][marc:subfield[@code='u']]">
4663                         <identifier>
4664                                 <xsl:attribute name="type">
4665                                         <xsl:choose>
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>
4669                                         </xsl:choose>
4670                                 </xsl:attribute>
4671                                 <xsl:choose>
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>
4674                                         </xsl:when>
4675                                         <xsl:otherwise>
4676                                                 <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
4677                                         </xsl:otherwise>
4678                                 </xsl:choose>
4679                         </identifier>
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>
4687                                                 </xsl:attribute>
4688                                         </xsl:if>
4689                                         <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
4690                                 </identifier>
4691                         </xsl:if>
4692                 </xsl:for-each>
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']"/>
4697                         </identifier>
4698                 </xsl:for-each>
4699                 <!-- 1/04 fix added $y -->
4700                 <xsl:for-each select="marc:datafield[@tag=856][marc:subfield[@code='u']]">
4701                         <location>
4702                                 <url>
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>
4708                                                 </xsl:attribute>
4709                                         </xsl:if>
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>
4715                                                 </xsl:attribute>
4716                                         </xsl:if>
4717                                         <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
4718
4719                                 </url>
4720                         </location>
4721                 </xsl:for-each>
4722                         
4723                         <!-- 3.2 change tmee 856z  -->
4724
4725                 
4726                 <xsl:for-each select="marc:datafield[@tag=852]">
4727                         <location>
4728                                 <physicalLocation>
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>
4733                                 </physicalLocation>
4734                         </location>
4735                 </xsl:for-each>
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>
4741                         </accessCondition>
4742                 </xsl:for-each>
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>
4748                         </accessCondition>
4749                 </xsl:for-each>
4750                 <recordInfo>
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>
4755                         </xsl:for-each>
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>
4760                         </xsl:for-each>
4761                         <xsl:for-each select="marc:controlfield[@tag=005]">
4762                                 <recordChangeDate encoding="iso8601">
4763                                         <xsl:value-of select="."></xsl:value-of>
4764                                 </recordChangeDate>
4765                         </xsl:for-each>
4766                         <xsl:for-each select="marc:controlfield[@tag=001]">
4767                                 <recordIdentifier>
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>
4771                                                 </xsl:attribute>
4772                                         </xsl:if>
4773                                         <xsl:value-of select="."></xsl:value-of>
4774                                 </recordIdentifier>
4775                         </xsl:for-each>
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>
4780                                         </languageTerm>
4781                                 </languageOfCataloging>
4782                         </xsl:for-each>
4783                 </recordInfo>
4784         </xsl:template>
4785         <xsl:template name="displayForm">
4786                 <xsl:for-each select="marc:subfield[@code='c']">
4787                         <displayForm>
4788                                 <xsl:value-of select="."></xsl:value-of>
4789                         </displayForm>
4790                 </xsl:for-each>
4791         </xsl:template>
4792         <xsl:template name="affiliation">
4793                 <xsl:for-each select="marc:subfield[@code='u']">
4794                         <affiliation>
4795                                 <xsl:value-of select="."></xsl:value-of>
4796                         </affiliation>
4797                 </xsl:for-each>
4798         </xsl:template>
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>
4803                         </xsl:attribute>
4804                 </xsl:for-each>
4805         </xsl:template>
4806         <xsl:template name="role">
4807                 <xsl:for-each select="marc:subfield[@code='e']">
4808                         <role>
4809                                 <roleTerm type="text">
4810                                         <xsl:value-of select="."></xsl:value-of>
4811                                 </roleTerm>
4812                         </role>
4813                 </xsl:for-each>
4814                 <xsl:for-each select="marc:subfield[@code='4']">
4815                         <role>
4816                                 <roleTerm authority="marcrelator" type="code">
4817                                         <xsl:value-of select="."></xsl:value-of>
4818                                 </roleTerm>
4819                         </role>
4820                 </xsl:for-each>
4821         </xsl:template>
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>
4829                 </xsl:variable>
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>
4836                 </xsl:variable>
4837                 <xsl:if test="string-length(normalize-space($partNumber))">
4838                         <partNumber>
4839                                 <xsl:call-template name="chopPunctuation">
4840                                         <xsl:with-param name="chopString" select="$partNumber"></xsl:with-param>
4841                                 </xsl:call-template>
4842                         </partNumber>
4843                 </xsl:if>
4844                 <xsl:if test="string-length(normalize-space($partName))">
4845                         <partName>
4846                                 <xsl:call-template name="chopPunctuation">
4847                                         <xsl:with-param name="chopString" select="$partName"></xsl:with-param>
4848                                 </xsl:call-template>
4849                         </partName>
4850                 </xsl:if>
4851         </xsl:template>
4852         <xsl:template name="relatedPart">
4853                 <xsl:if test="@tag=773">
4854                         <xsl:for-each select="marc:subfield[@code='g']">
4855                                 <part>
4856                                         <text>
4857                                                 <xsl:value-of select="."></xsl:value-of>
4858                                         </text>
4859                                 </part>
4860                         </xsl:for-each>
4861                         <xsl:for-each select="marc:subfield[@code='q']">
4862                                 <part>
4863                                         <xsl:call-template name="parsePart"></xsl:call-template>
4864                                 </part>
4865                         </xsl:for-each>
4866                 </xsl:if>
4867         </xsl: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>
4875                 </xsl:variable>
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>
4882                 </xsl:variable>
4883                 <xsl:if test="string-length(normalize-space($partNumber))">
4884                         <partNumber>
4885                                 <xsl:value-of select="$partNumber"></xsl:value-of>
4886                         </partNumber>
4887                 </xsl:if>
4888                 <xsl:if test="string-length(normalize-space($partName))">
4889                         <partName>
4890                                 <xsl:value-of select="$partName"></xsl:value-of>
4891                         </partName>
4892                 </xsl:if>
4893         </xsl:template>
4894         <xsl:template name="relatedName">
4895                 <xsl:for-each select="marc:subfield[@code='a']">
4896                         <name>
4897                                 <namePart>
4898                                         <xsl:value-of select="."></xsl:value-of>
4899                                 </namePart>
4900                         </name>
4901                 </xsl:for-each>
4902         </xsl:template>
4903         <xsl:template name="relatedForm">
4904                 <xsl:for-each select="marc:subfield[@code='h']">
4905                         <physicalDescription>
4906                                 <form>
4907                                         <xsl:value-of select="."></xsl:value-of>
4908                                 </form>
4909                         </physicalDescription>
4910                 </xsl:for-each>
4911         </xsl:template>
4912         <xsl:template name="relatedExtent">
4913                 <xsl:for-each select="marc:subfield[@code='h']">
4914                         <physicalDescription>
4915                                 <extent>
4916                                         <xsl:value-of select="."></xsl:value-of>
4917                                 </extent>
4918                         </physicalDescription>
4919                 </xsl:for-each>
4920         </xsl:template>
4921         <xsl:template name="relatedNote">
4922                 <xsl:for-each select="marc:subfield[@code='n']">
4923                         <note>
4924                                 <xsl:value-of select="."></xsl:value-of>
4925                         </note>
4926                 </xsl:for-each>
4927         </xsl:template>
4928         <xsl:template name="relatedSubject">
4929                 <xsl:for-each select="marc:subfield[@code='j']">
4930                         <subject>
4931                                 <temporal encoding="iso8601">
4932                                         <xsl:call-template name="chopPunctuation">
4933                                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4934                                         </xsl:call-template>
4935                                 </temporal>
4936                         </subject>
4937                 </xsl:for-each>
4938         </xsl: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>
4943                         </identifier>
4944                 </xsl:for-each>
4945         </xsl:template>
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>
4950                         </identifier>
4951                 </xsl:for-each>
4952         </xsl:template>
4953         <xsl:template name="relatedIdentifier">
4954                 <xsl:for-each select="marc:subfield[@code='o']">
4955                         <identifier>
4956                                 <xsl:value-of select="."></xsl:value-of>
4957                         </identifier>
4958                 </xsl:for-each>
4959         </xsl:template>
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>
4973         </xsl:template>
4974         <xsl:template name="subjectGeographicZ">
4975                 <geographic>
4976                         <xsl:call-template name="chopPunctuation">
4977                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4978                         </xsl:call-template>
4979                 </geographic>
4980         </xsl:template>
4981         <xsl:template name="subjectTemporalY">
4982                 <temporal>
4983                         <xsl:call-template name="chopPunctuation">
4984                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4985                         </xsl:call-template>
4986                 </temporal>
4987         </xsl:template>
4988         <xsl:template name="subjectTopic">
4989                 <topic>
4990                         <xsl:call-template name="chopPunctuation">
4991                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
4992                         </xsl:call-template>
4993                 </topic>
4994         </xsl:template> 
4995         <!-- 3.2 change tmee 6xx $v genre -->
4996         <xsl:template name="subjectGenre">
4997                 <genre>
4998                         <xsl:call-template name="chopPunctuation">
4999                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
5000                         </xsl:call-template>
5001                 </genre>
5002         </xsl:template>
5003         
5004         <xsl:template name="nameABCDN">
5005                 <xsl:for-each select="marc:subfield[@code='a']">
5006                         <namePart>
5007                                 <xsl:call-template name="chopPunctuation">
5008                                         <xsl:with-param name="chopString" select="."></xsl:with-param>
5009                                 </xsl:call-template>
5010                         </namePart>
5011                 </xsl:for-each>
5012                 <xsl:for-each select="marc:subfield[@code='b']">
5013                         <namePart>
5014                                 <xsl:value-of select="."></xsl:value-of>
5015                         </namePart>
5016                 </xsl:for-each>
5017                 <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
5018                         <namePart>
5019                                 <xsl:call-template name="subfieldSelect">
5020                                         <xsl:with-param name="codes">cdn</xsl:with-param>
5021                                 </xsl:call-template>
5022                         </namePart>
5023                 </xsl:if>
5024         </xsl:template>
5025         <xsl:template name="nameABCDQ">
5026                 <namePart>
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>
5032                                 </xsl:with-param>
5033                                 <xsl:with-param name="punctuation">
5034                                         <xsl:text>:,;/ </xsl:text>
5035                                 </xsl:with-param>
5036                         </xsl:call-template>
5037                 </namePart>
5038                 <xsl:call-template name="termsOfAddress"></xsl:call-template>
5039                 <xsl:call-template name="nameDate"></xsl:call-template>
5040         </xsl:template>
5041         <xsl:template name="nameACDEQ">
5042                 <namePart>
5043                         <xsl:call-template name="subfieldSelect">
5044                                 <xsl:with-param name="codes">acdeq</xsl:with-param>
5045                         </xsl:call-template>
5046                 </namePart>
5047         </xsl:template>
5048         <xsl:template name="constituentOrRelatedType">
5049                 <xsl:if test="@ind2=2">
5050                         <xsl:attribute name="type">constituent</xsl:attribute>
5051                 </xsl:if>
5052         </xsl:template>
5053         <xsl:template name="relatedTitle">
5054                 <xsl:for-each select="marc:subfield[@code='t']">
5055                         <titleInfo>
5056                                 <title>
5057                                         <xsl:call-template name="chopPunctuation">
5058                                                 <xsl:with-param name="chopString">
5059                                                         <xsl:value-of select="."></xsl:value-of>
5060                                                 </xsl:with-param>
5061                                         </xsl:call-template>
5062                                 </title>
5063                         </titleInfo>
5064                 </xsl:for-each>
5065         </xsl:template>
5066         <xsl:template name="relatedTitle76X-78X">
5067                 <xsl:for-each select="marc:subfield[@code='t']">
5068                         <titleInfo>
5069                                 <title>
5070                                         <xsl:call-template name="chopPunctuation">
5071                                                 <xsl:with-param name="chopString">
5072                                                         <xsl:value-of select="."></xsl:value-of>
5073                                                 </xsl:with-param>
5074                                         </xsl:call-template>
5075                                 </title>
5076                                 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
5077                                         <xsl:call-template name="relatedPartNumName"></xsl:call-template>
5078                                 </xsl:if>
5079                         </titleInfo>
5080                 </xsl:for-each>
5081                 <xsl:for-each select="marc:subfield[@code='p']">
5082                         <titleInfo type="abbreviated">
5083                                 <title>
5084                                         <xsl:call-template name="chopPunctuation">
5085                                                 <xsl:with-param name="chopString">
5086                                                         <xsl:value-of select="."></xsl:value-of>
5087                                                 </xsl:with-param>
5088                                         </xsl:call-template>
5089                                 </title>
5090                                 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
5091                                         <xsl:call-template name="relatedPartNumName"></xsl:call-template>
5092                                 </xsl:if>
5093                         </titleInfo>
5094                 </xsl:for-each>
5095                 <xsl:for-each select="marc:subfield[@code='s']">
5096                         <titleInfo type="uniform">
5097                                 <title>
5098                                         <xsl:call-template name="chopPunctuation">
5099                                                 <xsl:with-param name="chopString">
5100                                                         <xsl:value-of select="."></xsl:value-of>
5101                                                 </xsl:with-param>
5102                                         </xsl:call-template>
5103                                 </title>
5104                                 <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
5105                                         <xsl:call-template name="relatedPartNumName"></xsl:call-template>
5106                                 </xsl:if>
5107                         </titleInfo>
5108                 </xsl:for-each>
5109         </xsl:template>
5110         <xsl:template name="relatedOriginInfo">
5111                 <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
5112                         <originInfo>
5113                                 <xsl:if test="@tag=775">
5114                                         <xsl:for-each select="marc:subfield[@code='f']">
5115                                                 <place>
5116                                                         <placeTerm>
5117                                                                 <xsl:attribute name="type">code</xsl:attribute>
5118                                                                 <xsl:attribute name="authority">marcgac</xsl:attribute>
5119                                                                 <xsl:value-of select="."></xsl:value-of>
5120                                                         </placeTerm>
5121                                                 </place>
5122                                         </xsl:for-each>
5123                                 </xsl:if>
5124                                 <xsl:for-each select="marc:subfield[@code='d']">
5125                                         <publisher>
5126                                                 <xsl:value-of select="."></xsl:value-of>
5127                                         </publisher>
5128                                 </xsl:for-each>
5129                                 <xsl:for-each select="marc:subfield[@code='b']">
5130                                         <edition>
5131                                                 <xsl:value-of select="."></xsl:value-of>
5132                                         </edition>
5133                                 </xsl:for-each>
5134                         </originInfo>
5135                 </xsl:if>
5136         </xsl:template>
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>
5142                                 </xsl:with-param>
5143                         </xsl:call-template>
5144                 </xsl:for-each>
5145         </xsl: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>
5152                         </namePart>
5153                 </xsl:for-each>
5154         </xsl: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">
5161                                                         <xsl:choose>
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>
5165                                                                 <!-- 1/04 fix -->
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>
5171                                                                 </xsl:when>
5172                                                         </xsl:choose>
5173                                                 </xsl:attribute>
5174                                         </xsl:if>
5175                                 </xsl:if>
5176                         </xsl:if>
5177                 </xsl:if>
5178         </xsl:template>
5179         <xsl:template name="subjectAnyOrder">
5180                 <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
5181                         <xsl:choose>
5182                                 <xsl:when test="@code='v'">
5183                                         <xsl:call-template name="subjectGenre"></xsl:call-template>
5184                                 </xsl:when>
5185                                 <xsl:when test="@code='x'">
5186                                         <xsl:call-template name="subjectTopic"></xsl:call-template>
5187                                 </xsl:when>
5188                                 <xsl:when test="@code='y'">
5189                                         <xsl:call-template name="subjectTemporalY"></xsl:call-template>
5190                                 </xsl:when>
5191                                 <xsl:when test="@code='z'">
5192                                         <xsl:call-template name="subjectGeographicZ"></xsl:call-template>
5193                                 </xsl:when>
5194                         </xsl:choose>
5195                 </xsl:for-each>
5196         </xsl: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>
5207                                 </xsl:if>
5208                         </xsl:for-each>
5209                 </xsl:variable>
5210                 <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
5211         </xsl:template>
5212         
5213         <!-- 3.2 change tmee 6xx $v genre -->
5214         <xsl:template match="marc:datafield[@tag=600]">
5215                 <subject>
5216                         <xsl:call-template name="subjectAuthority"></xsl:call-template>
5217                         <name type="personal">
5218                                 <xsl:call-template name="termsOfAddress"></xsl:call-template>
5219                                 <namePart>
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>
5225                                                 </xsl:with-param>
5226                                         </xsl:call-template>
5227                                 </namePart>
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>
5231                         </name>
5232                         <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5233                 </subject>
5234         </xsl:template>
5235         <xsl:template match="marc:datafield[@tag=610]">
5236                 <subject>
5237                         <xsl:call-template name="subjectAuthority"></xsl:call-template>
5238                         <name type="corporate">
5239                                 <xsl:for-each select="marc:subfield[@code='a']">
5240                                         <namePart>
5241                                                 <xsl:value-of select="."></xsl:value-of>
5242                                         </namePart>
5243                                 </xsl:for-each>
5244                                 <xsl:for-each select="marc:subfield[@code='b']">
5245                                         <namePart>
5246                                                 <xsl:value-of select="."></xsl:value-of>
5247                                         </namePart>
5248                                 </xsl:for-each>
5249                                 <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
5250                                         <namePart>
5251                                                 <xsl:call-template name="subfieldSelect">
5252                                                         <xsl:with-param name="codes">cdnp</xsl:with-param>
5253                                                 </xsl:call-template>
5254                                         </namePart>
5255                                 </xsl:if>
5256                                 <xsl:call-template name="role"></xsl:call-template>
5257                         </name>
5258                         <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5259                 </subject>
5260         </xsl:template>
5261         <xsl:template match="marc:datafield[@tag=611]">
5262                 <subject>
5263                         <xsl:call-template name="subjectAuthority"></xsl:call-template>
5264                         <name type="conference">
5265                                 <namePart>
5266                                         <xsl:call-template name="subfieldSelect">
5267                                                 <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
5268                                         </xsl:call-template>
5269                                 </namePart>
5270                                 <xsl:for-each select="marc:subfield[@code='4']">
5271                                         <role>
5272                                                 <roleTerm authority="marcrelator" type="code">
5273                                                         <xsl:value-of select="."></xsl:value-of>
5274                                                 </roleTerm>
5275                                         </role>
5276                                 </xsl:for-each>
5277                         </name>
5278                         <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5279                 </subject>
5280         </xsl:template>
5281         <xsl:template match="marc:datafield[@tag=630]">
5282                 <subject>
5283                         <xsl:call-template name="subjectAuthority"></xsl:call-template>
5284                         <titleInfo>
5285                                 <title>
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>
5291                                                 </xsl:with-param>
5292                                         </xsl:call-template>
5293                                         <xsl:call-template name="part"></xsl:call-template>
5294                                 </title>
5295                         </titleInfo>
5296                         <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5297                 </subject>
5298         </xsl:template>
5299         <xsl:template match="marc:datafield[@tag=650]">
5300                 <subject>
5301                         <xsl:call-template name="subjectAuthority"></xsl:call-template>
5302                         <topic>
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>
5308                                         </xsl:with-param>
5309                                 </xsl:call-template>
5310                         </topic>
5311                         <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5312                 </subject>
5313         </xsl:template>
5314         <xsl:template match="marc:datafield[@tag=651]">
5315                 <subject>
5316                         <xsl:call-template name="subjectAuthority"></xsl:call-template>
5317                         <xsl:for-each select="marc:subfield[@code='a']">
5318                                 <geographic>
5319                                         <xsl:call-template name="chopPunctuation">
5320                                                 <xsl:with-param name="chopString" select="."></xsl:with-param>
5321                                         </xsl:call-template>
5322                                 </geographic>
5323                         </xsl:for-each>
5324                         <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
5325                 </subject>
5326         </xsl:template>
5327         <xsl:template match="marc:datafield[@tag=653]">
5328                 <subject>
5329                         <xsl:for-each select="marc:subfield[@code='a']">
5330                                 <topic>
5331                                         <xsl:value-of select="."></xsl:value-of>
5332                                 </topic>
5333                         </xsl:for-each>
5334                 </subject>
5335         </xsl:template>
5336         <xsl:template match="marc:datafield[@tag=656]">
5337                 <subject>
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>
5341                                 </xsl:attribute>
5342                         </xsl:if>
5343                         <occupation>
5344                                 <xsl:call-template name="chopPunctuation">
5345                                         <xsl:with-param name="chopString">
5346                                                 <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
5347                                         </xsl:with-param>
5348                                 </xsl:call-template>
5349                         </occupation>
5350                 </subject>
5351         </xsl: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>
5360                                         </xsl:with-param>
5361                                 </xsl:call-template>
5362                         </namePart>
5363                 </xsl:if>
5364         </xsl: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>
5369                         </xsl:attribute>
5370                 </xsl:if>
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>
5374                         </xsl:attribute>
5375                 </xsl:if>
5376         </xsl:template>
5377         <xsl:template name="isInvalid">
5378                 <xsl:param name="type"/>
5379                 <xsl:if test="marc:subfield[@code='z'] or marc:subfield[@code='y']">
5380                         <identifier>
5381                                 <xsl:attribute name="type">
5382                                         <xsl:value-of select="$type"/>
5383                                 </xsl:attribute>
5384                                 <xsl:attribute name="invalid">
5385                                         <xsl:text>yes</xsl:text>
5386                                 </xsl:attribute>
5387                                 <xsl:if test="marc:subfield[@code='z']">
5388                                         <xsl:value-of select="marc:subfield[@code='z']"/>
5389                                 </xsl:if>
5390                                 <xsl:if test="marc:subfield[@code='y']">
5391                                         <xsl:value-of select="marc:subfield[@code='y']"/>
5392                                 </xsl:if>
5393                         </identifier>
5394                 </xsl:if>
5395         </xsl:template>
5396         <xsl:template name="subtitle">
5397                 <xsl:if test="marc:subfield[@code='b']">
5398                         <subTitle>
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>-->
5405                                         </xsl:with-param>
5406                                 </xsl:call-template>
5407                         </subTitle>
5408                 </xsl:if>
5409         </xsl:template>
5410         <xsl:template name="script">
5411                 <xsl:param name="scriptCode"></xsl:param>
5412                 <xsl:attribute name="script">
5413                         <xsl:choose>
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>
5420                         </xsl:choose>
5421                 </xsl:attribute>
5422         </xsl:template>
5423         <xsl:template name="parsePart">
5424                 <!-- assumes 773$q= 1:2:3<4
5425                      with up to 3 levels and one optional start page
5426                 -->
5427                 <xsl:variable name="level1">
5428                         <xsl:choose>
5429                                 <xsl:when test="contains(text(),':')">
5430                                         <!-- 1:2 -->
5431                                         <xsl:value-of select="substring-before(text(),':')"></xsl:value-of>
5432                                 </xsl:when>
5433                                 <xsl:when test="not(contains(text(),':'))">
5434                                         <!-- 1 or 1<3 -->
5435                                         <xsl:if test="contains(text(),'&lt;')">
5436                                                 <!-- 1<3 -->
5437                                                 <xsl:value-of select="substring-before(text(),'&lt;')"></xsl:value-of>
5438                                         </xsl:if>
5439                                         <xsl:if test="not(contains(text(),'&lt;'))">
5440                                                 <!-- 1 -->
5441                                                 <xsl:value-of select="text()"></xsl:value-of>
5442                                         </xsl:if>
5443                                 </xsl:when>
5444                         </xsl:choose>
5445                 </xsl:variable>
5446                 <xsl:variable name="sici2">
5447                         <xsl:choose>
5448                                 <xsl:when test="starts-with(substring-after(text(),$level1),':')">
5449                                         <xsl:value-of select="substring(substring-after(text(),$level1),2)"></xsl:value-of>
5450                                 </xsl:when>
5451                                 <xsl:otherwise>
5452                                         <xsl:value-of select="substring-after(text(),$level1)"></xsl:value-of>
5453                                 </xsl:otherwise>
5454                         </xsl:choose>
5455                 </xsl:variable>
5456                 <xsl:variable name="level2">
5457                         <xsl:choose>
5458                                 <xsl:when test="contains($sici2,':')">
5459                                         <!--  2:3<4  -->
5460                                         <xsl:value-of select="substring-before($sici2,':')"></xsl:value-of>
5461                                 </xsl:when>
5462                                 <xsl:when test="contains($sici2,'&lt;')">
5463                                         <!-- 1: 2<4 -->
5464                                         <xsl:value-of select="substring-before($sici2,'&lt;')"></xsl:value-of>
5465                                 </xsl:when>
5466                                 <xsl:otherwise>
5467                                         <xsl:value-of select="$sici2"></xsl:value-of>
5468                                         <!-- 1:2 -->
5469                                 </xsl:otherwise>
5470                         </xsl:choose>
5471                 </xsl:variable>
5472                 <xsl:variable name="sici3">
5473                         <xsl:choose>
5474                                 <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
5475                                         <xsl:value-of select="substring(substring-after($sici2,$level2),2)"></xsl:value-of>
5476                                 </xsl:when>
5477                                 <xsl:otherwise>
5478                                         <xsl:value-of select="substring-after($sici2,$level2)"></xsl:value-of>
5479                                 </xsl:otherwise>
5480                         </xsl:choose>
5481                 </xsl:variable>
5482                 <xsl:variable name="level3">
5483                         <xsl:choose>
5484                                 <xsl:when test="contains($sici3,'&lt;')">
5485                                         <!-- 2<4 -->
5486                                         <xsl:value-of select="substring-before($sici3,'&lt;')"></xsl:value-of>
5487                                 </xsl:when>
5488                                 <xsl:otherwise>
5489                                         <xsl:value-of select="$sici3"></xsl:value-of>
5490                                         <!-- 3 -->
5491                                 </xsl:otherwise>
5492                         </xsl:choose>
5493                 </xsl:variable>
5494                 <xsl:variable name="page">
5495                         <xsl:if test="contains(text(),'&lt;')">
5496                                 <xsl:value-of select="substring-after(text(),'&lt;')"></xsl:value-of>
5497                         </xsl:if>
5498                 </xsl:variable>
5499                 <xsl:if test="$level1">
5500                         <detail level="1">
5501                                 <number>
5502                                         <xsl:value-of select="$level1"></xsl:value-of>
5503                                 </number>
5504                         </detail>
5505                 </xsl:if>
5506                 <xsl:if test="$level2">
5507                         <detail level="2">
5508                                 <number>
5509                                         <xsl:value-of select="$level2"></xsl:value-of>
5510                                 </number>
5511                         </detail>
5512                 </xsl:if>
5513                 <xsl:if test="$level3">
5514                         <detail level="3">
5515                                 <number>
5516                                         <xsl:value-of select="$level3"></xsl:value-of>
5517                                 </number>
5518                         </detail>
5519                 </xsl:if>
5520                 <xsl:if test="$page">
5521                         <extent unit="page">
5522                                 <start>
5523                                         <xsl:value-of select="$page"></xsl:value-of>
5524                                 </start>
5525                         </extent>
5526                 </xsl:if>
5527         </xsl:template>
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>
5532                 <xsl:choose>
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>
5539                         </xsl:when>
5540                         <xsl:otherwise>
5541                                 <language>
5542                                         <languageTerm authority="iso639-2b" type="code">
5543                                                 <xsl:value-of select="substring($langString,1,3)"></xsl:value-of>
5544                                         </languageTerm>
5545                                 </language>
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>
5550                         </xsl:otherwise>
5551                 </xsl:choose>
5552         </xsl: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>
5557                 <xsl:choose>
5558                         <xsl:when test="string-length($currentLanguage)=0"></xsl:when>
5559                         <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
5560                                 <language>
5561                                         <xsl:if test="@code!='a'">
5562                                                 <xsl:attribute name="objectPart">
5563                                                         <xsl:choose>
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>
5570                                                         </xsl:choose>
5571                                                 </xsl:attribute>
5572                                         </xsl:if>
5573                                         <languageTerm authority="iso639-2b" type="code">
5574                                                 <xsl:value-of select="$currentLanguage"></xsl:value-of>
5575                                         </languageTerm>
5576                                 </language>
5577                                 <xsl:call-template name="isoLanguage">
5578                                         <xsl:with-param name="currentLanguage">
5579                                                 <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
5580                                         </xsl:with-param>
5581                                         <xsl:with-param name="usedLanguages">
5582                                                 <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
5583                                         </xsl:with-param>
5584                                         <xsl:with-param name="remainingLanguages">
5585                                                 <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
5586                                         </xsl:with-param>
5587                                 </xsl:call-template>
5588                         </xsl:when>
5589                         <xsl:otherwise>
5590                                 <xsl:call-template name="isoLanguage">
5591                                         <xsl:with-param name="currentLanguage">
5592                                                 <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
5593                                         </xsl:with-param>
5594                                         <xsl:with-param name="usedLanguages">
5595                                                 <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
5596                                         </xsl:with-param>
5597                                         <xsl:with-param name="remainingLanguages">
5598                                                 <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
5599                                         </xsl:with-param>
5600                                 </xsl:call-template>
5601                         </xsl:otherwise>
5602                 </xsl:choose>
5603         </xsl: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>
5610                 </xsl:variable>
5611                 <xsl:if test="substring($string, 1,1)='['">
5612                         <xsl:value-of select="substring($string,2, string-length($string)-2)"></xsl:value-of>
5613                 </xsl:if>
5614                 <xsl:if test="substring($string, 1,1)!='['">
5615                         <xsl:value-of select="$string"></xsl:value-of>
5616                 </xsl:if>
5617         </xsl:template>
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>
5623                 <xsl:choose>
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))">
5627                                         <language>
5628                                                 <xsl:if test="@code!='a'">
5629                                                         <xsl:attribute name="objectPart">
5630                                                                 <xsl:choose>
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>
5637                                                                 </xsl:choose>
5638                                                         </xsl:attribute>
5639                                                 </xsl:if>
5640                                                 <languageTerm authority="rfc3066" type="code">
5641                                                         <xsl:value-of select="$currentLanguage"/>
5642                                                 </languageTerm>
5643                                         </language>
5644                                 </xsl:if>
5645                         </xsl:when>
5646                         <xsl:otherwise>
5647                         </xsl:otherwise>
5648                 </xsl:choose>
5649         </xsl:template>
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"/>
5658                         </xsl:attribute>
5659                         <xsl:attribute name="ind1">
5660                                 <xsl:value-of select="$ind1"/>
5661                         </xsl:attribute>
5662                         <xsl:attribute name="ind2">
5663                                 <xsl:value-of select="$ind2"/>
5664                         </xsl:attribute>
5665                         <xsl:copy-of select="$subfields"/>
5666                 </xsl:element>
5667         </xsl:template>
5668
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"/>
5676                                 </xsl:if>
5677                         </xsl:for-each>
5678                 </xsl:variable>
5679                 <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
5680         </xsl:template>
5681
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>
5691                 </xsl:if>
5692         </xsl:template>
5693
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)"/>
5698                 <xsl:choose>
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>
5705                         </xsl:when>
5706                         <xsl:when test="not($chopString)"/>
5707                         <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
5708                 </xsl:choose>
5709         </xsl:template>
5710
5711         <xsl:template name="chopPunctuationFront">
5712                 <xsl:param name="chopString"/>
5713                 <xsl:variable name="length" select="string-length($chopString)"/>
5714                 <xsl:choose>
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>
5720                         </xsl:when>
5721                         <xsl:when test="not($chopString)"/>
5722                         <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
5723                 </xsl:choose>
5724         </xsl:template>
5725 </xsl:stylesheet>$$ WHERE name = 'mods32';
5726
5727 COMMIT;
5728
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';
5735