Next / Previous / Contents / Shipman's homepage

12. class BirdForm: Notes for one kind of bird

An instance of this class represents the XML form element. See the definition of the form element in the schema.

In much of this program, the structure of objects follows the XML structure fairly closely. For example, where the XML has a note-set root element with day-notes children, the object structure has a BirdNoteSet root with DayNotes children. However, in the BirdForm class, we deviate from that structure. A Sighting instance is similar but not identical to a floc element in the XML.

In the XML, the floc element is optional, and used only when multiple sightings of the same kind of bird differ in their ages, sexes, locality codes, or other details. It would have been more consistent to design the schema such that the form element carried the species code, and the rest had to be wrapped in a floc element that would carry age, sex, and other data. However, since the vast majority of records have only one floc element, and since the initial XML file creation was done by hand (using emacs), the schema's single-sighting pattern allows the floc level to be omitted.

In any case, each BirdForm instance has one or more Sighting instance children. An XML form element with no floc children will be translated into a BirdForm instance with one Sighting child, while an XML form element with three floc children will be translated into a BirdForm instance with three Sighting children.

Note that the schema allows both form and floc elements to carry loc-group and sighting-notes content. The internal representation depends on whether this is the single-sighting or multi-sighting case.

For more discussion about potential differences between XML as read and XML as written, see BirdForm-writeNode.

birdnotes.py
# - - - - -   c l a s s   B i r d F o r m

class BirdForm:
    """Represents one or more sightings of a single kind of bird.

      Exports:
        BirdForm(dayNotes, birdId, notable=None):
          [ (dayNotes is a DayNotes instance) and
            (birdId is an abbr.BirdId instance) and
            (notable is true iff the sighting is notable) ->
              dayNotes  +:=   a new BirdForm instance with those values,
                              containing no sightings
              return that instance ]
        .dayNotes:    [ as passed to constructor, read-only ]
        .birdId:      [ as passed to constructor, read-only ]
        .notable:     [ as passed to constructor, read-only ]

We also pass through the .txKey attribute of self.birdId.

birdnotes.py
        .txKey:   [ passthrough, equals .birdId.txKey ]

Sightings are added and retrieving using these methods:

birdnotes.py
        .__len__(self):  [ return number of sightings in self ]
        .__getitem__(self, n):
          [ n is an integer ->
              if n is the index of a sighting in self ->
                return that as a Sighting instance
              else -> raise KeyError ]
        .addSighting(sighting):
          [ sighting is a Sighting instance ->
              self  :=  self with sighting added ]
        .genSightings():
          [ generate sightings in self as a sequence of Sighting
            instances in the order they were added ]

Because the schema allows elements such as loc-detail and desc to be attached to either the form element or the floc element, we have to implement inheritance. For example, if the parent form has a loc-detail describing the precise location of the sighting, it applies to each of its child floc elements, unless the child overrides it with its own loc-detail element. Hence, these next attributes represent items that can occur either here in a BirdForm instance or in the child Sighting instances or both. They are designated as read/write attributes, intended to be set or retrieved by direct attribute references from outside the class.

birdnotes.py
        .locGroup:
          [ if self has locality information ->
              a LocGroup instance representing the locality
            else -> None ]
        .sightNotes:
          [ if self has any sighting notes ->
              a SightNotes instance representing those notes
            else -> None ]

We also provide a .getLoc() method to find the effective locality data, using inheritance from the parent DayNotes instance for locality attributes not defined at this level. Compare this to the .locGroup attribute, which describes only the locality data directly provided at the form level.

birdnotes.py
        .getLoc():
          [ return the effective locality data for self as a
            Loc instance ]

The class has the usual node reader and writer functions. There may be one or multiple “sightings,” stored in the instance's ._sightingList attribute.

birdnotes.py
        BirdForm.readNode(txny, dayNotes, node):    # Static method
          [ (txny is a bird taxonomy as a txny.Txny instance) and
            (dayNotes is the parent DayNotes instance) and
            (node is an et.Element) ->
              if node is an rnc.FORM_N node conforming to
              birdnotes.rnc and txny ->
                dayNotes  +:=  a new BirdForm instance representing node
                return that instance
              else -> raise IOError ]                
        .writeNode(parent):
          [ parent is an et.Element ->
              parent  :=  parent with a new rnc.FORM_N node
                          added representing self
              return that new node ]

Additional internal state:

birdnotes.py
      State/Invariants:
        ._sightingList:
          [ a list containing the Sighting instances in self
            in the order they were added ]
    """

12.1. BirdForm.__len__(): Number of sightings

This method returns the number of sightings inside the instance.

birdnotes.py
# - - -   B i r d F o r m . _ _ l e n _ _

    def __len__(self):
        """Return the sighting count for self.
        """
        return  len(self._sightingList)