require 'stringio' module MARC4J4R Record = Java::org.marc4j.marc.impl::RecordImpl class Record include Enumerable alias_method :<<, :addVariableField alias_method :append, :addVariableField alias_method :fields, :getVariableFields # Export as a MARC-Hash, as described at # http://robotlibrarian.billdueber.com/marc-hash-the-saga-continues-now-with-even-less-structure/ # @return A marc-hash representation of the record, suitable for calling .to_json on or whatever # Show equality def == other return false unless (self.leader == other.leader) self.zip(other) do |so| unless so[0] == so[1] puts "self <> other\n#{so[0]}\n#{so[1]}" return false; end end other.zip(self) do |so| unless so[0] == so[1] puts "#{so[0]}\n#{so[1]}" return false; end end return true end # Create a local hash by tag number; makes some stuff faster # Called automatically if you use reader.each def hashify return if @hashedtags # don't do it more than once @hashedtags = {} self.getVariableFields.each do |f| @hashedtags[f.tag] ||= [] @hashedtags[f.tag].push f end end # Force a re-hash def rehash @hashedtags = nil hashify end # Create a nice string of the record def to_s arr = ['LEADER ' + self.leader] self.each do |f| arr.push f.to_s end return arr.join("\n") end # Get the leader as a string (marc4j would otherwise return Leader object) def leader self.get_leader.toString end # Set the leader # @throw RuntimeError if leader is illegal def leader= str begin self.set_leader Java::org.marc4j.marc.impl.LeaderImpl.new(str) rescue Java::java.lang.StringIndexOutOfBoundsException => e raise RuntimeError.new("'#{str}' not a legal leader: #{e.message}") end end # Cycle through the fields in the order the appear in the record def each self.getVariableFields.each do |f| yield f end end # Get the first field associated with a tag # @param [String] tag The tag # @return [Field] The first matching field, or nil if none. Note that # to mirror ruby-marc, this returns a single field def [] tag if defined? @hashedtags if @hashedtags[tag] return @hashedtags[tag][0] else return nil end else return self.getVariableField(tag) end end # Get a (possibly empty) list of fields with the given tag(s) # # @param [String, Array] tags A string (or Array of strings) with the tags you're interested in # @param [Boolean] originalorder Whether or not results should be presented in the original order within the # record or with a two-column sort of (a) Order of the tag in the list of tags sent, (b) order within that tag # in the record # @return [Array] Either an empty list or a list of one or more matched fields will be returned. # # originalorder == false will use an internal hash and be faster in many cases (see #hashify) # # @example originalorder == false # # Given a record that looks like # # 010 $a 68027371 # # 035 $a (RLIN)MIUG0001728-B # # 035 $a (CaOTULAS)159818044 # # 035 $a (OCoLC)ocm00001728 # # r.find_by_tag(['035', '010']).each {|f| puts f.to_s} # # 035 $a (RLIN)MIUG0001728-B # # 035 $a (CaOTULAS)159818044 # # 035 $a (OCoLC)ocm00001728 # # 010 $a 68027371 # # # The results are ordered first by tag as passed in, then by original order within the tag # # @example Just get all fields for a single tag # ohThirtyFives = r.find_by_tag('035') # # @example Get a bunch of standard identifiers # standardIDs = r.find_by_tag(['022', '020', '010']) # # @example originalorder == true # r.find_by_tag(['035', '010'], true).each {|f| puts f.to_s} # # 010 $a 68027371 # # 035 $a (RLIN)MIUG0001728-B # # 035 $a (CaOTULAS)159818044 # # 035 $a (OCoLC)ocm00001728 def find_by_tag(tags, originalorder = false) self.hashify unless @hashedtags and !originalorder if !tags.is_a? Array return @hashedtags[tags] || [] end if originalorder return self.find_all {|f| tags.include? f.tag} else # puts "Tags is #{tags}: got #{@hashedtags.values_at(*tags)}" return @hashedtags.values_at(*tags).flatten.compact end end # Return the record as valid MARC-XML # @param String encoding The encoding to use # @return String A MARC-XML representation of the record, including the XML header def to_xml return Java::org.marc4j.MarcXmlWriter.record_to_XML(self) end def to_marc encoding='UTF-8' # begin s = Java::java.io.ByteArrayOutputStream.new writer = org.marc4j.MarcPermissiveStreamWriter.new(s, encoding) writer.write(self) return s.to_string # writer.close # @marcbinary = s.to_string # return @marcbinary # rescue # # "Woops! to_marc failed for record #{self['001'].data}: #{$!}" # "Whoops! Failed: #{$!}" # end end def to_marchash h = {} h['type'] = 'marc-hash' h['version'] = [1,0] h['leader'] = self.leader fields = [] self.getVariableFields.each do |f| if f.controlField? fields << [f.tag, f.value] else farray = [f.tag, f.indicator1 || ' ', f.indicator2 || ' '] subs = [] f.each do |subfield| subs << [subfield.code, subfield.value] end farray.push subs fields << farray end end h['fields'] = fields return h end # Turn it into a marc-in-json hashmap. Note that this won't really work # like a ruby hash; you need to know what you're getting, since stuff # like #each won't work. # # Better to just use to_marc_in_json if you want a json string def to_hash return Java::org.marc4j.MarcInJSON.record_to_hash(self) end # Turn it into a marc-in-json JSON string using Jackson def to_marc_in_json return Java::org.marc4j.MarcInJSON.record_to_marc_in_json(self) end end # Give a marc record in a string, turn it into an object # @param String str The record as a MARC binary string # @return MARC4J4R::Record The first record encoded in the string # # Note that the normal way of defining this class (self.from_string) # didn't work; I assume it has something to do with the fact that # it's actually jrst aliased to the Java class def Record.from_string str, encoding=nil s = Java::java.io.ByteArrayInputStream.new(str.to_java_bytes) # return MARC4J4R::Reader.new(StringIO.new(str), :strictmarc, encoding).first return MARC4J4R::Reader.new(s, :strictmarc, encoding).first end # Give a marc-xml record in a string, turn it into an object # @param String str The record as a MARC-XML string # @return MARC4J4R::Record The first record encoded in the string def Record.from_xml_string str return MARC4J4R::Reader.new(StringIO.new(str), :marcxml).first end def Record.new_from_hash hash return Java::org.marc4j.MarcInJSON.new_from_hash(hash) end def Record.new_from_marc_in_json jsonstring return Java::org.marc4j.MarcInJSON.new_from_marc_in_json(jsonstring) end end