This method parses the common part of unbanded, new, and recap encounter lines: the body and tail. The “body” is the fixed-format part, and the “tail” is the free-format part that follows the body.
We define a class variable named BODY_FIELD_LIST that shows the classes and field
names of the body part. For the classes that process
each field type, see:
Section 49, “class MicroPPCField: Primary coverts
micro-aging field”.
Section 50, “class MicroSSCField: Secondary coverts
micro-aging field”.
Section 51, “class MicroPPFField: Primaries
micro-aging field”.
Section 52, “class MicroSSFField: Secondaries
micro-aging field”.
Section 53, “class MicroTTField: Tertials
micro-aging field”.
Section 54, “class MicroRRField: Rectrices micro-aging
field”.
Section 58, “class MicroBPLField: Body plumage
micro-aging field”.
Section 59, “class MicroNFField: Non-feather
micro-aging field”.
# - - - B a s e E n c o u n t e r . s c a n B o d y - - -
BODY_FIELD_LIST = [
(Spec4Field, SPEC4_ATTR),
(AgeCodeField, AGE_CODE_ATTR),
(HowGroupField, HOW_AGED_ATTR),
(WrpField, WRP_ATTR),
(SexCodeField, SEX_CODE_ATTR),
(HowGroupField, HOW_SEXED_ATTR),
(SkullField, SKULL_ATTR),
(CloacalField, CLOACAL_ATTR),
(BroodField, BROOD_ATTR),
(FatField, FAT_ATTR),
(BodyMoltField, BODY_MOLT_ATTR),
(FlightMoltField, FLIGHT_MOLT_ATTR),
(FlightWearField, FLIGHT_WEAR_ATTR),
(JuvenalField, JUVENAL_ATTR),
(MicroPPCField, MICRO_PPC_ATTR),
(MicroSSCField, MICRO_SSC_ATTR),
(MicroPPFField, MICRO_PPF_ATTR),
(MicroSSFField, MICRO_SSF_ATTR),
(MicroTTField, MICRO_TT_ATTR),
(MicroRRField, MICRO_RR_ATTR),
(MicroBPLField, MICRO_BPL_ATTR),
(MicroNFField, MICRO_NF_ATTR),
(WingField, WING_ATTR),
(MassField, MASS_ATTR),
(StatusField, STATUS_ATTR),
(DateField, DATE_ATTR),
(HHMField, TIME_ATTR) ]
def scanBody(self, scan):
'''Scan encounter record body and tail.
[ scan is a Scan object ->
if scan contains a valid encounter body and tail in
the context of self ->
scan := scan advanced to end of line
self := self with all fields from that line added
else ->
Log() +:= error message(s)
raise SyntaxError ]
'''
The body part of an encounter record contains a long sequence
of fixed-size fields. We can parse these fields in a
table-driven fashion by using Section 7, “scanFieldItems(): Parse a sequence of
FieldItem objects”.
The logic here parses the MAPS 2006 format. Other body
formats should use a class derived from BaseEncounter, and redefine the BODY_FIELD_LIST table appropriately.
#-- 1 --
# [ if the line in scan starts with a sequence of valid
# fields as described by self.BODY_FIELD_LIST ->
# scan := scan advanced past those fields
# self := self with values of those fields stored by
# the attribute names in self.BODY_FIELD_LIST
# else ->
# scan := scan advanced no further than end of line
# Log() +:= error message(s)
# raise SyntaxError ]
scanFieldItems(self, self.BODY_FIELD_LIST, scan)
The fields in self.BODY_FIELD_LIST stop just
before where the station code field will be in multi-station
sets; in single-station sets, there will be no station code.
See Section 66.1, “StationCodeField.scanField()”.
#-- 2 --
# [ if (self.compiler is a multi-station set) and
# (line in scan starts with a valid station code in
# the context of self.compiler) ->
# scan := scan advanced past that field
# self.(STATION_ATTR) := a StationCodeField containing
# that field
# else if (self.compiler is a multi-station set) and
# (line in scan does not start with a valid station code in
# the context of self.compiler) ->
# scan := scan advanced no further than end of line
# Log() +:= error message(s)
# raise SyntaxError
# else ->
# self.(STATION_ATTR) := a StationCodeField containing
# self.compiler.station.staCode ]
if self.compiler.location is not None:
#-- 2.1 --
# [ if line in scan starts with a valid station code in
# the context of self.compiler ->
# scan := scan advanced past that field
# self.(STATION_ATTR) := a Station object representing
# that field
# else ->
# scan := scan advanced no further than end of line
# Log() +:= error message(s)
# raise SyntaxError ]
StationCodeField.scanField(self, scan, STATION_ATTR)
else:
setattr(self, STATION_ATTR,
StationCodeField(self,
self.compiler.station.staCode))
Next we parse the net field. In this protocol, we use the
two-character version. Variants may wish to use a three-
or four-character net field; the output record has that
capacity. See Section 67.1, “Net2Field.scanField()”.
#-- 3 --
# [ if scan starts with a valid 2-character net field ->
# scan := scan advanced past that field
# self.(NET_ATTR) := that field
# else ->
# scan := scan advanced no further than end of line
# Log() +:= error message(s)
# raise SyntaxError ]
Net2Field.scanField(self, scan, NET_ATTR)
Next comes the alignment check character.
#-- 4 --
# [ if scan starts with an alignment check character ->
# scan := scan advanced past that character
# else ->
# Log() +:= error message(s)
# raise SyntaxError ]
m = scan.tabMatch(ALIGNMENT_CHAR)
if m is None:
scan.syntax("Expecting the alignment character, '%s'." %
ALIGNMENT_CHAR)
All that remains is to scan the tail section; see
Section 74.14, “BaseEncounter.scanTail(): Scan tail
fields”.
#-- 5 --
# [ if the line in scan starts with a valid tail section ->
# scan := scan advanced to end of line
# self := self with values from the tail stored using
# attribute names from self.OUT_FIELD_LIST
# else ->
# scan := scan advanced no further than end of line
# Log() +:= error message(s)
# raise SyntaxError ]
self.scanTail(scan)