A implementation of the MARCspec query language for Ruby and ruby-marc.
Add ruby-marc-spec
to your Gemfile or gemspec, or just install it:
-
Gemfile:
gem 'ruby-marc-spec'
-
gemspec
spec.add_dependency 'ruby-marc-spec'
-
from the command line:
gem install ruby-marc-spec
Then, in your code:
require 'marc/spec'
The entry point for MARC::Spec
is the MARC::Spec#find
method, which takes a string
MARCspec query and a MARC::Record
object.
MARC::Spec.find('245$a', marc_record)
# => [#<MARC::Subfield:0x00007ffa1686e3f0 @code="a", @value="Arithmetic /">]
Note that for simplicity's sake MARC::Spec#find
always returns an array, even for
queries that can only return a single-element result, e.g.
MARC::Spec.find('LDR', marc_record)
# => ["01142cam 2200301 a 4500"]
All examples below are based on the record sandburg.xml
from the Library of Congress MARCXML documentation.
marc_record = MARC::XMLReader.new('sandburg.xml').first
MARC::Spec.find('LDR', marc_record)
# => ["01142cam 2200301 a 4500"]
Find all fields whose tag begins with 00
:
MARC::Spec.find('00.', marc_record)
# => [
# #<MARC::ControlField:0x00007ff9f706ac40 @tag="001", @value=" 92005291 ">,
# #<MARC::ControlField:0x00007ff9f70686c0 @tag="003", @value="DLC">,
# #<MARC::ControlField:0x00007ff9f7062450 @tag="005", @value="19930521155141.9">,
# #<MARC::ControlField:0x00007ff9f70600d8 @tag="008", @value="920219s1993 caua j 000 0 eng ">
# ]
Find the first six characters (characters 0 through 6) of the 008
field:
MARC::Spec.find('008/0-5', marc_record)
# => ["920219"]
Find the first two 650
fields (fields 0 and 1):
MARC::Spec.find('650[0-1]', marc_record)
# => [#<MARC::DataField:0x00007ffa1799a5c0
# @indicator1=" ",
# @indicator2="0",
# @subfields=[#<MARC::Subfield:0x00007ffa17999878 @code="a", @value="Arithmetic">, #<MARC::Subfield:0x00007ffa179984a0 @code="x", @value="Juvenile poetry.">],
# @tag="650">,
# #<MARC::DataField:0x00007ffa17992618
# @indicator1=" ",
# @indicator2="0",
# @subfields=[#<MARC::Subfield:0x00007ffa179918d0 @code="a", @value="Children's poetry, American.">],
# @tag="650">]
Find subfield a
of all 650 fields:
MARC::Spec.find('650$a', marc_record)
# =>
# [#<MARC::Subfield:0x00007ffa17999878 @code="a", @value="Arithmetic">,
# #<MARC::Subfield:0x00007ffa179918d0 @code="a", @value="Children's poetry, American.">,
# #<MARC::Subfield:0x00007ffa1798acb0 @code="a", @value="Arithmetic">,
# #<MARC::Subfield:0x00007ffa17982cb8 @code="a", @value="American poetry.">,
# #<MARC::Subfield:0x00007ffa17980120 @code="a", @value="Visual perception.">]
Find the first six characters (characters 0 through 5) of subfield a
of the fifth (zero-indexed) 650
field:
MARC::Spec.find('650[4]$a/0-5', marc_record)
# => ["Visual"]
Find all 650
fields having a value of 0
for the second indicator:
MARC::Spec.find('650{^2=\0}', marc_record)
# =>
# [#<MARC::DataField:0x00007ffa1799a5c0
# @indicator1=" ",
# @indicator2="0",
# @subfields=[#<MARC::Subfield:0x00007ffa17999878 @code="a", @value="Arithmetic">, #<MARC::Subfield:0x00007ffa179984a0 @code="x", @value="Juvenile poetry.">],
# @tag="650">,
# #<MARC::DataField:0x00007ffa17992618
# @indicator1=" ",
# @indicator2="0",
# @subfields=[#<MARC::Subfield:0x00007ffa179918d0 @code="a", @value="Children's poetry, American.">],
# @tag="650">]
Find subfield a
of each 650
field that also has a subfield x
:
MARC::Spec.find('650$a{$x}', marc_record)
# => [#<MARC::Subfield:0x00007ffa17999878 @code="a", @value="Arithmetic">, #<MARC::Subfield:0x00007ffa1798acb0 @code="a", @value="Arithmetic">]
Note that this 650$a{$x}
could also be written 650$a{?$x}
; the ?
("exists") operator
is implicit if no other operator is specified.
Find the first seven characters of 260$b
, but only if the corresponding $a
contains
the string San Diego
and there is at least one 050$b
containing as a substring characters
7 through 10 of the 008
field:
MARC::Spec.find('260$b/0-7{$a~\San\sDiego}{050$b~008/7-10}', marc_record)
# => ["Harcourt"]
For further examples, see the MARCSpec documentation.
The tests for this gem include a set generated from the MARCSpec-Test-Suite
project, which is provided as a Git submodule
under spec/suite
.
The tests themselves are in spec/suite/generated
. It's not necessary to fetch the submodule in order
to run these tests, but it is necessary if you need to regenerate them. To fetch the submodule, from the project root, run:
git submodule init
git submodule update
To regenerate the tests, run rake spec:generate
.