Ticket #3094: validators.2.py

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

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