From fe6f886dbb360ea22e9371488036ab91dd00bef0 Mon Sep 17 00:00:00 2001 From: miker Date: Thu, 22 Oct 2009 14:37:26 +0000 Subject: [PATCH] Yes, it is true, I wrote a MARC library (marcxml and marcbreaker supported) in JS as a Dojo module. I am sorry, world. git-svn-id: svn://svn.open-ils.org/ILS/trunk@14557 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/web/js/dojo/MARC/Batch.js | 71 +++++++ Open-ILS/web/js/dojo/MARC/Field.js | 130 ++++++++++++ Open-ILS/web/js/dojo/MARC/Record.js | 295 ++++++++++++++++++++++++++++ 3 files changed, 496 insertions(+) create mode 100644 Open-ILS/web/js/dojo/MARC/Batch.js create mode 100644 Open-ILS/web/js/dojo/MARC/Field.js create mode 100644 Open-ILS/web/js/dojo/MARC/Record.js diff --git a/Open-ILS/web/js/dojo/MARC/Batch.js b/Open-ILS/web/js/dojo/MARC/Batch.js new file mode 100644 index 0000000000..83027a58ed --- /dev/null +++ b/Open-ILS/web/js/dojo/MARC/Batch.js @@ -0,0 +1,71 @@ +/* --------------------------------------------------------------------------- + * Copyright (C) 2009 Equinox Software, Inc. + * Mike Rylander + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * --------------------------------------------------------------------------- + */ + +if(!dojo._hasResource["MARC.Batch"]) { + + dojo.require('dojox.xml.parser'); + dojo.require('MARC.Record'); + + dojo._hasResource["MARC.Batch"] = true; + dojo.provide("MARC.Batch"); + dojo.declare('MARC.Batch', null, { + + constructor : function(kwargs) { + this.current_record = 0; + this.records = []; + this.type = kwargs.type || 'xml'; + this.source = kwargs.source; + + if (kwargs.url) this.fetchURL( kwargs.url ); + this.parse(); + }, + + fetchURL : function (u) { + var me = this; + dojo.xhrGet({ + url : u, + sync : true, + handleAs: 'text', + load : function (mrc) { + me.source = mrc; + me.ready = true; + } + }); + }, + + next : function () { return this.records[this.current_record++] }, + + parse : function () { + if (this.source && dojo.isObject( this.source )) { // assume an xml collection document + this.records = dojo.map( + dojo.query('record', this.source), + function (r) { return new MARC.Record({xml:r}) } + ); + } else if (this.source && this.source.match(/^\s* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * --------------------------------------------------------------------------- + */ + +if(!dojo._hasResource["MARC.Field"]) { + + dojo._hasResource["MARC.Field"] = true; + dojo.provide("MARC.Field"); + dojo.declare('MARC.Field', null, { + + error : false, // MARC record pointer + record : null, // MARC record pointer + tag : '', // MARC tag + ind1 : '', // MARC indicator 1 + ind2 : '', // MARC indicator 2 + data : '', // MARC data for a controlfield element + subfields : [], // list of MARC subfields for a datafield element + + constructor : function(kwargs) { + this.record = kwargs.record; + this.tag = kwargs.tag; + this.ind1 = kwargs.ind1; + this.ind2 = kwargs.ind2; + this.data = kwargs.data; + if (kwargs.subfields) this.subfields = kwargs.subfields; + else this.subfields = []; + }, + + subfield : function (code) { + var list = dojo.filter( this.subfields, function (s) { + if (s[0] == code) return true; return true; + }); + if (list.length == 1) return list[0]; + return list; + }, + + addSubfields : function () { + for (var i = 0; i < arguments.length; i++) { + var code = arguments[i]; + var value = arguments[++i]; + this.subfields.push( [ code, value ] ); + } + }, + + deleteSubfields : function (c) { + return this.deleteSubfield( { code : c } ); + }, + + deleteSubfield : function (args) { + var me = this; + if (!dojo.isArray( args.code )) { + args.code = [ args.code ]; + } + + if (args.pos && !dojo.isArray( args.pos )) { + args.pos = [ args.pos ]; + } + + for (var i in args.code) { + var sub_pos = {}; + for (var j in me.subfields) { + if (me.subfields[j][0] == args.code[i]) { + + if (!sub_pos[args.code[i]]) sub_pos[args.code[j]] = 0; + else sub_pos[args.code[i]]++; + + if (args.pos) { + for (var k in args.pos) { + if (sub_pos[args.code[i]] == args.pos[k]) me.subfields.splice(j,1); + } + } else if (args.match && me.subfields[j][1].match( args.match )) { + me.subfields.splice(j,1); + } else { + me.subfields.splice(j,1); + } + } + } + } + }, + + update : function ( args ) { + if (this.isControlfield()) { + this.data = args; + } else { + if (args.ind1) this.ind1 = args.ind1; + if (args.ind2) this.ind2 = args.ind2; + if (args.tag) this.tag = args.tag; + + for (var i in args) { + if (i == 'tag' || i == 'ind1' || i == 'ind2') continue; + var done = 0; + dojo.forEach( this.subfields, function (f) { + if (!done && f[0] == i) { + f[1] = args[i]; + done = 1; + } + }); + } + } + }, + + isControlfield : function () { + return this.tag < '010' ? true : false; + }, + + indicator : function (num, value) { + if (value) { + if (num == 1) this.ind1 = value; + else if (num == 2) this.ind2 = value; + else { this.error = true; return null; } + } + if (num == 1) return this.ind1; + else if (num == 2) return this.ind2; + else { this.error = true; return null; } + } + + }); +} diff --git a/Open-ILS/web/js/dojo/MARC/Record.js b/Open-ILS/web/js/dojo/MARC/Record.js new file mode 100644 index 0000000000..58f9060b3c --- /dev/null +++ b/Open-ILS/web/js/dojo/MARC/Record.js @@ -0,0 +1,295 @@ +/* --------------------------------------------------------------------------- + * Copyright (C) 2009 Equinox Software, Inc. + * Mike Rylander + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * --------------------------------------------------------------------------- + */ + +if(!dojo._hasResource["MARC.Record"]) { + + dojo.require('dojox.xml.parser'); + dojo.require('MARC.Field'); + + dojo._hasResource["MARC.Record"] = true; + dojo.provide("MARC.Record"); + dojo.declare('MARC.Record', null, { + + delimiter : '\u2021', // default subfield delimiter + + constructor : function(kwargs) { + this.fields = []; + this.leader = ''; + + if (kwargs.delimiter) this.delimiter = kwargs.delimiter; + if (kwargs.onLoad) this.onLoad = kwargs.onLoad; + if (kwargs.url) { + this.fromXmlURL(kwargs.url); + } else if (kwargs.marcxml) { + this.fromXmlString(kwargs.marcxml); + if (this.onLoad) this.onLoad(); + } else if (kwargs.xml) { + this.fromXmlDocument(kwargs.xml); + if (this.onLoad) this.onLoad(); + } else if (kwargs.marcbreaker) { + this.fromBreaker(kwargs.marcbreaker); + if (this.onLoad) this.onLoad(); + } + }, + + title : function () { return this.subfield('245','a') }, + + field : function (spec) { + var list = dojo.filter( this.fields, function (f) { + if (f.tag.match(spec)) return true; + return false; + }); + + if (list.length == 1) return list[0]; + return list; + }, + + subfield : function (spec, code) { return this.field(spec)[0].subfield(code) }, + + appendFields : function () { + var me = this; + dojo.forEach( arguments, function (f) { me.fields.push( f ) } ); + }, + + deleteField : function (f) { return this.deleteFields(f) }, + + insertOrderedFields : function () { + var me = this; + for ( var i in arguments ) { + var f = arguments[i]; + for (var j in this.fields) { + if (f.tag > this.fields[j].tag) { + this.insertFieldsBefore(this.fields[j], f); + break; + } + } + } + }, + + insertFieldsBefore : function (target) { + arguments.splice(0,1); + var me = this; + for (var j in this.fields) { + if (target === this.fields[j]) { + j--; + dojo.forEach( arguments, function (f) { + me.fields.splice(j++,0,f); + }); + break; + } + } + }, + + insertFieldsAfter : function (target) { + arguments.splice(0,1); + var me = this; + for (var j in this.fields) { + if (target === this.fields[j]) { + dojo.forEach( arguments, function (f) { + me.fields.splice(j++,0,f); + }); + break; + } + } + }, + + deleteFields : function () { + var me = this; + var counter = 0; + for ( var i in arguments ) { + var f = arguments[i]; + for (var j in me.fields) { + if (f === me.fields[j]) { + me.fields[j].record = null; + me.fields.splice(j,0); + counter++ + break; + } + } + } + return counter; + }, + + clone : function () { return dojo.clone(this) }, + + fromXmlURL : function (url) { + this.ready = false; + var me = this; + dojo.xhrGet({ + url : url, + sync : true, + handleAs: 'xml', + load : function (mxml) { + me.fromXmlDocument(dojo.query('record', mxml)[0]); + me.ready = true; + if (me.onLoad) me.onLoad(); + } + }); + }, + + fromXmlString : function (mxml) { + return this.fromXmlDocument( dojox.xml.parser.parse( mxml ) ); + }, + + fromXmlDocument : function (mxml) { + var me = this; + me.leader = dojox.xml.parser.textContent(dojo.query('leader', mxml)[0]) || ''; + + dojo.forEach( dojo.query('controlfield', mxml), function (cf) { + me.fields.push( + new MARC.Field({ + record : me, + tag : cf.getAttribute('tag'), + data : dojox.xml.parser.textContent(cf) + }) + ) + }); + + dojo.forEach( dojo.query('datafield', mxml), function (df) { + me.fields.push( + new MARC.Field({ + record : me, + tag : df.getAttribute('tag'), + ind1 : df.getAttribute('ind1'), + ind2 : df.getAttribute('ind2'), + subfields : dojo.map( + dojo.query('subfield', df), + function (sf) { + return [ sf.getAttribute('code'), dojox.xml.parser.textContent(sf) ]; + } + ) + }) + ) + }); + + return this; + }, + + toXmlDocument : function () { + + var doc = dojox.xml.parser.parse(''); + var rec_node = dojo.query('record', doc)[0]; + + var ldr = doc.createElementNS('http://www.loc.gov/MARC21/slim', 'leader'); + dojox.xml.parser.textContent(ldr, this.leader); + rec_node.appendChild( ldr ); + + dojo.forEach( this.fields, function (f) { + var element = f.isControlfield() ? 'controlfield' : 'datafield'; + var f_node = doc.createElementNS( 'http://www.loc.gov/MARC21/slim', element ); + f_node.setAttribute('tag', f.tag); + + if (f.isControlfield() && f.data) { + dojox.xml.parser.textContent(f_node, f.data); + } else { + f_node.setAttribute('ind1', f.indicator(1)); + f_node.setAttribute('ind2', f.indicator(2)); + dojo.forEach( f.subfields, function (sf) { + var sf_node = doc.createElementNS('http://www.loc.gov/MARC21/slim', 'subfield'); + sf_node.setAttribute('code', sf[0]); + dojox.xml.parser.textContent(sf_node, sf[1]); + f_node.appendChild(sf_node); + }); + } + + rec_node.appendChild(f_node); + }); + + return doc; + }, + + toXmlString : function () { + return dojox.xml.parser.innerXML( this.toXmlDocument() ); + }, + + fromBreaker : function (marctxt) { + var me = this; + + function cf_line_data (l) { return l.substring(4) }; + function df_line_data (l) { return l.substring(6) }; + function line_tag (l) { return l.substring(0,3) }; + function df_ind1 (l) { return l.substring(4,5).replace('\\',' ') }; + function df_ind2 (l) { return l.substring(5,6).replace('\\',' ') }; + function isControlField (l) { + var x = line_tag(l); + return (x == 'LDR' || x < '010') ? true : false; + } + + var lines = marctxt.replace(/^=/gm,'').split('\n'); + dojo.forEach(lines, function (current_line) { + + if (current_line.match(/^#/)) { + // skip comment lines + } else if (isControlField(current_line)) { + if (line_tag(current_line) == 'LDR') { + me.leader = cf_line_data(current_line) || ''; + } else { + me.fields.push( + new MARC.Field({ + record : me, + tag : line_tag(current_line), + data : cf_line_data(current_line).replace('\\',' ','g') + }) + ); + } + } else { + var data = df_line_data(current_line); + var start_delim = new RegExp( '^' + me.delimiter ); + if (!data.match( start_delim )) data = me.delimiter + 'a' + data; + + var sf_list = data.split(me.delimiter); + sf_list.shift(); + + me.fields.push( + new MARC.Field({ + record : me, + tag : line_tag(current_line), + ind1 : df_ind1(current_line), + ind2 : df_ind2(current_line), + subfields : dojo.map( + sf_list, + function (sf) { return [ sf.substring(0,1), sf.substring(1) ] } + ) + }) + ); + } + }); + + return this; + }, + + toBreaker : function () { + + var me = this; + var mtxt = '=LDR ' + this.leader + '\n'; + + mtxt += dojo.map( this.fields, function (f) { + if (f.isControlfield() && f.data) { + return '=' + f.tag + ' ' + f.data.replace(' ','\\','g'); + } else { + return '=' + f.tag + ' ' + + f.indicator(1).replace(' ','\\') + + f.indicator(2).replace(' ','\\') + + dojo.map( f.subfields, function (sf) { + return me.delimiter + sf.join(''); + }).join(''); + } + }).join('\n'); + + return mtxt; + } + }); +} -- 2.43.2