def validate_feed(content, content_type, base_uri): """Validate the content of an Atom, RSS, or KML feed. :param content: string containing xml feed :param content_type: Content-Type HTTP header :param base_uri: Feed URI for comparison with <link rel="self"> Prints formatted list of warnings and errors for use in doctests. No return value. """ lines = content.split('\n') result = feedvalidator.validateStream(StringIO(content), contentType=content_type, base=base_uri) errors = [] for error_level in (feedvalidator.logging.Error, feedvalidator.logging.Warning, feedvalidator.logging.Info): for item in result['loggedEvents']: if isinstance(item, error_level): errors.append("-------- %s: %s --------" % (error_level.__name__, item.__class__.__name__)) for key, value in sorted(item.params.items()): errors.append('%s: %s' % (key.title(), value)) if 'line' not in item.params: continue if isinstance(item, feedvalidator.logging.SelfDoesntMatchLocation): errors.append('Location: %s' % base_uri) error_line_number = item.params['line'] column_number = item.params['column'] errors.append('=') # Wrap the line with the error to make it clearer # which column contains the error. max_line_length = 66 wrapped_column_number = column_number % max_line_length line_number_range = list( range(max(error_line_number - 2, 1), min(error_line_number + 3, len(lines)))) for line_number in line_number_range: unicode_line = unicode(lines[line_number - 1], 'ascii', 'replace') ascii_line = unicode_line.encode('ascii', 'replace') wrapped_lines = wrap(ascii_line, max_line_length) if line_number == error_line_number: # Point to the column where the error occurs, e.g. # Error: <feed><entriez> # Point: ~~~~~~~~~~~~~^~~~~~~~~~~~~~~ point_list = ['~'] * max_line_length point_list[wrapped_column_number] = '^' point_string = ''.join(point_list) index = column_number / max_line_length + 1 wrapped_lines.insert(index, point_string) errors.append("% 3d: %s" % (line_number, '\n : '.join(wrapped_lines))) errors.append('=') if len(errors) == 0: print "No Errors" else: print '\n'.join(errors)
def _validate(self, headers, body): if headers.status in [200, 201]: baseuri = headers.get('content-location', '') try: events = feedvalidator.validateStream(cStringIO.StringIO(body), firstOccurrenceOnly=1, base=baseuri)['loggedEvents'] except feedvalidator.logging.ValidationFailure, vf: events = [vf.event] errors = [event for event in events if isinstance(event, feedvalidator.logging.Error)] if errors: self.error(msg.VALID_ATOM, "\n".join(text_formatter(errors))) warnings = [event for event in events if isinstance(event, feedvalidator.logging.Warning)] if warnings: self.warning(msg.VALID_ATOM, "\n".join(text_formatter(warnings))) if self.verbosity > 2: infos = [event for event in events if isinstance(event, feedvalidator.logging.Info)] if infos: self.info("\n".join(text_formatter(infos)))
if __name__ == '__main__': # arg 1 is URL to validate link = sys.argv[1:] and sys.argv[1] or 'http://www.intertwingly.net/blog/index.atom' link = urlparse.urljoin('file:' + urllib.pathname2url(os.getcwd()) + '/', link) try: link = link.decode('utf-8').encode('idna') except: pass print 'Validating %s' % link curdir = os.path.abspath(os.path.dirname(sys.argv[0])) basedir = urlparse.urljoin('file:' + curdir, ".") try: if link.startswith(basedir): events = feedvalidator.validateStream(urllib.urlopen(link), firstOccurrenceOnly=1,base=link.replace(basedir,"http://www.feedvalidator.org/"))['loggedEvents'] else: events = feedvalidator.validateURL(link, firstOccurrenceOnly=1)['loggedEvents'] except feedvalidator.logging.ValidationFailure, vf: events = [vf.event] # (optional) arg 2 is compatibility level # "A" is most basic level # "AA" mimics online validator # "AAA" is experimental; these rules WILL change or disappear in future versions from feedvalidator import compatibility filter = sys.argv[2:] and sys.argv[2] or "AA" filterFunc = getattr(compatibility, filter) events = filterFunc(events) from feedvalidator.formatter.text_plain import Formatter
link = urlparse.urljoin('file:' + urllib.pathname2url(os.getcwd()) + '/', link) try: link = link.decode('utf-8').encode('idna') except: pass print 'Validating %s' % link curdir = os.path.abspath(os.path.dirname(sys.argv[0])) basedir = urlparse.urljoin('file:' + curdir, ".") try: if link.startswith(basedir): events = feedvalidator.validateStream( urllib.urlopen(link), firstOccurrenceOnly=1, base=link.replace( basedir, "http://www.feedvalidator.org/"))['loggedEvents'] else: events = feedvalidator.validateURL( link, firstOccurrenceOnly=1)['loggedEvents'] except feedvalidator.logging.ValidationFailure as vf: events = [vf.event] # (optional) arg 2 is compatibility level # "A" is most basic level # "AA" mimics online validator # "AAA" is experimental; these rules WILL change or disappear in future versions from feedvalidator import compatibility filter = sys.argv[2:] and sys.argv[2] or "AA" filterFunc = getattr(compatibility, filter)
def validate_feed(content, content_type, base_uri): """Validate the content of an Atom, RSS, or KML feed. :param content: string containing xml feed :param content_type: Content-Type HTTP header :param base_uri: Feed URI for comparison with <link rel="self"> Prints formatted list of warnings and errors for use in doctests. No return value. """ lines = content.split('\n') result = feedvalidator.validateStream( StringIO(content), contentType=content_type, base=base_uri) errors = [] for error_level in (feedvalidator.logging.Error, feedvalidator.logging.Warning, feedvalidator.logging.Info): for item in result['loggedEvents']: if isinstance(item, error_level): errors.append("-------- %s: %s --------" % (error_level.__name__, item.__class__.__name__)) for key, value in sorted(item.params.items()): errors.append('%s: %s' % (key.title(), value)) if 'line' not in item.params: continue if isinstance(item, feedvalidator.logging.SelfDoesntMatchLocation): errors.append('Location: %s' % base_uri) error_line_number = item.params['line'] column_number = item.params['column'] errors.append('=') # Wrap the line with the error to make it clearer # which column contains the error. max_line_length = 66 wrapped_column_number = column_number % max_line_length line_number_range = range( max(error_line_number-2, 1), min(error_line_number+3, len(lines))) for line_number in line_number_range: unicode_line = unicode( lines[line_number-1], 'ascii', 'replace') ascii_line = unicode_line.encode('ascii', 'replace') wrapped_lines = wrap(ascii_line, max_line_length) if line_number == error_line_number: # Point to the column where the error occurs, e.g. # Error: <feed><entriez> # Point: ~~~~~~~~~~~~~^~~~~~~~~~~~~~~ point_list = ['~'] * max_line_length point_list[wrapped_column_number] = '^' point_string = ''.join(point_list) index = column_number/max_line_length + 1 wrapped_lines.insert(index, point_string) errors.append( "% 3d: %s" % (line_number, '\n : '.join(wrapped_lines))) errors.append('=') if len(errors) == 0: print "No Errors" else: print '\n'.join(errors)