Upload Tizen:Base source
[toolchains/python-lxml.git] / src / lxml / xmlschema.pxi
1 #  support for XMLSchema validation
2 cimport xmlschema
3
4 class XMLSchemaError(LxmlError):
5     u"""Base class of all XML Schema errors
6     """
7     pass
8
9 class XMLSchemaParseError(XMLSchemaError):
10     u"""Error while parsing an XML document as XML Schema.
11     """
12     pass
13
14 class XMLSchemaValidateError(XMLSchemaError):
15     u"""Error while validating an XML document with an XML Schema.
16     """
17     pass
18
19 ################################################################################
20 # XMLSchema
21
22 cdef XPath _check_for_default_attributes = XPath(
23     u"boolean(//xs:attribute[@default or @fixed][1])",
24     namespaces={u'xs': u'http://www.w3.org/2001/XMLSchema'})
25
26 cdef class XMLSchema(_Validator):
27     u"""XMLSchema(self, etree=None, file=None)
28     Turn a document into an XML Schema validator.
29
30     Either pass a schema as Element or ElementTree, or pass a file or
31     filename through the ``file`` keyword argument.
32
33     Passing the ``attribute_defaults`` boolean option will make the
34     schema insert default/fixed attributes into validated documents.
35     """
36     cdef xmlschema.xmlSchema* _c_schema
37     cdef bint _has_default_attributes
38     cdef bint _add_attribute_defaults
39
40     def __init__(self, etree=None, *, file=None, attribute_defaults=False):
41         cdef _Document doc
42         cdef _Element root_node
43         cdef xmlDoc* fake_c_doc
44         cdef xmlNode* c_node
45         cdef char* c_href
46         cdef xmlschema.xmlSchemaParserCtxt* parser_ctxt
47
48         self._has_default_attributes = True # play safe
49         self._add_attribute_defaults = attribute_defaults
50         self._c_schema = NULL
51         _Validator.__init__(self)
52         fake_c_doc = NULL
53         if etree is not None:
54             doc = _documentOrRaise(etree)
55             root_node = _rootNodeOrRaise(etree)
56
57             # work around for libxml2 bug if document is not XML schema at all
58             if _LIBXML_VERSION_INT < 20624:
59                 c_node = root_node._c_node
60                 c_href = _getNs(c_node)
61                 if c_href is NULL or \
62                        cstd.strcmp(c_href, 'http://www.w3.org/2001/XMLSchema') != 0:
63                     raise XMLSchemaParseError, u"Document is not XML Schema"
64
65             fake_c_doc = _fakeRootDoc(doc._c_doc, root_node._c_node)
66             self._error_log.connect()
67             parser_ctxt = xmlschema.xmlSchemaNewDocParserCtxt(fake_c_doc)
68         elif file is not None:
69             if _isString(file):
70                 doc = None
71                 filename = _encodeFilename(file)
72                 self._error_log.connect()
73                 parser_ctxt = xmlschema.xmlSchemaNewParserCtxt(_cstr(filename))
74             else:
75                 doc = _parseDocument(file, None, None)
76                 self._error_log.connect()
77                 parser_ctxt = xmlschema.xmlSchemaNewDocParserCtxt(doc._c_doc)
78         else:
79             raise XMLSchemaParseError, u"No tree or file given"
80
81         if parser_ctxt is not NULL:
82             if doc is None:
83                 with nogil:
84                     self._c_schema = xmlschema.xmlSchemaParse(parser_ctxt)
85             else:
86                 # calling xmlSchemaParse on a schema with imports or
87                 # includes will cause libxml2 to create an internal
88                 # context for parsing, so push an implied context to route
89                 # resolve requests to the document's parser
90                 __GLOBAL_PARSER_CONTEXT.pushImpliedContextFromParser(doc._parser)
91                 self._c_schema = xmlschema.xmlSchemaParse(parser_ctxt)
92                 __GLOBAL_PARSER_CONTEXT.popImpliedContext()
93
94             if _LIBXML_VERSION_INT >= 20624:
95                 xmlschema.xmlSchemaFreeParserCtxt(parser_ctxt)
96
97         self._error_log.disconnect()
98
99         if fake_c_doc is not NULL:
100             _destroyFakeDoc(doc._c_doc, fake_c_doc)
101
102         if self._c_schema is NULL:
103             raise XMLSchemaParseError(
104                 self._error_log._buildExceptionMessage(
105                     u"Document is not valid XML Schema"),
106                 self._error_log)
107
108         if doc is not None:
109             self._has_default_attributes = _check_for_default_attributes(doc)
110         self._add_attribute_defaults = attribute_defaults and \
111                                        self._has_default_attributes
112
113     def __dealloc__(self):
114         xmlschema.xmlSchemaFree(self._c_schema)
115
116     def __call__(self, etree):
117         u"""__call__(self, etree)
118
119         Validate doc using XML Schema.
120
121         Returns true if document is valid, false if not.
122         """
123         cdef xmlschema.xmlSchemaValidCtxt* valid_ctxt
124         cdef _Document doc
125         cdef _Element root_node
126         cdef xmlDoc* c_doc
127         cdef int ret
128
129         doc = _documentOrRaise(etree)
130         root_node = _rootNodeOrRaise(etree)
131
132         self._error_log.connect()
133         valid_ctxt = xmlschema.xmlSchemaNewValidCtxt(self._c_schema)
134         if valid_ctxt is NULL:
135             self._error_log.disconnect()
136             return python.PyErr_NoMemory()
137
138         if self._add_attribute_defaults:
139             xmlschema.xmlSchemaSetValidOptions(
140                 valid_ctxt, xmlschema.XML_SCHEMA_VAL_VC_I_CREATE)
141
142         c_doc = _fakeRootDoc(doc._c_doc, root_node._c_node)
143         with nogil:
144             ret = xmlschema.xmlSchemaValidateDoc(valid_ctxt, c_doc)
145         _destroyFakeDoc(doc._c_doc, c_doc)
146
147         xmlschema.xmlSchemaFreeValidCtxt(valid_ctxt)
148
149         self._error_log.disconnect()
150         if ret == -1:
151             raise XMLSchemaValidateError(
152                 u"Internal error in XML Schema validation.",
153                 self._error_log)
154         if ret == 0:
155             return True
156         else:
157             return False
158
159     cdef _ParserSchemaValidationContext _newSaxValidator(
160             self, bint add_default_attributes):
161         cdef _ParserSchemaValidationContext context
162         context = NEW_SCHEMA_CONTEXT(_ParserSchemaValidationContext)
163         context._schema = self
164         context._valid_ctxt = NULL
165         context._sax_plug = NULL
166         context._add_default_attributes = (self._has_default_attributes and (
167             add_default_attributes or self._add_attribute_defaults))
168         return context
169
170 cdef class _ParserSchemaValidationContext:
171     cdef XMLSchema _schema
172     cdef xmlschema.xmlSchemaValidCtxt* _valid_ctxt
173     cdef xmlschema.xmlSchemaSAXPlugStruct* _sax_plug
174     cdef bint _add_default_attributes
175
176     def __dealloc__(self):
177         self.disconnect()
178         if self._valid_ctxt:
179             xmlschema.xmlSchemaFreeValidCtxt(self._valid_ctxt)
180
181     cdef _ParserSchemaValidationContext copy(self):
182         return self._schema._newSaxValidator(
183             self._add_default_attributes)
184
185     cdef void inject_default_attributes(self, xmlDoc* c_doc):
186         # we currently need to insert default attributes manually
187         # after parsing, as libxml2 does not support this at parse
188         # time
189         if self._add_default_attributes:
190             with nogil:
191                 xmlschema.xmlSchemaValidateDoc(self._valid_ctxt, c_doc)
192
193     cdef int connect(self, xmlparser.xmlParserCtxt* c_ctxt) except -1:
194         if self._valid_ctxt is NULL:
195             self._valid_ctxt = xmlschema.xmlSchemaNewValidCtxt(
196                 self._schema._c_schema)
197             if self._valid_ctxt is NULL:
198                 return python.PyErr_NoMemory()
199             if self._add_default_attributes:
200                 xmlschema.xmlSchemaSetValidOptions(
201                     self._valid_ctxt,
202                     xmlschema.XML_SCHEMA_VAL_VC_I_CREATE)
203         self._sax_plug = xmlschema.xmlSchemaSAXPlug(
204             self._valid_ctxt, &c_ctxt.sax, &c_ctxt.userData)
205
206     cdef void disconnect(self):
207         if self._sax_plug is not NULL:
208             xmlschema.xmlSchemaSAXUnplug(self._sax_plug)
209             self._sax_plug = NULL
210
211     cdef bint isvalid(self):
212         if self._valid_ctxt is NULL:
213             return 1 # valid
214         return xmlschema.xmlSchemaIsValid(self._valid_ctxt)
215
216 cdef extern from "etree_defs.h":
217     # macro call to 't->tp_new()' for fast instantiation
218     cdef _ParserSchemaValidationContext NEW_SCHEMA_CONTEXT "PY_NEW" (object t)