Django

Code

Ticket #3094: validators.2.py

File validators.2.py, 3.3 kB (added by David Danier <goliath.mailinglist@gmx.de>, 2 years ago)

validators.py including RelaxNG-class

Line 
1 from django.core.validators import ValidationError
2 from lxml import etree
3 from StringIO import StringIO
4 from django.utils.translation import gettext_lazy as _
5 import re
6
7 class 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)