Ticket #3094: validators.py

File validators.py, 3.3 KB (added by David Danier <goliath.mailinglist@…>, 18 years ago)

validator.py including RelaxNG-class

Line 
1from django.core.validators import ValidationError
2from lxml import etree
3from StringIO import StringIO
4from django.utils.translation import gettext_lazy as _
5from django.template.defaultfilters import escape
6import re
7
8class RelaxNG(object):
9 "Validate against a Relax NG schema"
10 def __init__(self, schema_path, additional_root_element=None):
11 self.schema_path = schema_path
12 self.additional_root_element = additional_root_element
13
14 def raiseValidationError(self, field_data, error_log):
15 display_errors = []
16 lines = field_data.split('\n')
17 for error in error_log:
18 # Scrape the lxml error messages to reword them more nicely.
19 m = re.search(r'Opening and ending tag mismatch: (.+?) line (\d+?) and (.+?)', error.message)
20 if m:
21 display_errors.append(_('Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "%(start)s".)') % \
22 {'tag':m.group(1).replace('/', ''), 'line':m.group(2), 'start':lines[int(m.group(2)) - 1][:30]})
23 continue
24 m = re.search(r'Did not expect text in element (.+?) content', error.message)
25 if m:
26 display_errors.append(_('Some text starting on line %(line)s is not allowed in that context. (Line starts with "%(start)s".)') % \
27 {'line':error.line, 'start':lines[int(error.line) - 1][:30]})
28 continue
29 m = re.search(r'Invalid attribute (.+?) for element (.+?)', error.message)
30 if m:
31 display_errors.append(_('"%(attr)s" on line %(line)s is an invalid attribute. (Line starts with "%(start)s".)') % \
32 {'attr':m.group(1), 'line':error.line, 'start':lines[int(error.line) - 1][:30]})
33 continue
34 m = re.search(r'Did not expect element (.+?) there', error.message)
35 if m:
36 display_errors.append(_('"<%(tag)s>" on line %(line)s is an invalid tag. (Line starts with "%(start)s".)') % \
37 {'tag':m.group(1), 'line':error.line, 'start':lines[int(error.line) - 1][:30]})
38 continue
39 m = re.search(r'Element (.+?) failed to validate attributes', error.message)
40 if m:
41 display_errors.append(_('A tag on line %(line)s is missing one or more required attributes. (Line starts with "%(start)s".)') % \
42 {'line':error.line, 'start':lines[int(error.line) - 1][:30]})
43 continue
44 m = re.search(r'Invalid attribute (.+?) for element (.+?)', error.message)
45 if m:
46 display_errors.append(_('The "%(attr)s" attribute on line %(line)s has an invalid value. (Line starts with "%(start)s".)') % \
47 {'attr':m.group(1), 'line':error.line, 'start':lines[int(error.line) - 1][:30]})
48 continue
49 # Failing all those checks, use the default error message.
50 display_errors.append('Line %s: %s [%s]' % (error.line, error.message, error.level_name))
51 raise ValidationError, display_errors
52
53 def __call__(self, field_data, all_data):
54 self.errors = []
55 if self.additional_root_element:
56 field_data = '<%(are)s>%(data)s\n</%(are)s>' % {
57 'are': self.additional_root_element,
58 'data': field_data
59 }
60
61 etree.clearErrorLog()
62 try:
63 doc = etree.parse(StringIO(field_data))
64 except etree.XMLSyntaxError, e:
65 self.raiseValidationError(field_data, e.error_log)
66 etree.clearErrorLog()
67 try:
68 rng_doc = etree.parse(self.schema_path)
69 except etree.XMLSyntaxError, e:
70 self.raiseValidationError(field_data, e.error_log)
71 rng = etree.RelaxNG(rng_doc)
72 if not rng(doc):
73 self.raiseValidationError(field_data, rng.error_log)
74
Back to Top