def descendants_by_name(self, desc_name): """ Gets all sub-elements that match a query name """ r = (d for d in flatten(self) if d.name == desc_name) res = tuple(r) if not res: return None return res
def get_by_id_ref(self, attrref, attrvalue, tagfilter=None): """ Generic function by pointer references within the document to get all other tags that contain this ID. For example, given: ... <system sbref="123" /> ... <sb xml:id="123" /> ... The call: get_by_id_ref("sbref", "123") will return a pointer to the <system /> element in the tree. If tagfilter is not None, it will only return the attribute values on a specific tag, e.g., get_by_id_ref("sbref", "123", "system"). This is useful if you have multiple possible places where an attribute is being used in the document. Returns a list of MeiElements that match. """ if not self.__flattened_elements: self.__flattened_elements = flatten(self.root) if tagfilter: filt_elements = self.search(tagfilter) return [f for f in filt_elements if f.has_attribute(attrref) and f.attribute_by_name(attrref).value == attrvalue] else: return [f for f in self.__flattened_elements if f.has_attribute(attrref) and f.attribute_by_name(attrref).value == attrvalue]
def flat(self): """ Returns a flattened list of the elements in this document. Useful for searching and doing document-wide operations on many related elements in different places in the document. """ if not self.__flattened_elements: self.__flattened_elements = flatten(self.root) return self.__flattened_elements
def descendant_by_id(self, desc_id): """ Get a descendant element by that element's unique id """ r = (d for d in flatten(self) if d.id == desc_id) res = tuple(r) if not res: return None elif len(res) > 1: raise MeiError("There is more than one element with that ID. Someone screwed up.") return None else: return res[0]
def get_by_id(self, id): """ Gets a document object by ID. Returns None if the element does not exist. """ if not self.__flattened_elements: self.__flattened_elements = flatten(self.root) # return (o for o in self.__flattened_elements if o.id == id) els = self.get_by_id_ref("xml:id", id) if not els: return None else: return els[0]
def get_system(self, element): """ Returns the 'n' attribute of the system break immediately preceding the given MEI Element. If the element is not found, None will be returned. If the element occurs before the first system break, -1 will be returned. """ current_system = -1 if not self.__flattened_elements: self.__flattened_elements = flatten(self.root) for e in self.__flattened_elements: if e.name == 'sb': current_system = e.attribute_by_name('n').value if e.id == element.id: return current_system return None
def search(self, searchterm, *args, **kwargs): """ Searches an MEI Document for an object name that matches the search term. @TODO: Passing in args will narrow down the search by only retrieving objects with that attribute. Passing in kwargs will narrow down the search by only retrieving objects where k = v. """ # there should only be one toplevel element if not self.__flattened_elements: self.__flattened_elements = flatten(self.root) return [o for o in self.__flattened_elements if o.name == searchterm]
def get_by_id_ref(self, attrref, attrvalue, tagfilter=None): """ Generic function by pointer references within the document to get all other tags that contain this ID. For example, given: ... <system sbref="123" /> ... <sb xml:id="123" /> ... The call: get_by_id_ref("sbref", "123") will return a pointer to the <system /> element in the tree. If tagfilter is not None, it will only return the attribute values on a specific tag, e.g., get_by_id_ref("sbref", "123", "system"). This is useful if you have multiple possible places where an attribute is being used in the document. Returns a list of MeiElements that match. """ if not self.__flattened_elements: self.__flattened_elements = flatten(self.gettoplevel()) def __idfilt(ob, ar=attrref, av=attrvalue, tf=tagfilter): try: if ob.attribute_by_name(ar).value == av: if not tf: return ob else: if ob.name == tf: return ob except AttributeError, e: return None
def get_by_id(self, id): """ Gets a document object by ID. """ if not self.__flattened_elements: self.__flattened_elements = flatten(self.root) # return (o for o in self.__flattened_elements if o.id == id) return self.get_by_id_ref("xml:id", id)
# grab the next eight neumes incipit_neumes = [] for n in flattened[division_index:]: if n.name == "neume": incipit_neumes.append(n) if len(incipit_neumes) == 8: break if len(incipit_neumes) < 8: continue incipit_notes = [] # grab all the notes in the neumes for neume in incipit_neumes: neume_notes = [n for n in flatten(neume) if n.name == "note"] incipit_notes.extend(neume_notes) # grab the locations for each neume locs = getLocation(incipit_notes, meifile, zones) notes = [n.attribute_by_name('pname').value for n in incipit_notes] notes = "".join(notes) incipits.append({"id": str(uuid.uuid4()), "incipit": notes, "location": str(locs), "pagen": pagen}) print incipits solrconn.add_many(incipits)
def id_to_tstamp(event, base=None): ''' Returns the tstamp of one event. NB: the event needs to be in a layer; the layer is supposed to start at beginning of measure ''' def __add_dot(total, dur): '''given a total number of dots and a dotted event's duration, calculates the relative duration''' rel_dur = 0.0000 dur = float(dur) while total != 1: rel_dur += 1 / (dur * 2) dur = dur*2 total -= 1 return rel_dur context = event.ancestor_by_name('layer') if context == None: raise MeiError('The current event must be in a mei:layer.') top = event.ancestor_by_name('music') # is there a better way to go up to the top? (say, root, without using MEIDocument?) #if base is not provided, get it from scoredef if base==None: scoredef = -1 # get the preceding::scoreDef[0] for e in flatten(top): if e.name == 'scoreDef': scoredef = e if e.id == event.id: break if scoredef != -1: base = float(scoredef.attribute_by_name('meter.unit').value) else: raise MeiError('Could not find a score definition.') #get all events in context (notes + rests. Other events that should be considered?) notes = context.descendants_by_name('note') rests = context.descendants_by_name('rest') events = [] if notes: events += notes if rests: events += rests durations = 0.0000 # sum up the durations of events preceding the current event for ev in events: # stop when reaching the current event if ev.id == event.id: break # add current duration durations += 1 / float(event.attribute_by_name('dur').value) # add dots if present (either as attribute or element) # this assumes that dots are encoded either with attribute OR with element - duplication sums up if event.attribute_by_name('dots') != None: total = float(event.attribute_by_name('dots').value) dur = float(event.attribute_by_name('dur').value) durations += __add_dot(total, dur) elif event.descendants_by_name('dot') != None: total = float(len(event.descendants_by_name('dot'))) dur = float(event.attribute_by_name('dur').value) durations += __add_dot(total, dur) # Finally calculate the current timestamp given the sum of preceding durations and the base. tstamp = (durations / ( 1 / base)) + 1 return tstamp