"""$Id: extension.py 750 2007-04-06 18:40:28Z rubys $""" __author__ = "Sam Ruby , Mark Pilgrim and Phil Ringnalda " __version__ = "$Revision: 750 $" __date__ = "$Date: 2007-04-06 18:40:28 +0000 (Fri, 06 Apr 2007) $" __copyright__ = "Copyright (c) 2002 Sam Ruby, Mark Pilgrim and Phil Ringnalda" from validators import * from logging import * ######################################################################## # Extensions that are valid everywhere # ######################################################################## class extension_everywhere: def do_dc_title(self): return text(), noduplicates() def do_dc_description(self): return text(), noduplicates() def do_dc_publisher(self): if "webMaster" in self.children: self.log(DuplicateSemantics({"core":"webMaster", "ext":"dc:publisher"})) return text() # duplicates allowed def do_dc_contributor(self): return text() # duplicates allowed def do_dc_type(self): return text(), noduplicates() def do_dc_format(self): return text(), noduplicates() def do_dc_identifier(self): return text() def do_dc_source(self): if "source" in self.children: self.log(DuplicateItemSemantics({"core":"source", "ext":"dc:source"})) return text(), noduplicates() def do_dc_language(self): if "language" in self.children: self.log(DuplicateSemantics({"core":"language", "ext":"dc:language"})) return iso639(), noduplicates() def do_dc_relation(self): return text(), # duplicates allowed def do_dc_coverage(self): return text(), # duplicates allowed def do_dc_rights(self): if "copyright" in self.children: self.log(DuplicateSemantics({"core":"copyright", "ext":"dc:rights"})) return nonhtml(), noduplicates() def do_dcterms_alternative(self): return text() #duplicates allowed def do_dcterms_abstract(self): return text(), noduplicates() def do_dcterms_tableOfContents(self): return rdfResourceURI(), noduplicates() def do_dcterms_created(self): return w3cdtf(), noduplicates() def do_dcterms_valid(self): return eater() def do_dcterms_available(self): return eater() def do_dcterms_issued(self): return w3cdtf(), noduplicates() def do_dcterms_modified(self): if "lastBuildDate" in self.children: self.log(DuplicateSemantics({"core":"lastBuildDate", "ext":"dcterms:modified"})) return w3cdtf(), noduplicates() def do_dcterms_dateAccepted(self): return text(), noduplicates() def do_dcterms_dateCopyrighted(self): return text(), noduplicates() def do_dcterms_dateSubmitted(self): return text(), noduplicates() def do_dcterms_extent(self): return positiveInteger(), nonblank(), noduplicates() # def do_dcterms_medium(self): # spec defines it as something that should never be used # undefined element'll do for now def do_dcterms_isVersionOf(self): return rdfResourceURI() # duplicates allowed def do_dcterms_hasVersion(self): return rdfResourceURI() # duplicates allowed def do_dcterms_isReplacedBy(self): return rdfResourceURI() # duplicates allowed def do_dcterms_replaces(self): return rdfResourceURI() # duplicates allowed def do_dcterms_isRequiredBy(self): return rdfResourceURI() # duplicates allowed def do_dcterms_requires(self): return rdfResourceURI() # duplicates allowed def do_dcterms_isPartOf(self): return rdfResourceURI() # duplicates allowed def do_dcterms_hasPart(self): return rdfResourceURI() # duplicates allowed def do_dcterms_isReferencedBy(self): return rdfResourceURI() # duplicates allowed def do_dcterms_references(self): return rdfResourceURI() # duplicates allowed def do_dcterms_isFormatOf(self): return rdfResourceURI() # duplicates allowed def do_dcterms_hasFormat(self): return rdfResourceURI() # duplicates allowed def do_dcterms_conformsTo(self): return rdfResourceURI() # duplicates allowed def do_dcterms_spatial(self): return eater() def do_dcterms_temporal(self): return eater() def do_dcterms_audience(self): return text() def do_dcterms_mediator(self): return text(), noduplicates() # added to DMCI, but no XML mapping has been defined def do_dcterms_accessRights(self): return eater() def do_dcterms_accrualMethod(self): return eater() def do_dcterms_accrualPeriodicity(self): return eater() def do_dcterms_accrualPolicy(self): return eater() def do_dcterms_bibliographicCitation(self): return eater() def do_dcterms_educationLevel(self): return eater() def do_dcterms_instructionalMethod(self): return eater() def do_dcterms_license(self): return eater() def do_dcterms_provenance(self): return eater() def do_dcterms_rightsHolder(self): return eater() def do_rdfs_seeAlso(self): return rdfResourceURI() # duplicates allowed def do_geo_Point(self): return geo_point() def do_geo_lat(self): return latitude() def do_geo_long(self): return longitude() def do_geo_alt(self): return decimal() def do_geourl_latitude(self): return latitude() def do_geourl_longitude(self): return longitude() def do_icbm_latitude(self): return latitude() def do_icbm_longitude(self): return longitude() ######################################################################## # Extensions that are valid at either the channel or item levels # ######################################################################## from media import media_elements, media_content, media_group class extension_channel_item(extension_everywhere, media_elements): def do_taxo_topics(self): return eater() def do_l_link(self): return l_link() ######################################################################## # Extensions that are valid at only at the item level # ######################################################################## class extension_item(extension_channel_item): def do_annotate_reference(self): return rdfResourceURI(), noduplicates() def do_ag_source(self): return text(), noduplicates() def do_ag_sourceURL(self): return rfc2396_full(), noduplicates() def do_ag_timestamp(self): return iso8601(), noduplicates() def do_ev_startdate(self): return iso8601(), noduplicates() def do_ev_enddate(self): return iso8601(), noduplicates() def do_ev_location(self): return eater() def do_ev_organizer(self): return eater() def do_ev_type(self): return text(), noduplicates() def do_foaf_maker(self): return eater() def do_foaf_primaryTopic(self): return eater() def do_slash_comments(self): return nonNegativeInteger() def do_slash_section(self): return text() def do_slash_department(self): return text() def do_slash_hit_parade(self): return commaSeparatedIntegers(), noduplicates() def do_thr_children(self): return eater() def do_thr_in_reply_to(self): return in_reply_to() def do_wfw_comment(self): return rfc2396_full(), noduplicates() def do_wfw_commentRss(self): return rfc2396_full(), noduplicates() def do_wfw_commentRSS(self): self.log(CommentRSS({"parent":self.parent.name, "element":self.name})) return rfc2396_full(), noduplicates() def do_wiki_diff(self): return text() def do_wiki_history(self): return text() def do_wiki_importance(self): return text() def do_wiki_status(self): return text() def do_wiki_version(self): return text() def do_g_actor(self): return nonhtml(), noduplicates() def do_g_age(self): return nonNegativeInteger(), noduplicates() def do_g_agent(self): return nonhtml(), noduplicates() def do_g_area(self): return nonhtml(), noduplicates() # intUnit def do_g_apparel_type(self): return nonhtml(), noduplicates() def do_g_artist(self): return nonhtml(), noduplicates() def do_g_author(self): return nonhtml(), noduplicates() def do_g_bathrooms(self): return nonNegativeInteger(), noduplicates() def do_g_bedrooms(self): return nonNegativeInteger(), noduplicates() def do_g_brand(self): return nonhtml(), noduplicates() def do_g_calories(self): return g_float(), noduplicates() def do_g_cholesterol(self): return g_float(), noduplicates() def do_g_color(self): return nonhtml(), noduplicates() def do_g_cooking_time(self): return g_float(), noduplicates() def do_g_condition(self): return nonhtml(), noduplicates() def do_g_course(self): return nonhtml(), noduplicates() def do_g_course_date_range(self): return g_dateTimeRange(), noduplicates() def do_g_course_number(self): return nonhtml(), noduplicates() def do_g_course_times(self): return nonhtml(), noduplicates() def do_g_cuisine(self): return nonhtml(), noduplicates() def do_g_currency(self): return iso4217(), noduplicates() def do_g_delivery_notes(self): return nonhtml(), noduplicates() def do_g_delivery_radius(self): return floatUnit(), noduplicates() def do_g_education(self): return nonhtml(), noduplicates() def do_g_employer(self): return nonhtml(), noduplicates() def do_g_ethnicity(self): return nonhtml(), noduplicates() def do_g_event_date_range(self): return g_dateTimeRange(), noduplicates() def do_g_expiration_date(self): return iso8601_date(), noduplicates() def do_g_expiration_date_time(self): return iso8601(), noduplicates() def do_g_fiber(self): return g_float(), noduplicates() def do_g_from_location(self): return g_locationType(), noduplicates() def do_g_gender(self): return g_genderEnumeration(), noduplicates() def do_g_hoa_dues(self): return g_float(), noduplicates() def do_g_format(self): return nonhtml(), noduplicates() def do_g_id(self): return nonhtml(), noduplicates() def do_g_image_link(self): return rfc2396_full(), maxten() def do_g_immigration_status(self): return nonhtml(), noduplicates() def do_g_interested_in(self): return nonhtml(), noduplicates() def do_g_isbn(self): return nonhtml(), noduplicates() def do_g_job_function(self): return nonhtml(), noduplicates() def do_g_job_industry(self): return nonhtml(), noduplicates() def do_g_job_type(self): return nonhtml(), noduplicates() def do_g_label(self): return g_labelType(), maxten() def do_g_listing_type(self): return truefalse(), noduplicates() def do_g_location(self): return g_full_locationType(), noduplicates() def do_g_main_ingredient(self): return nonhtml(), noduplicates() def do_g_make(self): return nonhtml(), noduplicates() def do_g_manufacturer(self): return nonhtml(), noduplicates() def do_g_manufacturer_id(self): return nonhtml(), noduplicates() def do_g_marital_status(self): return g_maritalStatusEnumeration(), noduplicates() def do_g_meal_type(self): return nonhtml(), noduplicates() def do_g_megapixels(self): return floatUnit(), noduplicates() def do_g_memory(self): return floatUnit(), noduplicates() def do_g_mileage(self): return g_intUnit(), noduplicates() def do_g_model(self): return nonhtml(), noduplicates() def do_g_model_number(self): return nonhtml(), noduplicates() def do_g_name_of_item_being_reviewed(self): return nonhtml(), noduplicates() def do_g_news_source(self): return nonhtml(), noduplicates() def do_g_occupation(self): return nonhtml(), noduplicates() def do_g_payment_notes(self): return nonhtml(), noduplicates() def do_g_pages(self): return positiveInteger(), nonblank(), noduplicates() def do_g_payment_accepted(self): return g_paymentMethodEnumeration() def do_g_pickup(self): return truefalse(), noduplicates() def do_g_preparation_time(self): return floatUnit(), noduplicates() def do_g_price(self): return floatUnit(), noduplicates() def do_g_price_type(self): return g_priceTypeEnumeration(), noduplicates() def do_g_processor_speed(self): return floatUnit(), noduplicates() def do_g_product_type(self): return nonhtml(), noduplicates() def do_g_property_type(self): return nonhtml(), noduplicates() def do_g_protein(self): return floatUnit(), noduplicates() def do_g_publication_name(self): return nonhtml(), noduplicates() def do_g_publication_volume(self): return nonhtml(), noduplicates() def do_g_publish_date(self): return iso8601_date(), noduplicates() def do_g_quantity(self): return nonNegativeInteger(), nonblank(), noduplicates() def do_g_rating(self): return g_ratingTypeEnumeration(), noduplicates() def do_g_review_type(self): return nonhtml(), noduplicates() def do_g_reviewer_type(self): return g_reviewerTypeEnumeration(), noduplicates() def do_g_salary(self): return g_float(), noduplicates() def do_g_salary_type(self): return g_salaryTypeEnumeration(), noduplicates() def do_g_saturated_fat(self): return g_float(), noduplicates() def do_g_school_district(self): return nonhtml(), noduplicates() def do_g_service_type(self): return nonhtml(), noduplicates() def do_g_servings(self): return g_float(), noduplicates() def do_g_sexual_orientation(self): return nonhtml(), noduplicates() def do_g_size(self): return nonhtml(), noduplicates() # TODO: expressed in either two or three dimensions. def do_g_shipping(self): return g_shipping(), noduplicates() def do_g_sodium(self): return g_float(), noduplicates() def do_g_subject(self): return nonhtml(), noduplicates() def do_g_subject_area(self): return nonhtml(), noduplicates() def do_g_tax_percent(self): return percentType(), noduplicates() def do_g_tax_region(self): return nonhtml(), noduplicates() def do_g_to_location(self): return g_locationType(), noduplicates() def do_g_total_carbs(self): return g_float(), noduplicates() def do_g_total_fat(self): return g_float(), noduplicates() def do_g_travel_date_range(self): return g_dateTimeRange(), noduplicates() def do_g_university(self): return nonhtml(), noduplicates() def do_g_upc(self): return nonhtml(), noduplicates() def do_g_url_of_item_being_reviewed(self): return rfc2396_full(), noduplicates() def do_g_vehicle_type(self): return nonhtml(), noduplicates() def do_g_vin(self): return nonhtml(), noduplicates() def do_g_weight(self): return floatUnit(), noduplicates() def do_g_year(self): return g_year(), noduplicates() def do_media_group(self): return media_group() def do_media_content(self): return media_content() def do_georss_where(self): return georss_where() def do_georss_point(self): return gml_pos() def do_georss_line(self): return gml_posList() def do_georss_polygon(self): return gml_posList() def do_georss_featuretypetag(self): return text() def do_georss_relationshiptag(self): return text() def do_georss_featurename(self): return text() def do_georss_elev(self): return decimal() def do_georss_floor(self): return Integer() def do_georss_radius(self): return Float() class georss_where(validatorBase): def do_gml_Point(self): return gml_point() def do_gml_LineString(self): return gml_line() def do_gml_Polygon(self): return gml_polygon() def do_gml_Envelope(self): return gml_envelope() class geo_srsName(validatorBase): def getExpectedAttrNames(self): return [(None, u'srsName')] class gml_point(geo_srsName): def do_gml_pos(self): return gml_pos() class geo_point(validatorBase): def do_geo_lat(self): return latitude() def do_geo_long(self): return longitude() def validate(self): if "geo_lat" not in self.children: self.log(MissingElement({"parent":self.name.replace('_',':'), "element":"geo:lat"})) if "geo_long" not in self.children: self.log(MissingElement({"parent":self.name.replace('_',':'), "element":"geo:long"})) class gml_pos(text): def validate(self): if not re.match('^[-+]?\d+\.?\d*[ ,][-+]?\d+\.?\d*$', self.value): return self.log(InvalidCoord({'value':self.value})) if self.value.find(',')>=0: self.log(CoordComma({'value':self.value})) class gml_line(geo_srsName): def do_gml_posList(self): return gml_posList() class gml_posList(text): def validate(self): if self.value.find(',')>=0: # ensure that commas are only used to separate lat and long if not re.match('^[-+.0-9]+[, ][-+.0-9]( [-+.0-9]+[, ][-+.0-9])+$', value.strip()): return self.log(InvalidCoordList({'value':self.value})) self.log(CoordComma({'value':self.value})) self.value=self.value.replace(',',' ') values = self.value.strip().split() if len(values)<3 or len(values)%2 == 1: return self.log(InvalidCoordList({'value':self.value})) for value in values: if not re.match('^[-+]?\d+\.?\d*$', value): return self.log(InvalidCoordList({'value':value})) class gml_polygon(geo_srsName): def do_gml_exterior(self): return gml_exterior() class gml_exterior(validatorBase): def do_gml_LinearRing(self): return gml_linearRing() class gml_linearRing(geo_srsName): def do_gml_posList(self): return gml_posList() class gml_envelope(geo_srsName): def do_gml_lowerCorner(self): return gml_pos() def do_gml_upperCorner(self): return gml_pos() class access_restriction(enumeration): error = InvalidAccessRestrictionRel valuelist = ["allow", "deny"] def getExpectedAttrNames(self): return [(None, u'relationship')] def prevalidate(self): self.children.append(True) # force warnings about "mixed" content if not self.attrs.has_key((None,"relationship")): self.log(MissingAttribute({"parent":self.parent.name, "element":self.name, "attr":"relationship"})) else: self.value=self.attrs.getValue((None,"relationship")) ######################################################################## # Extensions that are valid at only at the RSS 2.0 item level # ######################################################################## class extension_rss20_item(extension_item): def do_trackback_ping(self): return rfc2396_full(), noduplicates() def do_trackback_about(self): return rfc2396_full() def do_dcterms_accessRights(self): return eater() def do_dcterms_accrualMethod(self): return eater() def do_dcterms_accrualPeriodicity(self): return eater() def do_dcterms_accrualPolicy(self): return eater() def do_dcterms_bibliographicCitation(self): return eater() def do_dcterms_educationLevel(self): return eater() def do_dcterms_instructionalMethod(self): return eater() def do_dcterms_license(self): return eater() def do_dcterms_provenance(self): return eater() def do_dcterms_rightsHolder(self): return eater() ######################################################################## # Extensions that are valid at only at the RSS 1.0 item level # ######################################################################## class extension_rss10_item(extension_item): def do_trackback_ping(self): return rdfResourceURI(), noduplicates() def do_trackback_about(self): return rdfResourceURI() def do_l_permalink(self): return l_permalink() class l_permalink(rdfResourceURI, MimeType): lNS = u'http://purl.org/rss/1.0/modules/link/' def getExpectedAttrNames(self): return rdfResourceURI.getExpectedAttrNames(self) + [(self.lNS, u'type')] def validate(self): if (self.lNS, 'type') in self.attrs.getNames(): self.value=self.attrs.getValue((self.lNS, 'type')) MimeType.validate(self) return rdfResourceURI.validate(self) class l_link(rdfResourceURI, MimeType): lNS = u'http://purl.org/rss/1.0/modules/link/' def getExpectedAttrNames(self): return rdfResourceURI.getExpectedAttrNames(self) + [ (self.lNS, u'lang'), (self.lNS, u'rel'), (self.lNS, u'type'), (self.lNS, u'title') ] def prevalidate(self): self.validate_optional_attribute((self.lNS,'lang'), iso639) self.validate_required_attribute((self.lNS,'rel'), rfc2396_full) self.validate_optional_attribute((self.lNS,'title'), nonhtml) if self.attrs.has_key((self.lNS, "type")): if self.attrs.getValue((self.lNS, "type")).find(':') < 0: self.validate_optional_attribute((self.lNS,'type'), MimeType) else: self.validate_optional_attribute((self.lNS,'type'), rfc2396_full) ######################################################################## # Extensions that are valid at only at the Atom entry level # ######################################################################## class extension_entry(extension_item): def do_dc_creator(self): # atom:creator return text() # duplicates allowed def do_dc_subject(self): # atom:category return text() # duplicates allowed def do_dc_date(self): # atom:published return w3cdtf(), noduplicates() def do_creativeCommons_license(self): return rfc2396_full() def do_trackback_ping(self): return rfc2396_full(), noduplicates() # XXX This should have duplicate semantics with link[@rel='related'] def do_trackback_about(self): return rfc2396_full() ######################################################################## # Extensions that are valid at only at the channel level # ######################################################################## class extension_channel(extension_channel_item): def do_admin_generatorAgent(self): if "generator" in self.children: self.log(DuplicateSemantics({"core":"generator", "ext":"admin:generatorAgent"})) return admin_generatorAgent(), noduplicates() def do_admin_errorReportsTo(self): return admin_errorReportsTo(), noduplicates() def do_blogChannel_blogRoll(self): return rfc2396_full(), noduplicates() def do_blogChannel_mySubscriptions(self): return rfc2396_full(), noduplicates() def do_blogChannel_blink(self): return rfc2396_full(), noduplicates() def do_blogChannel_changes(self): return rfc2396_full(), noduplicates() def do_sy_updatePeriod(self): return sy_updatePeriod(), noduplicates() def do_sy_updateFrequency(self): return positiveInteger(), nonblank(), noduplicates() def do_sy_updateBase(self): return w3cdtf(), noduplicates() def do_foaf_maker(self): return eater() def do_cp_server(self): return rdfResourceURI() def do_wiki_interwiki(self): return text() def do_thr_in_reply_to(self): return in_reply_to() def do_cf_listinfo(self): from cf import listinfo return listinfo() def do_cf_treatAs(self): from cf import treatAs return treatAs() def do_opensearch_totalResults(self): return nonNegativeInteger(), noduplicates() def do_opensearch_startIndex(self): return Integer(), noduplicates() def do_opensearch_itemsPerPage(self): return nonNegativeInteger(), noduplicates() def do_opensearch_Query(self): from opensearch import Query return Query() def do_xhtml_div(self): return eater() def do_xhtml_meta(self): return xhtml_meta() class xhtml_meta(validatorBase): def getExpectedAttrNames(self): return [ (None, u'name'), (None, u'content') ] def prevalidate(self): self.validate_required_attribute((None,'name'), xhtmlMetaEnumeration) self.validate_required_attribute((None,'content'), robotsEnumeration) class xhtmlMetaEnumeration(caseinsensitive_enumeration): error = InvalidMetaName valuelist = ["robots"] class robotsEnumeration(caseinsensitive_enumeration): error = InvalidMetaContent valuelist = [ "all", "none", "index", "index,follow", "index,nofollow", "noindex", "noindex,follow", "noindex,nofollow", "follow", "follow,index", "follow,noindex", "nofollow", "nofollow,index", "nofollow,noindex"] ######################################################################## # Extensions that are valid at only at the Atom feed level # ######################################################################## class extension_feed(extension_channel): def do_dc_creator(self): # atom:creator return text() # duplicates allowed def do_dc_subject(self): # atom:category return text() # duplicates allowed def do_dc_date(self): # atom:updated return w3cdtf(), noduplicates() def do_creativeCommons_license(self): return rfc2396_full() def do_access_restriction(self): return access_restriction() ######################################################################## # Validators # ######################################################################## class admin_generatorAgent(rdfResourceURI): pass class admin_errorReportsTo(rdfResourceURI): pass class sy_updatePeriod(text): def validate(self): if self.value not in ('hourly', 'daily', 'weekly', 'monthly', 'yearly'): self.log(InvalidUpdatePeriod({"parent":self.parent.name, "element":self.name, "value":self.value})) else: self.log(ValidUpdatePeriod({"parent":self.parent.name, "element":self.name, "value":self.value})) class g_complex_type(validatorBase): def getExpectedAttrNames(self): if self.getFeedType() == TYPE_RSS1: return [(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', u'parseType')] else: return [] class g_shipping(g_complex_type): def do_g_service(self): return g_serviceTypeEnumeration(), noduplicates() def do_g_country(self): return iso3166(), noduplicates() def do_g_price(self): return floatUnit(), noduplicates() class g_dateTimeRange(g_complex_type): def do_g_start(self): return iso8601(), noduplicates() def do_g_end(self): return iso8601(), noduplicates() class g_labelType(text): def validate(self): if self.value.find(',')>=0: self.log(InvalidLabel({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class g_locationType(text): def validate(self): if len(self.value.split(',')) not in [2,3]: self.log(InvalidLocation({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class g_full_locationType(text): def validate(self): fields = self.value.split(',') if len(fields) != 5 or 0 in [len(f.strip()) for f in fields]: self.log(InvalidFullLocation({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class g_genderEnumeration(enumeration): error = InvalidGender valuelist = ["Male", "M", "Female", "F"] class g_maritalStatusEnumeration(enumeration): error = InvalidMaritalStatus valuelist = ["single", "divorced", "separated", "widowed", "married", "in relationship"] class g_paymentMethodEnumeration(enumeration): error = InvalidPaymentMethod valuelist = ["Cash", "Check", "Visa", "MasterCard", "AmericanExpress", "Discover", "WireTransfer"] class g_priceTypeEnumeration(enumeration): error = InvalidPriceType valuelist = ["negotiable", "starting"] class g_ratingTypeEnumeration(enumeration): error = InvalidRatingType valuelist = ["1", "2", "3", "4", "5"] class g_reviewerTypeEnumeration(enumeration): error = InvalidReviewerType valuelist = ["editorial", "user"] class g_salaryTypeEnumeration(enumeration): error = InvalidSalaryType valuelist = ["starting", "negotiable"] class g_serviceTypeEnumeration(enumeration): error = InvalidServiceType valuelist = ['FedEx', 'UPS', 'DHL', 'Mail', 'Other', 'Overnight', 'Standard'] class g_float(text): def validate(self): import re if not re.match('\d+\.?\d*\s*\w*', self.value): self.log(InvalidFloat({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class floatUnit(text): def validate(self): import re if not re.match('\d+\.?\d*\s*\w*$', self.value): self.log(InvalidFloatUnit({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class decimal(text): def validate(self): import re if not re.match('[-+]?\d+\.?\d*\s*$', self.value): self.log(InvalidFloatUnit({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class g_year(text): def validate(self): import time try: year = int(self.value) if year < 1900 or year > time.localtime()[0]+4: raise InvalidYear except: self.log(InvalidYear({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class g_intUnit(text): def validate(self): try: if int(self.value.split(' ')[0].replace(',','')) < 0: raise InvalidIntUnit except: self.log(InvalidIntUnit({"parent":self.parent.name, "element":self.name, "attr": ':'.join(self.name.split('_',1)), "value":self.value})) class maxten(validatorBase): def textOK(self): pass def prevalidate(self): if 10 == len([1 for child in self.parent.children if self.name==child]): self.log(TooMany({"parent":self.parent.name, "element":self.name})) class in_reply_to(canonicaluri, xmlbase): def getExpectedAttrNames(self): return [(None, u'href'), (None, u'ref'), (None, u'source'), (None, u'type')] def validate(self): if self.attrs.has_key((None, "href")): self.value = self.attrs.getValue((None, "href")) self.name = "href" xmlbase.validate(self) if self.attrs.has_key((None, "ref")): self.value = self.attrs.getValue((None, "ref")) self.name = "ref" canonicaluri.validate(self) if self.attrs.has_key((None, "source")): self.value = self.attrs.getValue((None, "source")) self.name = "source" xmlbase.validate(self) if self.attrs.has_key((None, "type")): self.value = self.attrs.getValue((None, "type")) if not mime_re.match(self.value): self.log(InvalidMIMEType({"parent":self.parent.name, "element":self.name, "attr":"type", "value":self.value})) else: self.log(ValidMIMEAttribute({"parent":self.parent.name, "element":self.name, "attr":"type", "value":self.value}))