1import libxml2mod 2import types 3import sys 4 5# The root of all libxml2 errors. 6class libxmlError(Exception): pass 7 8# Type of the wrapper class for the C objects wrappers 9def checkWrapper(obj): 10 try: 11 n = type(_obj).__name__ 12 if n != 'PyCObject' and n != 'PyCapsule': 13 return 1 14 except: 15 return 0 16 return 0 17 18# 19# id() is sometimes negative ... 20# 21def pos_id(o): 22 i = id(o) 23 if (i < 0): 24 return (sys.maxsize - i) 25 return i 26 27# 28# Errors raised by the wrappers when some tree handling failed. 29# 30class treeError(libxmlError): 31 def __init__(self, msg): 32 self.msg = msg 33 def __str__(self): 34 return self.msg 35 36class parserError(libxmlError): 37 def __init__(self, msg): 38 self.msg = msg 39 def __str__(self): 40 return self.msg 41 42class uriError(libxmlError): 43 def __init__(self, msg): 44 self.msg = msg 45 def __str__(self): 46 return self.msg 47 48class xpathError(libxmlError): 49 def __init__(self, msg): 50 self.msg = msg 51 def __str__(self): 52 return self.msg 53 54class ioWrapper: 55 def __init__(self, _obj): 56 self.__io = _obj 57 self._o = None 58 59 def io_close(self): 60 if self.__io == None: 61 return(-1) 62 self.__io.close() 63 self.__io = None 64 return(0) 65 66 def io_flush(self): 67 if self.__io == None: 68 return(-1) 69 self.__io.flush() 70 return(0) 71 72 def io_read(self, len = -1): 73 if self.__io == None: 74 return(-1) 75 try: 76 if len < 0: 77 ret = self.__io.read() 78 else: 79 ret = self.__io.read(len) 80 except Exception: 81 import sys 82 e = sys.exc_info()[1] 83 print("failed to read from Python:", type(e)) 84 print("on IO:", self.__io) 85 self.__io == None 86 return(-1) 87 88 return(ret) 89 90 def io_write(self, str, len = -1): 91 if self.__io == None: 92 return(-1) 93 if len < 0: 94 return(self.__io.write(str)) 95 return(self.__io.write(str, len)) 96 97class ioReadWrapper(ioWrapper): 98 def __init__(self, _obj, enc = ""): 99 ioWrapper.__init__(self, _obj) 100 self._o = libxml2mod.xmlCreateInputBuffer(self, enc) 101 102 def __del__(self): 103 print("__del__") 104 self.io_close() 105 if self._o != None: 106 libxml2mod.xmlFreeParserInputBuffer(self._o) 107 self._o = None 108 109 def close(self): 110 self.io_close() 111 if self._o != None: 112 libxml2mod.xmlFreeParserInputBuffer(self._o) 113 self._o = None 114 115class ioWriteWrapper(ioWrapper): 116 def __init__(self, _obj, enc = ""): 117# print "ioWriteWrapper.__init__", _obj 118 if type(_obj) == type(''): 119 print("write io from a string") 120 self.o = None 121 elif type(_obj).__name__ == 'PyCapsule': 122 file = libxml2mod.outputBufferGetPythonFile(_obj) 123 if file != None: 124 ioWrapper.__init__(self, file) 125 else: 126 ioWrapper.__init__(self, _obj) 127 self._o = _obj 128# elif type(_obj) == types.InstanceType: 129# print(("write io from instance of %s" % (_obj.__class__))) 130# ioWrapper.__init__(self, _obj) 131# self._o = libxml2mod.xmlCreateOutputBuffer(self, enc) 132 else: 133 file = libxml2mod.outputBufferGetPythonFile(_obj) 134 if file != None: 135 ioWrapper.__init__(self, file) 136 else: 137 ioWrapper.__init__(self, _obj) 138 self._o = _obj 139 140 def __del__(self): 141# print "__del__" 142 self.io_close() 143 if self._o != None: 144 libxml2mod.xmlOutputBufferClose(self._o) 145 self._o = None 146 147 def flush(self): 148 self.io_flush() 149 if self._o != None: 150 libxml2mod.xmlOutputBufferClose(self._o) 151 self._o = None 152 153 def close(self): 154 self.io_flush() 155 if self._o != None: 156 libxml2mod.xmlOutputBufferClose(self._o) 157 self._o = None 158 159# 160# Example of a class to handle SAX events 161# 162class SAXCallback: 163 """Base class for SAX handlers""" 164 def startDocument(self): 165 """called at the start of the document""" 166 pass 167 168 def endDocument(self): 169 """called at the end of the document""" 170 pass 171 172 def startElement(self, tag, attrs): 173 """called at the start of every element, tag is the name of 174 the element, attrs is a dictionary of the element's attributes""" 175 pass 176 177 def endElement(self, tag): 178 """called at the start of every element, tag is the name of 179 the element""" 180 pass 181 182 def characters(self, data): 183 """called when character data have been read, data is the string 184 containing the data, multiple consecutive characters() callback 185 are possible.""" 186 pass 187 188 def cdataBlock(self, data): 189 """called when CDATA section have been read, data is the string 190 containing the data, multiple consecutive cdataBlock() callback 191 are possible.""" 192 pass 193 194 def reference(self, name): 195 """called when an entity reference has been found""" 196 pass 197 198 def ignorableWhitespace(self, data): 199 """called when potentially ignorable white spaces have been found""" 200 pass 201 202 def processingInstruction(self, target, data): 203 """called when a PI has been found, target contains the PI name and 204 data is the associated data in the PI""" 205 pass 206 207 def comment(self, content): 208 """called when a comment has been found, content contains the comment""" 209 pass 210 211 def externalSubset(self, name, externalID, systemID): 212 """called when a DOCTYPE declaration has been found, name is the 213 DTD name and externalID, systemID are the DTD public and system 214 identifier for that DTd if available""" 215 pass 216 217 def internalSubset(self, name, externalID, systemID): 218 """called when a DOCTYPE declaration has been found, name is the 219 DTD name and externalID, systemID are the DTD public and system 220 identifier for that DTD if available""" 221 pass 222 223 def entityDecl(self, name, type, externalID, systemID, content): 224 """called when an ENTITY declaration has been found, name is the 225 entity name and externalID, systemID are the entity public and 226 system identifier for that entity if available, type indicates 227 the entity type, and content reports it's string content""" 228 pass 229 230 def notationDecl(self, name, externalID, systemID): 231 """called when an NOTATION declaration has been found, name is the 232 notation name and externalID, systemID are the notation public and 233 system identifier for that notation if available""" 234 pass 235 236 def attributeDecl(self, elem, name, type, defi, defaultValue, nameList): 237 """called when an ATTRIBUTE definition has been found""" 238 pass 239 240 def elementDecl(self, name, type, content): 241 """called when an ELEMENT definition has been found""" 242 pass 243 244 def entityDecl(self, name, publicId, systemID, notationName): 245 """called when an unparsed ENTITY declaration has been found, 246 name is the entity name and publicId,, systemID are the entity 247 public and system identifier for that entity if available, 248 and notationName indicate the associated NOTATION""" 249 pass 250 251 def warning(self, msg): 252 #print msg 253 pass 254 255 def error(self, msg): 256 raise parserError(msg) 257 258 def fatalError(self, msg): 259 raise parserError(msg) 260 261# 262# This class is the ancestor of all the Node classes. It provides 263# the basic functionalities shared by all nodes (and handle 264# gracefylly the exception), like name, navigation in the tree, 265# doc reference, content access and serializing to a string or URI 266# 267class xmlCore: 268 def __init__(self, _obj=None): 269 if _obj != None: 270 self._o = _obj; 271 return 272 self._o = None 273 274 def __eq__(self, other): 275 if other == None: 276 return False 277 ret = libxml2mod.compareNodesEqual(self._o, other._o) 278 if ret == None: 279 return False 280 return ret == True 281 def __ne__(self, other): 282 if other == None: 283 return True 284 ret = libxml2mod.compareNodesEqual(self._o, other._o) 285 return not ret 286 def __hash__(self): 287 ret = libxml2mod.nodeHash(self._o) 288 return ret 289 290 def __str__(self): 291 return self.serialize() 292 def get_parent(self): 293 ret = libxml2mod.parent(self._o) 294 if ret == None: 295 return None 296 return nodeWrap(ret) 297 def get_children(self): 298 ret = libxml2mod.children(self._o) 299 if ret == None: 300 return None 301 return nodeWrap(ret) 302 def get_last(self): 303 ret = libxml2mod.last(self._o) 304 if ret == None: 305 return None 306 return nodeWrap(ret) 307 def get_next(self): 308 ret = libxml2mod.next(self._o) 309 if ret == None: 310 return None 311 return nodeWrap(ret) 312 def get_properties(self): 313 ret = libxml2mod.properties(self._o) 314 if ret == None: 315 return None 316 return xmlAttr(_obj=ret) 317 def get_prev(self): 318 ret = libxml2mod.prev(self._o) 319 if ret == None: 320 return None 321 return nodeWrap(ret) 322 def get_content(self): 323 return libxml2mod.xmlNodeGetContent(self._o) 324 getContent = get_content # why is this duplicate naming needed ? 325 def get_name(self): 326 return libxml2mod.name(self._o) 327 def get_type(self): 328 return libxml2mod.type(self._o) 329 def get_doc(self): 330 ret = libxml2mod.doc(self._o) 331 if ret == None: 332 if self.type in ["document_xml", "document_html"]: 333 return xmlDoc(_obj=self._o) 334 else: 335 return None 336 return xmlDoc(_obj=ret) 337 # 338 # Those are common attributes to nearly all type of nodes 339 # defined as python2 properties 340 # 341 import sys 342 if float(sys.version[0:3]) < 2.2: 343 def __getattr__(self, attr): 344 if attr == "parent": 345 ret = libxml2mod.parent(self._o) 346 if ret == None: 347 return None 348 return nodeWrap(ret) 349 elif attr == "properties": 350 ret = libxml2mod.properties(self._o) 351 if ret == None: 352 return None 353 return xmlAttr(_obj=ret) 354 elif attr == "children": 355 ret = libxml2mod.children(self._o) 356 if ret == None: 357 return None 358 return nodeWrap(ret) 359 elif attr == "last": 360 ret = libxml2mod.last(self._o) 361 if ret == None: 362 return None 363 return nodeWrap(ret) 364 elif attr == "next": 365 ret = libxml2mod.next(self._o) 366 if ret == None: 367 return None 368 return nodeWrap(ret) 369 elif attr == "prev": 370 ret = libxml2mod.prev(self._o) 371 if ret == None: 372 return None 373 return nodeWrap(ret) 374 elif attr == "content": 375 return libxml2mod.xmlNodeGetContent(self._o) 376 elif attr == "name": 377 return libxml2mod.name(self._o) 378 elif attr == "type": 379 return libxml2mod.type(self._o) 380 elif attr == "doc": 381 ret = libxml2mod.doc(self._o) 382 if ret == None: 383 if self.type == "document_xml" or self.type == "document_html": 384 return xmlDoc(_obj=self._o) 385 else: 386 return None 387 return xmlDoc(_obj=ret) 388 raise AttributeError(attr) 389 else: 390 parent = property(get_parent, None, None, "Parent node") 391 children = property(get_children, None, None, "First child node") 392 last = property(get_last, None, None, "Last sibling node") 393 next = property(get_next, None, None, "Next sibling node") 394 prev = property(get_prev, None, None, "Previous sibling node") 395 properties = property(get_properties, None, None, "List of properies") 396 content = property(get_content, None, None, "Content of this node") 397 name = property(get_name, None, None, "Node name") 398 type = property(get_type, None, None, "Node type") 399 doc = property(get_doc, None, None, "The document this node belongs to") 400 401 # 402 # Serialization routines, the optional arguments have the following 403 # meaning: 404 # encoding: string to ask saving in a specific encoding 405 # indent: if 1 the serializer is asked to indent the output 406 # 407 def serialize(self, encoding = None, format = 0): 408 return libxml2mod.serializeNode(self._o, encoding, format) 409 def saveTo(self, file, encoding = None, format = 0): 410 return libxml2mod.saveNodeTo(self._o, file, encoding, format) 411 412 # 413 # Canonicalization routines: 414 # 415 # nodes: the node set (tuple or list) to be included in the 416 # canonized image or None if all document nodes should be 417 # included. 418 # exclusive: the exclusive flag (0 - non-exclusive 419 # canonicalization; otherwise - exclusive canonicalization) 420 # prefixes: the list of inclusive namespace prefixes (strings), 421 # or None if there is no inclusive namespaces (only for 422 # exclusive canonicalization, ignored otherwise) 423 # with_comments: include comments in the result (!=0) or not 424 # (==0) 425 def c14nMemory(self, 426 nodes=None, 427 exclusive=0, 428 prefixes=None, 429 with_comments=0): 430 if nodes: 431 nodes = [n._o for n in nodes] 432 return libxml2mod.xmlC14NDocDumpMemory( 433 self.get_doc()._o, 434 nodes, 435 exclusive != 0, 436 prefixes, 437 with_comments != 0) 438 def c14nSaveTo(self, 439 file, 440 nodes=None, 441 exclusive=0, 442 prefixes=None, 443 with_comments=0): 444 if nodes: 445 nodes = [n._o for n in nodes] 446 return libxml2mod.xmlC14NDocSaveTo( 447 self.get_doc()._o, 448 nodes, 449 exclusive != 0, 450 prefixes, 451 with_comments != 0, 452 file) 453 454 # 455 # Selecting nodes using XPath, a bit slow because the context 456 # is allocated/freed every time but convenient. 457 # 458 def xpathEval(self, expr): 459 doc = self.doc 460 if doc == None: 461 return None 462 ctxt = doc.xpathNewContext() 463 ctxt.setContextNode(self) 464 res = ctxt.xpathEval(expr) 465 ctxt.xpathFreeContext() 466 return res 467 468# # 469# # Selecting nodes using XPath, faster because the context 470# # is allocated just once per xmlDoc. 471# # 472# # Removed: DV memleaks c.f. #126735 473# # 474# def xpathEval2(self, expr): 475# doc = self.doc 476# if doc == None: 477# return None 478# try: 479# doc._ctxt.setContextNode(self) 480# except: 481# doc._ctxt = doc.xpathNewContext() 482# doc._ctxt.setContextNode(self) 483# res = doc._ctxt.xpathEval(expr) 484# return res 485 def xpathEval2(self, expr): 486 return self.xpathEval(expr) 487 488 # Remove namespaces 489 def removeNsDef(self, href): 490 """ 491 Remove a namespace definition from a node. If href is None, 492 remove all of the ns definitions on that node. The removed 493 namespaces are returned as a linked list. 494 495 Note: If any child nodes referred to the removed namespaces, 496 they will be left with dangling links. You should call 497 renconciliateNs() to fix those pointers. 498 499 Note: This method does not free memory taken by the ns 500 definitions. You will need to free it manually with the 501 freeNsList() method on the returns xmlNs object. 502 """ 503 504 ret = libxml2mod.xmlNodeRemoveNsDef(self._o, href) 505 if ret is None:return None 506 __tmp = xmlNs(_obj=ret) 507 return __tmp 508 509 # support for python2 iterators 510 def walk_depth_first(self): 511 return xmlCoreDepthFirstItertor(self) 512 def walk_breadth_first(self): 513 return xmlCoreBreadthFirstItertor(self) 514 __iter__ = walk_depth_first 515 516 def free(self): 517 try: 518 self.doc._ctxt.xpathFreeContext() 519 except: 520 pass 521 libxml2mod.xmlFreeDoc(self._o) 522 523 524# 525# implements the depth-first iterator for libxml2 DOM tree 526# 527class xmlCoreDepthFirstItertor: 528 def __init__(self, node): 529 self.node = node 530 self.parents = [] 531 def __iter__(self): 532 return self 533 def __next__(self): 534 while 1: 535 if self.node: 536 ret = self.node 537 self.parents.append(self.node) 538 self.node = self.node.children 539 return ret 540 try: 541 parent = self.parents.pop() 542 except IndexError: 543 raise StopIteration 544 self.node = parent.next 545 next = __next__ 546 547# 548# implements the breadth-first iterator for libxml2 DOM tree 549# 550class xmlCoreBreadthFirstItertor: 551 def __init__(self, node): 552 self.node = node 553 self.parents = [] 554 def __iter__(self): 555 return self 556 def __next__(self): 557 while 1: 558 if self.node: 559 ret = self.node 560 self.parents.append(self.node) 561 self.node = self.node.next 562 return ret 563 try: 564 parent = self.parents.pop() 565 except IndexError: 566 raise StopIteration 567 self.node = parent.children 568 next = __next__ 569 570# 571# converters to present a nicer view of the XPath returns 572# 573def nodeWrap(o): 574 # TODO try to cast to the most appropriate node class 575 name = libxml2mod.type(o) 576 if name == "element" or name == "text": 577 return xmlNode(_obj=o) 578 if name == "attribute": 579 return xmlAttr(_obj=o) 580 if name[0:8] == "document": 581 return xmlDoc(_obj=o) 582 if name == "namespace": 583 return xmlNs(_obj=o) 584 if name == "elem_decl": 585 return xmlElement(_obj=o) 586 if name == "attribute_decl": 587 return xmlAttribute(_obj=o) 588 if name == "entity_decl": 589 return xmlEntity(_obj=o) 590 if name == "dtd": 591 return xmlDtd(_obj=o) 592 return xmlNode(_obj=o) 593 594def xpathObjectRet(o): 595 otype = type(o) 596 if otype == type([]): 597 ret = list(map(xpathObjectRet, o)) 598 return ret 599 elif otype == type(()): 600 ret = list(map(xpathObjectRet, o)) 601 return tuple(ret) 602 elif otype == type('') or otype == type(0) or otype == type(0.0): 603 return o 604 else: 605 return nodeWrap(o) 606 607# 608# register an XPath function 609# 610def registerXPathFunction(ctxt, name, ns_uri, f): 611 ret = libxml2mod.xmlRegisterXPathFunction(ctxt, name, ns_uri, f) 612 613# 614# For the xmlTextReader parser configuration 615# 616PARSER_LOADDTD=1 617PARSER_DEFAULTATTRS=2 618PARSER_VALIDATE=3 619PARSER_SUBST_ENTITIES=4 620 621# 622# For the error callback severities 623# 624PARSER_SEVERITY_VALIDITY_WARNING=1 625PARSER_SEVERITY_VALIDITY_ERROR=2 626PARSER_SEVERITY_WARNING=3 627PARSER_SEVERITY_ERROR=4 628 629# 630# register the libxml2 error handler 631# 632def registerErrorHandler(f, ctx): 633 """Register a Python written function to for error reporting. 634 The function is called back as f(ctx, error). """ 635 import sys 636 if 'libxslt' not in sys.modules: 637 # normal behaviour when libxslt is not imported 638 ret = libxml2mod.xmlRegisterErrorHandler(f,ctx) 639 else: 640 # when libxslt is already imported, one must 641 # use libxst's error handler instead 642 import libxslt 643 ret = libxslt.registerErrorHandler(f,ctx) 644 return ret 645 646class parserCtxtCore: 647 648 def __init__(self, _obj=None): 649 if _obj != None: 650 self._o = _obj; 651 return 652 self._o = None 653 654 def __del__(self): 655 if self._o != None: 656 libxml2mod.xmlFreeParserCtxt(self._o) 657 self._o = None 658 659 def setErrorHandler(self,f,arg): 660 """Register an error handler that will be called back as 661 f(arg,msg,severity,reserved). 662 663 @reserved is currently always None.""" 664 libxml2mod.xmlParserCtxtSetErrorHandler(self._o,f,arg) 665 666 def getErrorHandler(self): 667 """Return (f,arg) as previously registered with setErrorHandler 668 or (None,None).""" 669 return libxml2mod.xmlParserCtxtGetErrorHandler(self._o) 670 671 def addLocalCatalog(self, uri): 672 """Register a local catalog with the parser""" 673 return libxml2mod.addLocalCatalog(self._o, uri) 674 675 676class ValidCtxtCore: 677 678 def __init__(self, *args, **kw): 679 pass 680 681 def setValidityErrorHandler(self, err_func, warn_func, arg=None): 682 """ 683 Register error and warning handlers for DTD validation. 684 These will be called back as f(msg,arg) 685 """ 686 libxml2mod.xmlSetValidErrors(self._o, err_func, warn_func, arg) 687 688 689class SchemaValidCtxtCore: 690 691 def __init__(self, *args, **kw): 692 pass 693 694 def setValidityErrorHandler(self, err_func, warn_func, arg=None): 695 """ 696 Register error and warning handlers for Schema validation. 697 These will be called back as f(msg,arg) 698 """ 699 libxml2mod.xmlSchemaSetValidErrors(self._o, err_func, warn_func, arg) 700 701 702class relaxNgValidCtxtCore: 703 704 def __init__(self, *args, **kw): 705 pass 706 707 def setValidityErrorHandler(self, err_func, warn_func, arg=None): 708 """ 709 Register error and warning handlers for RelaxNG validation. 710 These will be called back as f(msg,arg) 711 """ 712 libxml2mod.xmlRelaxNGSetValidErrors(self._o, err_func, warn_func, arg) 713 714 715def _xmlTextReaderErrorFunc(xxx_todo_changeme,msg,severity,locator): 716 """Intermediate callback to wrap the locator""" 717 (f,arg) = xxx_todo_changeme 718 return f(arg,msg,severity,xmlTextReaderLocator(locator)) 719 720class xmlTextReaderCore: 721 722 def __init__(self, _obj=None): 723 self.input = None 724 if _obj != None:self._o = _obj;return 725 self._o = None 726 727 def __del__(self): 728 if self._o != None: 729 libxml2mod.xmlFreeTextReader(self._o) 730 self._o = None 731 732 def SetErrorHandler(self,f,arg): 733 """Register an error handler that will be called back as 734 f(arg,msg,severity,locator).""" 735 if f is None: 736 libxml2mod.xmlTextReaderSetErrorHandler(\ 737 self._o,None,None) 738 else: 739 libxml2mod.xmlTextReaderSetErrorHandler(\ 740 self._o,_xmlTextReaderErrorFunc,(f,arg)) 741 742 def GetErrorHandler(self): 743 """Return (f,arg) as previously registered with setErrorHandler 744 or (None,None).""" 745 f,arg = libxml2mod.xmlTextReaderGetErrorHandler(self._o) 746 if f is None: 747 return None,None 748 else: 749 # assert f is _xmlTextReaderErrorFunc 750 return arg 751 752# 753# The cleanup now goes though a wrapper in libxml.c 754# 755def cleanupParser(): 756 libxml2mod.xmlPythonCleanupParser() 757 758# 759# The interface to xmlRegisterInputCallbacks. 760# Since this API does not allow to pass a data object along with 761# match/open callbacks, it is necessary to maintain a list of all 762# Python callbacks. 763# 764__input_callbacks = [] 765def registerInputCallback(func): 766 def findOpenCallback(URI): 767 for cb in reversed(__input_callbacks): 768 o = cb(URI) 769 if o is not None: 770 return o 771 libxml2mod.xmlRegisterInputCallback(findOpenCallback) 772 __input_callbacks.append(func) 773 774def popInputCallbacks(): 775 # First pop python-level callbacks, when no more available - start 776 # popping built-in ones. 777 if len(__input_callbacks) > 0: 778 __input_callbacks.pop() 779 if len(__input_callbacks) == 0: 780 libxml2mod.xmlUnregisterInputCallback() 781 782# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 783# 784# Everything before this line comes from libxml.py 785# Everything after this line is automatically generated 786# 787# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 788 789