lxml 5.3.0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. lxml/ElementInclude.py +244 -0
  2. lxml/__init__.py +22 -0
  3. lxml/_elementpath.cpython-313-x86_64-linux-gnu.so +0 -0
  4. lxml/_elementpath.py +341 -0
  5. lxml/apihelpers.pxi +1793 -0
  6. lxml/builder.cpython-313-x86_64-linux-gnu.so +0 -0
  7. lxml/builder.py +232 -0
  8. lxml/classlookup.pxi +580 -0
  9. lxml/cleanup.pxi +215 -0
  10. lxml/cssselect.py +101 -0
  11. lxml/debug.pxi +90 -0
  12. lxml/docloader.pxi +178 -0
  13. lxml/doctestcompare.py +488 -0
  14. lxml/dtd.pxi +478 -0
  15. lxml/etree.cpython-313-x86_64-linux-gnu.so +0 -0
  16. lxml/etree.h +248 -0
  17. lxml/etree.pyx +3731 -0
  18. lxml/etree_api.h +195 -0
  19. lxml/extensions.pxi +833 -0
  20. lxml/html/ElementSoup.py +10 -0
  21. lxml/html/__init__.py +1923 -0
  22. lxml/html/_diffcommand.py +86 -0
  23. lxml/html/_html5builder.py +100 -0
  24. lxml/html/_setmixin.py +56 -0
  25. lxml/html/builder.py +133 -0
  26. lxml/html/clean.py +21 -0
  27. lxml/html/defs.py +135 -0
  28. lxml/html/diff.cpython-313-x86_64-linux-gnu.so +0 -0
  29. lxml/html/diff.py +878 -0
  30. lxml/html/formfill.py +299 -0
  31. lxml/html/html5parser.py +260 -0
  32. lxml/html/soupparser.py +314 -0
  33. lxml/html/usedoctest.py +13 -0
  34. lxml/includes/__init__.pxd +0 -0
  35. lxml/includes/__init__.py +0 -0
  36. lxml/includes/c14n.pxd +25 -0
  37. lxml/includes/config.pxd +3 -0
  38. lxml/includes/dtdvalid.pxd +18 -0
  39. lxml/includes/etree_defs.h +379 -0
  40. lxml/includes/etreepublic.pxd +237 -0
  41. lxml/includes/extlibs/__init__.py +0 -0
  42. lxml/includes/extlibs/libcharset.h +45 -0
  43. lxml/includes/extlibs/localcharset.h +137 -0
  44. lxml/includes/extlibs/zconf.h +543 -0
  45. lxml/includes/extlibs/zlib.h +1938 -0
  46. lxml/includes/htmlparser.pxd +56 -0
  47. lxml/includes/libexslt/__init__.py +0 -0
  48. lxml/includes/libexslt/exslt.h +108 -0
  49. lxml/includes/libexslt/exsltconfig.h +70 -0
  50. lxml/includes/libexslt/exsltexports.h +63 -0
  51. lxml/includes/libxml/HTMLparser.h +343 -0
  52. lxml/includes/libxml/HTMLtree.h +147 -0
  53. lxml/includes/libxml/SAX.h +202 -0
  54. lxml/includes/libxml/SAX2.h +171 -0
  55. lxml/includes/libxml/__init__.py +0 -0
  56. lxml/includes/libxml/c14n.h +126 -0
  57. lxml/includes/libxml/catalog.h +182 -0
  58. lxml/includes/libxml/chvalid.h +230 -0
  59. lxml/includes/libxml/debugXML.h +217 -0
  60. lxml/includes/libxml/dict.h +82 -0
  61. lxml/includes/libxml/encoding.h +235 -0
  62. lxml/includes/libxml/entities.h +155 -0
  63. lxml/includes/libxml/globals.h +41 -0
  64. lxml/includes/libxml/hash.h +232 -0
  65. lxml/includes/libxml/list.h +137 -0
  66. lxml/includes/libxml/nanoftp.h +186 -0
  67. lxml/includes/libxml/nanohttp.h +81 -0
  68. lxml/includes/libxml/parser.h +1384 -0
  69. lxml/includes/libxml/parserInternals.h +663 -0
  70. lxml/includes/libxml/relaxng.h +219 -0
  71. lxml/includes/libxml/schemasInternals.h +959 -0
  72. lxml/includes/libxml/schematron.h +143 -0
  73. lxml/includes/libxml/threads.h +87 -0
  74. lxml/includes/libxml/tree.h +1362 -0
  75. lxml/includes/libxml/uri.h +95 -0
  76. lxml/includes/libxml/valid.h +450 -0
  77. lxml/includes/libxml/xinclude.h +129 -0
  78. lxml/includes/libxml/xlink.h +189 -0
  79. lxml/includes/libxml/xmlIO.h +421 -0
  80. lxml/includes/libxml/xmlautomata.h +146 -0
  81. lxml/includes/libxml/xmlerror.h +948 -0
  82. lxml/includes/libxml/xmlexports.h +50 -0
  83. lxml/includes/libxml/xmlmemory.h +225 -0
  84. lxml/includes/libxml/xmlmodule.h +57 -0
  85. lxml/includes/libxml/xmlreader.h +434 -0
  86. lxml/includes/libxml/xmlregexp.h +215 -0
  87. lxml/includes/libxml/xmlsave.h +97 -0
  88. lxml/includes/libxml/xmlschemas.h +249 -0
  89. lxml/includes/libxml/xmlschemastypes.h +152 -0
  90. lxml/includes/libxml/xmlstring.h +140 -0
  91. lxml/includes/libxml/xmlunicode.h +202 -0
  92. lxml/includes/libxml/xmlversion.h +511 -0
  93. lxml/includes/libxml/xmlwriter.h +488 -0
  94. lxml/includes/libxml/xpath.h +575 -0
  95. lxml/includes/libxml/xpathInternals.h +633 -0
  96. lxml/includes/libxml/xpointer.h +138 -0
  97. lxml/includes/libxslt/__init__.py +0 -0
  98. lxml/includes/libxslt/attributes.h +39 -0
  99. lxml/includes/libxslt/documents.h +93 -0
  100. lxml/includes/libxslt/extensions.h +262 -0
  101. lxml/includes/libxslt/extra.h +72 -0
  102. lxml/includes/libxslt/functions.h +78 -0
  103. lxml/includes/libxslt/imports.h +75 -0
  104. lxml/includes/libxslt/keys.h +53 -0
  105. lxml/includes/libxslt/namespaces.h +68 -0
  106. lxml/includes/libxslt/numbersInternals.h +73 -0
  107. lxml/includes/libxslt/pattern.h +84 -0
  108. lxml/includes/libxslt/preproc.h +43 -0
  109. lxml/includes/libxslt/security.h +104 -0
  110. lxml/includes/libxslt/templates.h +77 -0
  111. lxml/includes/libxslt/transform.h +207 -0
  112. lxml/includes/libxslt/variables.h +118 -0
  113. lxml/includes/libxslt/xslt.h +110 -0
  114. lxml/includes/libxslt/xsltInternals.h +1995 -0
  115. lxml/includes/libxslt/xsltconfig.h +146 -0
  116. lxml/includes/libxslt/xsltexports.h +64 -0
  117. lxml/includes/libxslt/xsltlocale.h +44 -0
  118. lxml/includes/libxslt/xsltutils.h +343 -0
  119. lxml/includes/lxml-version.h +3 -0
  120. lxml/includes/relaxng.pxd +64 -0
  121. lxml/includes/schematron.pxd +34 -0
  122. lxml/includes/tree.pxd +494 -0
  123. lxml/includes/uri.pxd +5 -0
  124. lxml/includes/xinclude.pxd +22 -0
  125. lxml/includes/xmlerror.pxd +852 -0
  126. lxml/includes/xmlparser.pxd +265 -0
  127. lxml/includes/xmlschema.pxd +35 -0
  128. lxml/includes/xpath.pxd +136 -0
  129. lxml/includes/xslt.pxd +190 -0
  130. lxml/isoschematron/__init__.py +348 -0
  131. lxml/isoschematron/resources/rng/iso-schematron.rng +709 -0
  132. lxml/isoschematron/resources/xsl/RNG2Schtrn.xsl +75 -0
  133. lxml/isoschematron/resources/xsl/XSD2Schtrn.xsl +77 -0
  134. lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_abstract_expand.xsl +313 -0
  135. lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_dsdl_include.xsl +1160 -0
  136. lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_schematron_message.xsl +55 -0
  137. lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_schematron_skeleton_for_xslt1.xsl +1796 -0
  138. lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_svrl_for_xslt1.xsl +588 -0
  139. lxml/isoschematron/resources/xsl/iso-schematron-xslt1/readme.txt +84 -0
  140. lxml/iterparse.pxi +438 -0
  141. lxml/lxml.etree.h +248 -0
  142. lxml/lxml.etree_api.h +195 -0
  143. lxml/nsclasses.pxi +281 -0
  144. lxml/objectify.cpython-313-x86_64-linux-gnu.so +0 -0
  145. lxml/objectify.pyx +2145 -0
  146. lxml/objectpath.pxi +332 -0
  147. lxml/parser.pxi +2000 -0
  148. lxml/parsertarget.pxi +180 -0
  149. lxml/proxy.pxi +619 -0
  150. lxml/public-api.pxi +178 -0
  151. lxml/pyclasslookup.py +3 -0
  152. lxml/readonlytree.pxi +565 -0
  153. lxml/relaxng.pxi +165 -0
  154. lxml/sax.cpython-313-x86_64-linux-gnu.so +0 -0
  155. lxml/sax.py +275 -0
  156. lxml/saxparser.pxi +875 -0
  157. lxml/schematron.pxi +168 -0
  158. lxml/serializer.pxi +1781 -0
  159. lxml/usedoctest.py +13 -0
  160. lxml/xinclude.pxi +67 -0
  161. lxml/xmlerror.pxi +1654 -0
  162. lxml/xmlid.pxi +179 -0
  163. lxml/xmlschema.pxi +215 -0
  164. lxml/xpath.pxi +487 -0
  165. lxml/xslt.pxi +950 -0
  166. lxml/xsltext.pxi +242 -0
  167. lxml-5.3.0.dist-info/LICENSE.txt +29 -0
  168. lxml-5.3.0.dist-info/LICENSES.txt +29 -0
  169. lxml-5.3.0.dist-info/METADATA +103 -0
  170. lxml-5.3.0.dist-info/RECORD +172 -0
  171. lxml-5.3.0.dist-info/WHEEL +6 -0
  172. lxml-5.3.0.dist-info/top_level.txt +1 -0
lxml/dtd.pxi ADDED
@@ -0,0 +1,478 @@
1
+ # support for DTD validation
2
+ from lxml.includes cimport dtdvalid
3
+
4
+ cdef class DTDError(LxmlError):
5
+ """Base class for DTD errors.
6
+ """
7
+
8
+ cdef class DTDParseError(DTDError):
9
+ """Error while parsing a DTD.
10
+ """
11
+
12
+ cdef class DTDValidateError(DTDError):
13
+ """Error while validating an XML document with a DTD.
14
+ """
15
+
16
+
17
+ cdef inline int _assertValidDTDNode(node, void *c_node) except -1:
18
+ assert c_node is not NULL, "invalid DTD proxy at %s" % id(node)
19
+
20
+
21
+ @cython.final
22
+ @cython.internal
23
+ @cython.freelist(8)
24
+ cdef class _DTDElementContentDecl:
25
+ cdef DTD _dtd
26
+ cdef tree.xmlElementContent* _c_node
27
+
28
+ def __repr__(self):
29
+ return "<%s.%s object name=%r type=%r occur=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, self.type, self.occur, id(self))
30
+
31
+ @property
32
+ def name(self):
33
+ _assertValidDTDNode(self, self._c_node)
34
+ return funicodeOrNone(self._c_node.name)
35
+
36
+ @property
37
+ def type(self):
38
+ _assertValidDTDNode(self, self._c_node)
39
+ cdef int type = self._c_node.type
40
+ if type == tree.XML_ELEMENT_CONTENT_PCDATA:
41
+ return "pcdata"
42
+ elif type == tree.XML_ELEMENT_CONTENT_ELEMENT:
43
+ return "element"
44
+ elif type == tree.XML_ELEMENT_CONTENT_SEQ:
45
+ return "seq"
46
+ elif type == tree.XML_ELEMENT_CONTENT_OR:
47
+ return "or"
48
+ else:
49
+ return None
50
+
51
+ @property
52
+ def occur(self):
53
+ _assertValidDTDNode(self, self._c_node)
54
+ cdef int occur = self._c_node.ocur
55
+ if occur == tree.XML_ELEMENT_CONTENT_ONCE:
56
+ return "once"
57
+ elif occur == tree.XML_ELEMENT_CONTENT_OPT:
58
+ return "opt"
59
+ elif occur == tree.XML_ELEMENT_CONTENT_MULT:
60
+ return "mult"
61
+ elif occur == tree.XML_ELEMENT_CONTENT_PLUS:
62
+ return "plus"
63
+ else:
64
+ return None
65
+
66
+ @property
67
+ def left(self):
68
+ _assertValidDTDNode(self, self._c_node)
69
+ c1 = self._c_node.c1
70
+ if c1:
71
+ node = <_DTDElementContentDecl>_DTDElementContentDecl.__new__(_DTDElementContentDecl)
72
+ node._dtd = self._dtd
73
+ node._c_node = <tree.xmlElementContent*>c1
74
+ return node
75
+ else:
76
+ return None
77
+
78
+ @property
79
+ def right(self):
80
+ _assertValidDTDNode(self, self._c_node)
81
+ c2 = self._c_node.c2
82
+ if c2:
83
+ node = <_DTDElementContentDecl>_DTDElementContentDecl.__new__(_DTDElementContentDecl)
84
+ node._dtd = self._dtd
85
+ node._c_node = <tree.xmlElementContent*>c2
86
+ return node
87
+ else:
88
+ return None
89
+
90
+
91
+ @cython.final
92
+ @cython.internal
93
+ @cython.freelist(8)
94
+ cdef class _DTDAttributeDecl:
95
+ cdef DTD _dtd
96
+ cdef tree.xmlAttribute* _c_node
97
+
98
+ def __repr__(self):
99
+ return "<%s.%s object name=%r elemname=%r prefix=%r type=%r default=%r default_value=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, self.elemname, self.prefix, self.type, self.default, self.default_value, id(self))
100
+
101
+ @property
102
+ def name(self):
103
+ _assertValidDTDNode(self, self._c_node)
104
+ return funicodeOrNone(self._c_node.name)
105
+
106
+ @property
107
+ def elemname(self):
108
+ _assertValidDTDNode(self, self._c_node)
109
+ return funicodeOrNone(self._c_node.elem)
110
+
111
+ @property
112
+ def prefix(self):
113
+ _assertValidDTDNode(self, self._c_node)
114
+ return funicodeOrNone(self._c_node.prefix)
115
+
116
+ @property
117
+ def type(self):
118
+ _assertValidDTDNode(self, self._c_node)
119
+ cdef int type = self._c_node.atype
120
+ if type == tree.XML_ATTRIBUTE_CDATA:
121
+ return "cdata"
122
+ elif type == tree.XML_ATTRIBUTE_ID:
123
+ return "id"
124
+ elif type == tree.XML_ATTRIBUTE_IDREF:
125
+ return "idref"
126
+ elif type == tree.XML_ATTRIBUTE_IDREFS:
127
+ return "idrefs"
128
+ elif type == tree.XML_ATTRIBUTE_ENTITY:
129
+ return "entity"
130
+ elif type == tree.XML_ATTRIBUTE_ENTITIES:
131
+ return "entities"
132
+ elif type == tree.XML_ATTRIBUTE_NMTOKEN:
133
+ return "nmtoken"
134
+ elif type == tree.XML_ATTRIBUTE_NMTOKENS:
135
+ return "nmtokens"
136
+ elif type == tree.XML_ATTRIBUTE_ENUMERATION:
137
+ return "enumeration"
138
+ elif type == tree.XML_ATTRIBUTE_NOTATION:
139
+ return "notation"
140
+ else:
141
+ return None
142
+
143
+ @property
144
+ def default(self):
145
+ _assertValidDTDNode(self, self._c_node)
146
+ cdef int default = self._c_node.def_
147
+ if default == tree.XML_ATTRIBUTE_NONE:
148
+ return "none"
149
+ elif default == tree.XML_ATTRIBUTE_REQUIRED:
150
+ return "required"
151
+ elif default == tree.XML_ATTRIBUTE_IMPLIED:
152
+ return "implied"
153
+ elif default == tree.XML_ATTRIBUTE_FIXED:
154
+ return "fixed"
155
+ else:
156
+ return None
157
+
158
+ @property
159
+ def default_value(self):
160
+ _assertValidDTDNode(self, self._c_node)
161
+ return funicodeOrNone(self._c_node.defaultValue)
162
+
163
+ def itervalues(self):
164
+ _assertValidDTDNode(self, self._c_node)
165
+ cdef tree.xmlEnumeration *c_node = self._c_node.tree
166
+ while c_node is not NULL:
167
+ yield funicode(c_node.name)
168
+ c_node = c_node.next
169
+
170
+ def values(self):
171
+ return list(self.itervalues())
172
+
173
+
174
+ @cython.final
175
+ @cython.internal
176
+ @cython.freelist(8)
177
+ cdef class _DTDElementDecl:
178
+ cdef DTD _dtd
179
+ cdef tree.xmlElement* _c_node
180
+
181
+ def __repr__(self):
182
+ return "<%s.%s object name=%r prefix=%r type=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, self.prefix, self.type, id(self))
183
+
184
+ @property
185
+ def name(self):
186
+ _assertValidDTDNode(self, self._c_node)
187
+ return funicodeOrNone(self._c_node.name)
188
+
189
+ @property
190
+ def prefix(self):
191
+ _assertValidDTDNode(self, self._c_node)
192
+ return funicodeOrNone(self._c_node.prefix)
193
+
194
+ @property
195
+ def type(self):
196
+ _assertValidDTDNode(self, self._c_node)
197
+ cdef int type = self._c_node.etype
198
+ if type == tree.XML_ELEMENT_TYPE_UNDEFINED:
199
+ return "undefined"
200
+ elif type == tree.XML_ELEMENT_TYPE_EMPTY:
201
+ return "empty"
202
+ elif type == tree.XML_ELEMENT_TYPE_ANY:
203
+ return "any"
204
+ elif type == tree.XML_ELEMENT_TYPE_MIXED:
205
+ return "mixed"
206
+ elif type == tree.XML_ELEMENT_TYPE_ELEMENT:
207
+ return "element"
208
+ else:
209
+ return None
210
+
211
+ @property
212
+ def content(self):
213
+ _assertValidDTDNode(self, self._c_node)
214
+ cdef tree.xmlElementContent *content = self._c_node.content
215
+ if content:
216
+ node = <_DTDElementContentDecl>_DTDElementContentDecl.__new__(_DTDElementContentDecl)
217
+ node._dtd = self._dtd
218
+ node._c_node = content
219
+ return node
220
+ else:
221
+ return None
222
+
223
+ def iterattributes(self):
224
+ _assertValidDTDNode(self, self._c_node)
225
+ cdef tree.xmlAttribute *c_node = self._c_node.attributes
226
+ while c_node:
227
+ node = <_DTDAttributeDecl>_DTDAttributeDecl.__new__(_DTDAttributeDecl)
228
+ node._dtd = self._dtd
229
+ node._c_node = c_node
230
+ yield node
231
+ c_node = c_node.nexth
232
+
233
+ def attributes(self):
234
+ return list(self.iterattributes())
235
+
236
+
237
+ @cython.final
238
+ @cython.internal
239
+ @cython.freelist(8)
240
+ cdef class _DTDEntityDecl:
241
+ cdef DTD _dtd
242
+ cdef tree.xmlEntity* _c_node
243
+ def __repr__(self):
244
+ return "<%s.%s object name=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, id(self))
245
+
246
+ @property
247
+ def name(self):
248
+ _assertValidDTDNode(self, self._c_node)
249
+ return funicodeOrNone(self._c_node.name)
250
+
251
+ @property
252
+ def orig(self):
253
+ _assertValidDTDNode(self, self._c_node)
254
+ return funicodeOrNone(self._c_node.orig)
255
+
256
+ @property
257
+ def content(self):
258
+ _assertValidDTDNode(self, self._c_node)
259
+ return funicodeOrNone(self._c_node.content)
260
+
261
+ @property
262
+ def system_url(self):
263
+ _assertValidDTDNode(self, self._c_node)
264
+ return funicodeOrNone(self._c_node.SystemID)
265
+
266
+
267
+ ################################################################################
268
+ # DTD
269
+
270
+ cdef class DTD(_Validator):
271
+ """DTD(self, file=None, external_id=None)
272
+ A DTD validator.
273
+
274
+ Can load from filesystem directly given a filename or file-like object.
275
+ Alternatively, pass the keyword parameter ``external_id`` to load from a
276
+ catalog.
277
+ """
278
+ cdef tree.xmlDtd* _c_dtd
279
+ def __init__(self, file=None, *, external_id=None):
280
+ _Validator.__init__(self)
281
+ if file is not None:
282
+ file = _getFSPathOrObject(file)
283
+ if _isString(file):
284
+ file = _encodeFilename(file)
285
+ with self._error_log:
286
+ orig_loader = _register_document_loader()
287
+ self._c_dtd = xmlparser.xmlParseDTD(NULL, _xcstr(file))
288
+ _reset_document_loader(orig_loader)
289
+ elif hasattr(file, 'read'):
290
+ orig_loader = _register_document_loader()
291
+ self._c_dtd = _parseDtdFromFilelike(file)
292
+ _reset_document_loader(orig_loader)
293
+ else:
294
+ raise DTDParseError, "file must be a filename, file-like or path-like object"
295
+ elif external_id is not None:
296
+ with self._error_log:
297
+ orig_loader = _register_document_loader()
298
+ self._c_dtd = xmlparser.xmlParseDTD(<const_xmlChar*>external_id, NULL)
299
+ _reset_document_loader(orig_loader)
300
+ else:
301
+ raise DTDParseError, "either filename or external ID required"
302
+
303
+ if self._c_dtd is NULL:
304
+ raise DTDParseError(
305
+ self._error_log._buildExceptionMessage("error parsing DTD"),
306
+ self._error_log)
307
+
308
+ @property
309
+ def name(self):
310
+ if self._c_dtd is NULL:
311
+ return None
312
+ return funicodeOrNone(self._c_dtd.name)
313
+
314
+ @property
315
+ def external_id(self):
316
+ if self._c_dtd is NULL:
317
+ return None
318
+ return funicodeOrNone(self._c_dtd.ExternalID)
319
+
320
+ @property
321
+ def system_url(self):
322
+ if self._c_dtd is NULL:
323
+ return None
324
+ return funicodeOrNone(self._c_dtd.SystemID)
325
+
326
+ def iterelements(self):
327
+ cdef tree.xmlNode *c_node = self._c_dtd.children if self._c_dtd is not NULL else NULL
328
+ while c_node is not NULL:
329
+ if c_node.type == tree.XML_ELEMENT_DECL:
330
+ node = _DTDElementDecl()
331
+ node._dtd = self
332
+ node._c_node = <tree.xmlElement*>c_node
333
+ yield node
334
+ c_node = c_node.next
335
+
336
+ def elements(self):
337
+ return list(self.iterelements())
338
+
339
+ def iterentities(self):
340
+ cdef tree.xmlNode *c_node = self._c_dtd.children if self._c_dtd is not NULL else NULL
341
+ while c_node is not NULL:
342
+ if c_node.type == tree.XML_ENTITY_DECL:
343
+ node = _DTDEntityDecl()
344
+ node._dtd = self
345
+ node._c_node = <tree.xmlEntity*>c_node
346
+ yield node
347
+ c_node = c_node.next
348
+
349
+ def entities(self):
350
+ return list(self.iterentities())
351
+
352
+ def __dealloc__(self):
353
+ tree.xmlFreeDtd(self._c_dtd)
354
+
355
+ def __call__(self, etree):
356
+ """__call__(self, etree)
357
+
358
+ Validate doc using the DTD.
359
+
360
+ Returns true if the document is valid, false if not.
361
+ """
362
+ cdef _Document doc
363
+ cdef _Element root_node
364
+ cdef xmlDoc* c_doc
365
+ cdef dtdvalid.xmlValidCtxt* valid_ctxt
366
+ cdef int ret = -1
367
+
368
+ assert self._c_dtd is not NULL, "DTD not initialised"
369
+ doc = _documentOrRaise(etree)
370
+ root_node = _rootNodeOrRaise(etree)
371
+
372
+ valid_ctxt = dtdvalid.xmlNewValidCtxt()
373
+ if valid_ctxt is NULL:
374
+ raise DTDError("Failed to create validation context")
375
+
376
+ # work around error reporting bug in libxml2 <= 2.9.1 (and later?)
377
+ # https://bugzilla.gnome.org/show_bug.cgi?id=724903
378
+ valid_ctxt.error = <dtdvalid.xmlValidityErrorFunc>_nullGenericErrorFunc
379
+ valid_ctxt.userData = NULL
380
+
381
+ try:
382
+ with self._error_log:
383
+ c_doc = _fakeRootDoc(doc._c_doc, root_node._c_node)
384
+ ret = dtdvalid.xmlValidateDtd(valid_ctxt, c_doc, self._c_dtd)
385
+ _destroyFakeDoc(doc._c_doc, c_doc)
386
+ finally:
387
+ dtdvalid.xmlFreeValidCtxt(valid_ctxt)
388
+
389
+ if ret == -1:
390
+ raise DTDValidateError("Internal error in DTD validation",
391
+ self._error_log)
392
+ return ret == 1
393
+
394
+
395
+ cdef tree.xmlDtd* _parseDtdFromFilelike(file) except NULL:
396
+ cdef _ExceptionContext exc_context
397
+ cdef _FileReaderContext dtd_parser
398
+ cdef _ErrorLog error_log
399
+ cdef tree.xmlDtd* c_dtd = NULL
400
+ exc_context = _ExceptionContext()
401
+ dtd_parser = _FileReaderContext(file, exc_context, None)
402
+ error_log = _ErrorLog()
403
+
404
+ with error_log:
405
+ c_dtd = dtd_parser._readDtd()
406
+
407
+ exc_context._raise_if_stored()
408
+ if c_dtd is NULL:
409
+ raise DTDParseError("error parsing DTD", error_log)
410
+ return c_dtd
411
+
412
+ cdef DTD _dtdFactory(tree.xmlDtd* c_dtd):
413
+ # do not run through DTD.__init__()!
414
+ cdef DTD dtd
415
+ if c_dtd is NULL:
416
+ return None
417
+ dtd = DTD.__new__(DTD)
418
+ dtd._c_dtd = _copyDtd(c_dtd)
419
+ _Validator.__init__(dtd)
420
+ return dtd
421
+
422
+
423
+ cdef tree.xmlDtd* _copyDtd(tree.xmlDtd* c_orig_dtd) except NULL:
424
+ """
425
+ Copy a DTD. libxml2 (currently) fails to set up the element->attributes
426
+ links when copying DTDs, so we have to rebuild them here.
427
+ """
428
+ c_dtd = tree.xmlCopyDtd(c_orig_dtd)
429
+ if not c_dtd:
430
+ raise MemoryError
431
+ cdef tree.xmlNode* c_node = c_dtd.children
432
+ while c_node:
433
+ if c_node.type == tree.XML_ATTRIBUTE_DECL:
434
+ _linkDtdAttribute(c_dtd, <tree.xmlAttribute*>c_node)
435
+ c_node = c_node.next
436
+ return c_dtd
437
+
438
+
439
+ cdef void _linkDtdAttribute(tree.xmlDtd* c_dtd, tree.xmlAttribute* c_attr) noexcept:
440
+ """
441
+ Create the link to the DTD attribute declaration from the corresponding
442
+ element declaration.
443
+ """
444
+ c_elem = dtdvalid.xmlGetDtdElementDesc(c_dtd, c_attr.elem)
445
+ if not c_elem:
446
+ # no such element? something is wrong with the DTD ...
447
+ return
448
+ c_pos = c_elem.attributes
449
+ if not c_pos:
450
+ c_elem.attributes = c_attr
451
+ c_attr.nexth = NULL
452
+ return
453
+ # libxml2 keeps namespace declarations first, and we need to make
454
+ # sure we don't re-insert attributes that are already there
455
+ if _isDtdNsDecl(c_attr):
456
+ if not _isDtdNsDecl(c_pos):
457
+ c_elem.attributes = c_attr
458
+ c_attr.nexth = c_pos
459
+ return
460
+ while c_pos != c_attr and c_pos.nexth and _isDtdNsDecl(c_pos.nexth):
461
+ c_pos = c_pos.nexth
462
+ else:
463
+ # append at end
464
+ while c_pos != c_attr and c_pos.nexth:
465
+ c_pos = c_pos.nexth
466
+ if c_pos == c_attr:
467
+ return
468
+ c_attr.nexth = c_pos.nexth
469
+ c_pos.nexth = c_attr
470
+
471
+
472
+ cdef bint _isDtdNsDecl(tree.xmlAttribute* c_attr) noexcept:
473
+ if cstring_h.strcmp(<const_char*>c_attr.name, "xmlns") == 0:
474
+ return True
475
+ if (c_attr.prefix is not NULL and
476
+ cstring_h.strcmp(<const_char*>c_attr.prefix, "xmlns") == 0):
477
+ return True
478
+ return False