[libxml2]Add libxml2 library

This commit is contained in:
zhoujiale
2026-07-26 16:57:28 +08:00
committed by zhoujiale
parent 0a44ec8a06
commit e841ac915d
3790 changed files with 668244 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
/gen_prog
/libxml2-export.c
/libxml2-py.c
/libxml2-py.h
/libxml2.py
/setup.py
/tests/tmp.xml
+48
View File
@@ -0,0 +1,48 @@
# Makefile for libxml2 python library
# We use a rule with multiple output files which creates problems with
# parallel builds.
.NOTPARALLEL:
SUBDIRS = . tests
EXTRA_DIST = \
generator.py \
libxml.py \
pyproject.toml \
meson.build
if WITH_PYTHON
AM_CPPFLAGS = \
-I$(top_builddir)/include \
-I$(top_srcdir)/include \
$(PYTHON_CFLAGS)
pyexec_LTLIBRARIES = libxml2mod.la
libxml2mod_la_SOURCES = libxml.c libxml_wrap.h types.c
nodist_libxml2mod_la_SOURCES = libxml2-py.h libxml2-py.c
libxml2mod_la_LDFLAGS = $(AM_LDFLAGS) $(PYTHON_LDFLAGS) -module -avoid-version
libxml2mod_la_LIBADD = $(top_builddir)/libxml2.la $(PYTHON_LIBS)
BUILT_SOURCES = libxml2-export.c libxml2-py.h libxml2-py.c
python_PYTHON = drv_libxml2.py
nodist_python_PYTHON = libxml2.py
API_DESC = ../doc/html.stamp
GENERATED = libxml2.py $(BUILT_SOURCES)
CLEANFILES = $(GENERATED)
all-local: libxml2.py
$(GENERATED): $(srcdir)/generator.py $(API_DESC)
$(PYTHON) $(srcdir)/generator.py $(builddir)
# libxml.c #includes libxml2-export.c
libxml.$(OBJEXT): libxml2-export.c
clean-local:
rm -rf __pycache__ *.pyc
endif
+37
View File
@@ -0,0 +1,37 @@
Module libxml2-python
=====================
DEPRECATION WARNING: It is planned to remove the libxml2 Python
bindings from the libxml2 repo.
This is the libxml2 python module, providing access to the
libxml2 and libxslt (if available) libraries. For general
informationss on those XML and XSLT libraries check their
web pages at:
https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home
and
https://gitlab.gnome.org/GNOME/libxslt/-/wikis/home
The latest version of the sources for this module and the
associated libraries can be found at:
https://gitlab.gnome.org/GNOME/libxml2/-/releases
Binaries packages of the libxml2 and libxslt libraries can
be found either on the FTP site for Linux, from external
sources linked from the web pages, or as part of your set of
packages provided with your operating system.
NOTE:
this module distribution is not the primary distribution
of the libxml2 and libxslt Python binding code, but as
the Python way of packaging those for non-Linux systems.
The main sources are the libxml2 and libxslt tar.gz found on
the site. One side effect is that the official RPM packages for
those modules are not generated from the libxml2-python
distributions but as part of the normal RPM packaging of
those two libraries.
The RPM packages can be found at:
http://rpmfind.net/linux/rpm2html/search.php?query=libxml2-python
http://rpmfind.net/linux/rpm2html/search.php?query=libxslt-python
Daniel Veillard
+382
View File
@@ -0,0 +1,382 @@
# -*- coding: iso-8859-1 -*-
""" A SAX2 driver for libxml2, on top of it's XmlReader API
USAGE
# put this file (drv_libxml2.py) in PYTHONPATH
import xml.sax
reader = xml.sax.make_parser(["drv_libxml2"])
# ...and the rest is standard python sax.
CAVEATS
- Lexical handlers are supported, except for start/endEntity
(waiting for XmlReader.ResolveEntity) and start/endDTD
- Error callbacks are not exactly synchronous, they tend
to be invoked before the corresponding content callback,
because the underlying reader interface parses
data by chunks of 512 bytes
TODO
- search for TODO
- some ErrorHandler events (warning)
- some ContentHandler events (setDocumentLocator, skippedEntity)
- EntityResolver (using libxml2.?)
- DTDHandler (if/when libxml2 exposes such node types)
- DeclHandler (if/when libxml2 exposes such node types)
- property_xml_string?
- feature_string_interning?
- Incremental parser
- additional performance tuning:
- one might cache callbacks to avoid some name lookups
- one might implement a smarter way to pass attributes to startElement
(some kind of lazy evaluation?)
- there might be room for improvement in start/endPrefixMapping
- other?
"""
__author__ = "Stéphane Bidoul <sbi@skynet.be>"
__version__ = "0.3"
import sys
import codecs
if sys.version_info[0] < 3:
__author__ = codecs.unicode_escape_decode(__author__)[0]
StringTypes = (str, unicode)
# libxml2 returns strings as UTF8
_decoder = codecs.lookup("utf8")[1]
def _d(s):
if s is None:
return s
else:
return _decoder(s)[0]
else:
StringTypes = str
# s is Unicode `str` already
def _d(s):
return s
from xml.sax._exceptions import *
from xml.sax import xmlreader, saxutils
from xml.sax.handler import \
feature_namespaces, \
feature_namespace_prefixes, \
feature_string_interning, \
feature_validation, \
feature_external_ges, \
feature_external_pes, \
property_lexical_handler, \
property_declaration_handler, \
property_dom_node, \
property_xml_string
try:
import libxml2
except ImportError:
raise SAXReaderNotAvailable("libxml2 not available: " \
"import error was: %s" % sys.exc_info()[1])
class Locator(xmlreader.Locator):
"""SAX Locator adapter for libxml2.xmlTextReaderLocator"""
def __init__(self,locator):
self.__locator = locator
def getColumnNumber(self):
"Return the column number where the current event ends."
return -1
def getLineNumber(self):
"Return the line number where the current event ends."
return self.__locator.LineNumber()
def getPublicId(self):
"Return the public identifier for the current event."
return None
def getSystemId(self):
"Return the system identifier for the current event."
return self.__locator.BaseURI()
class LibXml2Reader(xmlreader.XMLReader):
def __init__(self):
xmlreader.XMLReader.__init__(self)
# features
self.__ns = 0
self.__nspfx = 0
self.__validate = 0
self.__extparams = 1
# parsing flag
self.__parsing = 0
# additional handlers
self.__lex_handler = None
self.__decl_handler = None
# error messages accumulator
self.__errors = None
def _errorHandler(self,arg,msg,severity,locator):
if self.__errors is None:
self.__errors = []
self.__errors.append((severity,
SAXParseException(msg,None,
Locator(locator))))
def _reportErrors(self,fatal):
for severity,exception in self.__errors:
if severity in (libxml2.PARSER_SEVERITY_VALIDITY_WARNING,
libxml2.PARSER_SEVERITY_WARNING):
self._err_handler.warning(exception)
else:
# when fatal is set, the parse will stop;
# we consider that the last error reported
# is the fatal one.
if fatal and exception is self.__errors[-1][1]:
self._err_handler.fatalError(exception)
else:
self._err_handler.error(exception)
self.__errors = None
def parse(self, source):
self.__parsing = 1
try:
# prepare source and create reader
if isinstance(source, StringTypes):
reader = libxml2.newTextReaderFilename(source)
else:
source = saxutils.prepare_input_source(source)
stream = source.getCharacterStream()
if stream is None:
stream = source.getByteStream()
input = libxml2.inputBuffer(stream)
reader = input.newTextReader(source.getSystemId())
reader.SetErrorHandler(self._errorHandler,None)
# configure reader
if self.__extparams:
reader.SetParserProp(libxml2.PARSER_LOADDTD,1)
reader.SetParserProp(libxml2.PARSER_DEFAULTATTRS,1)
reader.SetParserProp(libxml2.PARSER_SUBST_ENTITIES,1)
reader.SetParserProp(libxml2.PARSER_VALIDATE,self.__validate)
else:
reader.SetParserProp(libxml2.PARSER_LOADDTD, 0)
# we reuse attribute maps (for a slight performance gain)
if self.__ns:
attributesNSImpl = xmlreader.AttributesNSImpl({},{})
else:
attributesImpl = xmlreader.AttributesImpl({})
# prefixes to pop (for endPrefixMapping)
prefixes = []
# start loop
self._cont_handler.startDocument()
while 1:
r = reader.Read()
# check for errors
if r == 1:
if not self.__errors is None:
self._reportErrors(0)
elif r == 0:
if not self.__errors is None:
self._reportErrors(0)
break # end of parse
else:
if not self.__errors is None:
self._reportErrors(1)
else:
self._err_handler.fatalError(\
SAXException("Read failed (no details available)"))
break # fatal parse error
# get node type
nodeType = reader.NodeType()
# Element
if nodeType == 1:
if self.__ns:
eltName = (_d(reader.NamespaceUri()),\
_d(reader.LocalName()))
eltQName = _d(reader.Name())
attributesNSImpl._attrs = attrs = {}
attributesNSImpl._qnames = qnames = {}
newPrefixes = []
while reader.MoveToNextAttribute():
qname = _d(reader.Name())
value = _d(reader.Value())
if qname.startswith("xmlns"):
if len(qname) > 5:
newPrefix = qname[6:]
else:
newPrefix = None
newPrefixes.append(newPrefix)
self._cont_handler.startPrefixMapping(\
newPrefix,value)
if not self.__nspfx:
continue # don't report xmlns attribute
attName = (_d(reader.NamespaceUri()),
_d(reader.LocalName()))
qnames[attName] = qname
attrs[attName] = value
reader.MoveToElement()
self._cont_handler.startElementNS( \
eltName,eltQName,attributesNSImpl)
if reader.IsEmptyElement():
self._cont_handler.endElementNS(eltName,eltQName)
for newPrefix in newPrefixes:
self._cont_handler.endPrefixMapping(newPrefix)
else:
prefixes.append(newPrefixes)
else:
eltName = _d(reader.Name())
attributesImpl._attrs = attrs = {}
while reader.MoveToNextAttribute():
attName = _d(reader.Name())
attrs[attName] = _d(reader.Value())
reader.MoveToElement()
self._cont_handler.startElement( \
eltName,attributesImpl)
if reader.IsEmptyElement():
self._cont_handler.endElement(eltName)
# EndElement
elif nodeType == 15:
if self.__ns:
self._cont_handler.endElementNS( \
(_d(reader.NamespaceUri()),_d(reader.LocalName())),
_d(reader.Name()))
for prefix in prefixes.pop():
self._cont_handler.endPrefixMapping(prefix)
else:
self._cont_handler.endElement(_d(reader.Name()))
# Text
elif nodeType == 3:
self._cont_handler.characters(_d(reader.Value()))
# Whitespace
elif nodeType == 13:
self._cont_handler.ignorableWhitespace(_d(reader.Value()))
# SignificantWhitespace
elif nodeType == 14:
self._cont_handler.characters(_d(reader.Value()))
# CDATA
elif nodeType == 4:
if not self.__lex_handler is None:
self.__lex_handler.startCDATA()
self._cont_handler.characters(_d(reader.Value()))
if not self.__lex_handler is None:
self.__lex_handler.endCDATA()
# EntityReference
elif nodeType == 5:
if not self.__lex_handler is None:
self.startEntity(_d(reader.Name()))
reader.ResolveEntity()
# EndEntity
elif nodeType == 16:
if not self.__lex_handler is None:
self.endEntity(_d(reader.Name()))
# ProcessingInstruction
elif nodeType == 7:
self._cont_handler.processingInstruction( \
_d(reader.Name()),_d(reader.Value()))
# Comment
elif nodeType == 8:
if not self.__lex_handler is None:
self.__lex_handler.comment(_d(reader.Value()))
# DocumentType
elif nodeType == 10:
#if not self.__lex_handler is None:
# self.__lex_handler.startDTD()
pass # TODO (how to detect endDTD? on first non-dtd event?)
# XmlDeclaration
elif nodeType == 17:
pass # TODO
# Entity
elif nodeType == 6:
pass # TODO (entity decl)
# Notation (decl)
elif nodeType == 12:
pass # TODO
# Attribute (never in this loop)
#elif nodeType == 2:
# pass
# Document (not exposed)
#elif nodeType == 9:
# pass
# DocumentFragment (never returned by XmlReader)
#elif nodeType == 11:
# pass
# None
#elif nodeType == 0:
# pass
# -
else:
raise SAXException("Unexpected node type %d" % nodeType)
if r == 0:
self._cont_handler.endDocument()
reader.Close()
finally:
self.__parsing = 0
def setDTDHandler(self, handler):
# TODO (when supported, the inherited method works just fine)
raise SAXNotSupportedException("DTDHandler not supported")
def setEntityResolver(self, resolver):
# TODO (when supported, the inherited method works just fine)
raise SAXNotSupportedException("EntityResolver not supported")
def getFeature(self, name):
if name == feature_namespaces:
return self.__ns
elif name == feature_namespace_prefixes:
return self.__nspfx
elif name == feature_validation:
return self.__validate
elif name == feature_external_ges:
return 1 # TODO (does that relate to PARSER_LOADDTD)?
elif name == feature_external_pes:
return self.__extparams
else:
raise SAXNotRecognizedException("Feature '%s' not recognized" % \
name)
def setFeature(self, name, state):
if self.__parsing:
raise SAXNotSupportedException("Cannot set feature %s " \
"while parsing" % name)
if name == feature_namespaces:
self.__ns = state
elif name == feature_namespace_prefixes:
self.__nspfx = state
elif name == feature_validation:
self.__validate = state
elif name == feature_external_ges:
if state == 0:
# TODO (does that relate to PARSER_LOADDTD)?
raise SAXNotSupportedException("Feature '%s' not supported" % \
name)
elif name == feature_external_pes:
self.__extparams = state
else:
raise SAXNotRecognizedException("Feature '%s' not recognized" % \
name)
def getProperty(self, name):
if name == property_lexical_handler:
return self.__lex_handler
elif name == property_declaration_handler:
return self.__decl_handler
else:
raise SAXNotRecognizedException("Property '%s' not recognized" % \
name)
def setProperty(self, name, value):
if name == property_lexical_handler:
self.__lex_handler = value
elif name == property_declaration_handler:
# TODO: remove if/when libxml2 supports dtd events
raise SAXNotSupportedException("Property '%s' not supported" % \
name)
self.__decl_handler = value
else:
raise SAXNotRecognizedException("Property '%s' not recognized" % \
name)
def create_parser():
return LibXml2Reader()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+794
View File
@@ -0,0 +1,794 @@
import libxml2mod
import types
import sys
# The root of all libxml2 errors.
class libxmlError(Exception): pass
# Type of the wrapper class for the C objects wrappers
def checkWrapper(obj):
try:
n = type(_obj).__name__
if n != 'PyCObject' and n != 'PyCapsule':
return 1
except:
return 0
return 0
#
# id() is sometimes negative ...
#
def pos_id(o):
i = id(o)
if (i < 0):
return (sys.maxsize - i)
return i
#
# Errors raised by the wrappers when some tree handling failed.
#
class treeError(libxmlError):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class parserError(libxmlError):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class uriError(libxmlError):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class xpathError(libxmlError):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class ioWrapper:
def __init__(self, _obj):
self.__io = _obj
self._o = None
def io_close(self):
if self.__io == None:
return(-1)
self.__io.close()
self.__io = None
return(0)
def io_flush(self):
if self.__io == None:
return(-1)
self.__io.flush()
return(0)
def io_read(self, len = -1):
if self.__io == None:
return(-1)
try:
if len < 0:
ret = self.__io.read()
else:
ret = self.__io.read(len)
except Exception:
import sys
e = sys.exc_info()[1]
print("failed to read from Python:", type(e))
print("on IO:", self.__io)
self.__io == None
return(-1)
return(ret)
def io_write(self, str, len = -1):
if self.__io == None:
return(-1)
if len < 0:
return(self.__io.write(str))
return(self.__io.write(str, len))
class ioReadWrapper(ioWrapper):
def __init__(self, _obj, enc = ""):
ioWrapper.__init__(self, _obj)
self._o = libxml2mod.xmlCreateInputBuffer(self, enc)
def __del__(self):
print("__del__")
self.io_close()
if self._o != None:
libxml2mod.xmlFreeParserInputBuffer(self._o)
self._o = None
def close(self):
self.io_close()
if self._o != None:
libxml2mod.xmlFreeParserInputBuffer(self._o)
self._o = None
class ioWriteWrapper(ioWrapper):
def __init__(self, _obj, enc = ""):
# print "ioWriteWrapper.__init__", _obj
if type(_obj) == type(''):
print("write io from a string")
self.o = None
elif type(_obj).__name__ == 'PyCapsule':
file = libxml2mod.outputBufferGetPythonFile(_obj)
if file != None:
ioWrapper.__init__(self, file)
else:
ioWrapper.__init__(self, _obj)
self._o = _obj
# elif type(_obj) == types.InstanceType:
# print(("write io from instance of %s" % (_obj.__class__)))
# ioWrapper.__init__(self, _obj)
# self._o = libxml2mod.xmlCreateOutputBuffer(self, enc)
else:
file = libxml2mod.outputBufferGetPythonFile(_obj)
if file != None:
ioWrapper.__init__(self, file)
else:
ioWrapper.__init__(self, _obj)
self._o = _obj
def __del__(self):
# print "__del__"
self.io_close()
if self._o != None:
libxml2mod.xmlOutputBufferClose(self._o)
self._o = None
def flush(self):
self.io_flush()
if self._o != None:
libxml2mod.xmlOutputBufferClose(self._o)
self._o = None
def close(self):
self.io_flush()
if self._o != None:
libxml2mod.xmlOutputBufferClose(self._o)
self._o = None
#
# Example of a class to handle SAX events
#
class SAXCallback:
"""Base class for SAX handlers"""
def startDocument(self):
"""called at the start of the document"""
pass
def endDocument(self):
"""called at the end of the document"""
pass
def startElement(self, tag, attrs):
"""called at the start of every element, tag is the name of
the element, attrs is a dictionary of the element's attributes"""
pass
def endElement(self, tag):
"""called at the start of every element, tag is the name of
the element"""
pass
def characters(self, data):
"""called when character data have been read, data is the string
containing the data, multiple consecutive characters() callback
are possible."""
pass
def cdataBlock(self, data):
"""called when CDATA section have been read, data is the string
containing the data, multiple consecutive cdataBlock() callback
are possible."""
pass
def reference(self, name):
"""called when an entity reference has been found"""
pass
def ignorableWhitespace(self, data):
"""called when potentially ignorable white spaces have been found"""
pass
def processingInstruction(self, target, data):
"""called when a PI has been found, target contains the PI name and
data is the associated data in the PI"""
pass
def comment(self, content):
"""called when a comment has been found, content contains the comment"""
pass
def externalSubset(self, name, externalID, systemID):
"""called when a DOCTYPE declaration has been found, name is the
DTD name and externalID, systemID are the DTD public and system
identifier for that DTd if available"""
pass
def internalSubset(self, name, externalID, systemID):
"""called when a DOCTYPE declaration has been found, name is the
DTD name and externalID, systemID are the DTD public and system
identifier for that DTD if available"""
pass
def entityDecl(self, name, type, externalID, systemID, content):
"""called when an ENTITY declaration has been found, name is the
entity name and externalID, systemID are the entity public and
system identifier for that entity if available, type indicates
the entity type, and content reports it's string content"""
pass
def notationDecl(self, name, externalID, systemID):
"""called when an NOTATION declaration has been found, name is the
notation name and externalID, systemID are the notation public and
system identifier for that notation if available"""
pass
def attributeDecl(self, elem, name, type, defi, defaultValue, nameList):
"""called when an ATTRIBUTE definition has been found"""
pass
def elementDecl(self, name, type, content):
"""called when an ELEMENT definition has been found"""
pass
def entityDecl(self, name, publicId, systemID, notationName):
"""called when an unparsed ENTITY declaration has been found,
name is the entity name and publicId,, systemID are the entity
public and system identifier for that entity if available,
and notationName indicate the associated NOTATION"""
pass
def warning(self, msg):
#print msg
pass
def error(self, msg):
raise parserError(msg)
def fatalError(self, msg):
raise parserError(msg)
#
# This class is the ancestor of all the Node classes. It provides
# the basic functionalities shared by all nodes (and handle
# gracefylly the exception), like name, navigation in the tree,
# doc reference, content access and serializing to a string or URI
#
class xmlCore:
def __init__(self, _obj=None):
if _obj != None:
self._o = _obj;
return
self._o = None
def __eq__(self, other):
if other == None:
return False
ret = libxml2mod.compareNodesEqual(self._o, other._o)
if ret == None:
return False
return ret == True
def __ne__(self, other):
if other == None:
return True
ret = libxml2mod.compareNodesEqual(self._o, other._o)
return not ret
def __hash__(self):
ret = libxml2mod.nodeHash(self._o)
return ret
def __str__(self):
return self.serialize()
def get_parent(self):
ret = libxml2mod.parent(self._o)
if ret == None:
return None
return nodeWrap(ret)
def get_children(self):
ret = libxml2mod.children(self._o)
if ret == None:
return None
return nodeWrap(ret)
def get_last(self):
ret = libxml2mod.last(self._o)
if ret == None:
return None
return nodeWrap(ret)
def get_next(self):
ret = libxml2mod.next(self._o)
if ret == None:
return None
return nodeWrap(ret)
def get_properties(self):
ret = libxml2mod.properties(self._o)
if ret == None:
return None
return xmlAttr(_obj=ret)
def get_prev(self):
ret = libxml2mod.prev(self._o)
if ret == None:
return None
return nodeWrap(ret)
def get_content(self):
return libxml2mod.xmlNodeGetContent(self._o)
getContent = get_content # why is this duplicate naming needed ?
def get_name(self):
return libxml2mod.name(self._o)
def get_type(self):
return libxml2mod.type(self._o)
def get_doc(self):
ret = libxml2mod.doc(self._o)
if ret == None:
if self.type in ["document_xml", "document_html"]:
return xmlDoc(_obj=self._o)
else:
return None
return xmlDoc(_obj=ret)
#
# Those are common attributes to nearly all type of nodes
# defined as python2 properties
#
import sys
if float(sys.version[0:3]) < 2.2:
def __getattr__(self, attr):
if attr == "parent":
ret = libxml2mod.parent(self._o)
if ret == None:
return None
return nodeWrap(ret)
elif attr == "properties":
ret = libxml2mod.properties(self._o)
if ret == None:
return None
return xmlAttr(_obj=ret)
elif attr == "children":
ret = libxml2mod.children(self._o)
if ret == None:
return None
return nodeWrap(ret)
elif attr == "last":
ret = libxml2mod.last(self._o)
if ret == None:
return None
return nodeWrap(ret)
elif attr == "next":
ret = libxml2mod.next(self._o)
if ret == None:
return None
return nodeWrap(ret)
elif attr == "prev":
ret = libxml2mod.prev(self._o)
if ret == None:
return None
return nodeWrap(ret)
elif attr == "content":
return libxml2mod.xmlNodeGetContent(self._o)
elif attr == "name":
return libxml2mod.name(self._o)
elif attr == "type":
return libxml2mod.type(self._o)
elif attr == "doc":
ret = libxml2mod.doc(self._o)
if ret == None:
if self.type == "document_xml" or self.type == "document_html":
return xmlDoc(_obj=self._o)
else:
return None
return xmlDoc(_obj=ret)
raise AttributeError(attr)
else:
parent = property(get_parent, None, None, "Parent node")
children = property(get_children, None, None, "First child node")
last = property(get_last, None, None, "Last sibling node")
next = property(get_next, None, None, "Next sibling node")
prev = property(get_prev, None, None, "Previous sibling node")
properties = property(get_properties, None, None, "List of properties")
content = property(get_content, None, None, "Content of this node")
name = property(get_name, None, None, "Node name")
type = property(get_type, None, None, "Node type")
doc = property(get_doc, None, None, "The document this node belongs to")
#
# Serialization routines, the optional arguments have the following
# meaning:
# encoding: string to ask saving in a specific encoding
# indent: if 1 the serializer is asked to indent the output
#
def serialize(self, encoding = None, format = 0):
return libxml2mod.serializeNode(self._o, encoding, format)
def saveTo(self, file, encoding = None, format = 0):
return libxml2mod.saveNodeTo(self._o, file, encoding, format)
#
# Canonicalization routines:
#
# nodes: the node set (tuple or list) to be included in the
# canonized image or None if all document nodes should be
# included.
# exclusive: the exclusive flag (0 - non-exclusive
# canonicalization; otherwise - exclusive canonicalization)
# prefixes: the list of inclusive namespace prefixes (strings),
# or None if there is no inclusive namespaces (only for
# exclusive canonicalization, ignored otherwise)
# with_comments: include comments in the result (!=0) or not
# (==0)
def c14nMemory(self,
nodes=None,
exclusive=0,
prefixes=None,
with_comments=0):
if nodes:
nodes = [n._o for n in nodes]
return libxml2mod.xmlC14NDocDumpMemory(
self.get_doc()._o,
nodes,
exclusive != 0,
prefixes,
with_comments != 0)
def c14nSaveTo(self,
file,
nodes=None,
exclusive=0,
prefixes=None,
with_comments=0):
if nodes:
nodes = [n._o for n in nodes]
return libxml2mod.xmlC14NDocSaveTo(
self.get_doc()._o,
nodes,
exclusive != 0,
prefixes,
with_comments != 0,
file)
#
# Selecting nodes using XPath, a bit slow because the context
# is allocated/freed every time but convenient.
#
def xpathEval(self, expr):
doc = self.doc
if doc == None:
return None
ctxt = doc.xpathNewContext()
ctxt.setContextNode(self)
res = ctxt.xpathEval(expr)
ctxt.xpathFreeContext()
return res
# #
# # Selecting nodes using XPath, faster because the context
# # is allocated just once per xmlDoc.
# #
# # Removed: DV memleaks c.f. #126735
# #
# def xpathEval2(self, expr):
# doc = self.doc
# if doc == None:
# return None
# try:
# doc._ctxt.setContextNode(self)
# except:
# doc._ctxt = doc.xpathNewContext()
# doc._ctxt.setContextNode(self)
# res = doc._ctxt.xpathEval(expr)
# return res
def xpathEval2(self, expr):
return self.xpathEval(expr)
# Remove namespaces
def removeNsDef(self, href):
"""
Remove a namespace definition from a node. If href is None,
remove all of the ns definitions on that node. The removed
namespaces are returned as a linked list.
Note: If any child nodes referred to the removed namespaces,
they will be left with dangling links. You should call
renconciliateNs() to fix those pointers.
Note: This method does not free memory taken by the ns
definitions. You will need to free it manually with the
freeNsList() method on the returns xmlNs object.
"""
ret = libxml2mod.xmlNodeRemoveNsDef(self._o, href)
if ret is None:return None
__tmp = xmlNs(_obj=ret)
return __tmp
# support for python2 iterators
def walk_depth_first(self):
return xmlCoreDepthFirstItertor(self)
def walk_breadth_first(self):
return xmlCoreBreadthFirstItertor(self)
__iter__ = walk_depth_first
def free(self):
try:
self.doc._ctxt.xpathFreeContext()
except:
pass
libxml2mod.xmlFreeDoc(self._o)
#
# implements the depth-first iterator for libxml2 DOM tree
#
class xmlCoreDepthFirstItertor:
def __init__(self, node):
self.node = node
self.parents = []
def __iter__(self):
return self
def __next__(self):
while 1:
if self.node:
ret = self.node
self.parents.append(self.node)
self.node = self.node.children
return ret
try:
parent = self.parents.pop()
except IndexError:
raise StopIteration
self.node = parent.next
next = __next__
#
# implements the breadth-first iterator for libxml2 DOM tree
#
class xmlCoreBreadthFirstItertor:
def __init__(self, node):
self.node = node
self.parents = []
def __iter__(self):
return self
def __next__(self):
while 1:
if self.node:
ret = self.node
self.parents.append(self.node)
self.node = self.node.next
return ret
try:
parent = self.parents.pop()
except IndexError:
raise StopIteration
self.node = parent.children
next = __next__
#
# converters to present a nicer view of the XPath returns
#
def nodeWrap(o):
# TODO try to cast to the most appropriate node class
name = libxml2mod.type(o)
if name == "element" or name == "text":
return xmlNode(_obj=o)
if name == "attribute":
return xmlAttr(_obj=o)
if name[0:8] == "document":
return xmlDoc(_obj=o)
if name == "namespace":
return xmlNs(_obj=o)
if name == "elem_decl":
return xmlElement(_obj=o)
if name == "attribute_decl":
return xmlAttribute(_obj=o)
if name == "entity_decl":
return xmlEntity(_obj=o)
if name == "dtd":
return xmlDtd(_obj=o)
return xmlNode(_obj=o)
def xpathObjectRet(o):
otype = type(o)
if otype == type([]):
ret = list(map(xpathObjectRet, o))
return ret
elif otype == type(()):
ret = list(map(xpathObjectRet, o))
return tuple(ret)
elif otype == type('') or otype == type(0) or otype == type(0.0):
return o
else:
return nodeWrap(o)
#
# register an XPath function
#
def registerXPathFunction(ctxt, name, ns_uri, f):
ret = libxml2mod.xmlRegisterXPathFunction(ctxt, name, ns_uri, f)
#
# For the xmlTextReader parser configuration
#
PARSER_LOADDTD=1
PARSER_DEFAULTATTRS=2
PARSER_VALIDATE=3
PARSER_SUBST_ENTITIES=4
#
# For the error callback severities
#
PARSER_SEVERITY_VALIDITY_WARNING=1
PARSER_SEVERITY_VALIDITY_ERROR=2
PARSER_SEVERITY_WARNING=3
PARSER_SEVERITY_ERROR=4
#
# register the libxml2 error handler
#
def registerErrorHandler(f, ctx):
"""Register a Python written function to for error reporting.
The function is called back as f(ctx, error). """
import sys
if 'libxslt' not in sys.modules:
# normal behaviour when libxslt is not imported
ret = libxml2mod.xmlRegisterErrorHandler(f,ctx)
else:
# when libxslt is already imported, one must
# use libxst's error handler instead
import libxslt
ret = libxslt.registerErrorHandler(f,ctx)
return ret
class parserCtxtCore:
def __init__(self, _obj=None):
if _obj != None:
self._o = _obj;
return
self._o = None
def __del__(self):
if self._o != None:
libxml2mod.xmlFreeParserCtxt(self._o)
self._o = None
def setErrorHandler(self,f,arg):
"""Register an error handler that will be called back as
f(arg,msg,severity,reserved).
@reserved is currently always None."""
libxml2mod.xmlParserCtxtSetErrorHandler(self._o,f,arg)
def getErrorHandler(self):
"""Return (f,arg) as previously registered with setErrorHandler
or (None,None)."""
return libxml2mod.xmlParserCtxtGetErrorHandler(self._o)
def addLocalCatalog(self, uri):
"""Register a local catalog with the parser"""
return libxml2mod.addLocalCatalog(self._o, uri)
class ValidCtxtCore:
def __init__(self, *args, **kw):
pass
def setValidityErrorHandler(self, err_func, warn_func, arg=None):
"""
Register error and warning handlers for DTD validation.
These will be called back as f(msg,arg)
"""
libxml2mod.xmlSetValidErrors(self._o, err_func, warn_func, arg)
class SchemaValidCtxtCore:
def __init__(self, *args, **kw):
pass
def setValidityErrorHandler(self, err_func, warn_func, arg=None):
"""
Register error and warning handlers for Schema validation.
These will be called back as f(msg,arg)
"""
libxml2mod.xmlSchemaSetValidErrors(self._o, err_func, warn_func, arg)
class relaxNgValidCtxtCore:
def __init__(self, *args, **kw):
pass
def setValidityErrorHandler(self, err_func, warn_func, arg=None):
"""
Register error and warning handlers for RelaxNG validation.
These will be called back as f(msg,arg)
"""
libxml2mod.xmlRelaxNGSetValidErrors(self._o, err_func, warn_func, arg)
def _xmlTextReaderErrorFunc(xxx_todo_changeme,msg,severity,locator):
"""Intermediate callback to wrap the locator"""
(f,arg) = xxx_todo_changeme
return f(arg,msg,severity,xmlTextReaderLocator(locator))
class xmlTextReaderCore:
def __init__(self, _obj=None):
self.input = None
if _obj != None:self._o = _obj;return
self._o = None
def __del__(self):
if self._o != None:
libxml2mod.xmlFreeTextReader(self._o)
self._o = None
def SetErrorHandler(self,f,arg):
"""Register an error handler that will be called back as
f(arg,msg,severity,locator)."""
if f is None:
libxml2mod.xmlTextReaderSetErrorHandler(\
self._o,None,None)
else:
libxml2mod.xmlTextReaderSetErrorHandler(\
self._o,_xmlTextReaderErrorFunc,(f,arg))
def GetErrorHandler(self):
"""Return (f,arg) as previously registered with setErrorHandler
or (None,None)."""
f,arg = libxml2mod.xmlTextReaderGetErrorHandler(self._o)
if f is None:
return None,None
else:
# assert f is _xmlTextReaderErrorFunc
return arg
#
# The cleanup now goes though a wrapper in libxml.c
#
def cleanupParser():
libxml2mod.xmlPythonCleanupParser()
#
# The interface to xmlRegisterInputCallbacks.
# Since this API does not allow to pass a data object along with
# match/open callbacks, it is necessary to maintain a list of all
# Python callbacks.
#
__input_callbacks = []
def registerInputCallback(func):
def findOpenCallback(URI):
for cb in reversed(__input_callbacks):
o = cb(URI)
if o is not None:
return o
libxml2mod.xmlRegisterInputCallback(findOpenCallback)
__input_callbacks.append(func)
def popInputCallbacks():
# First pop python-level callbacks, when no more available - start
# popping built-in ones.
if len(__input_callbacks) > 0:
__input_callbacks.pop()
if len(__input_callbacks) == 0:
libxml2mod.xmlUnregisterInputCallback()
#
# Deprecated
#
def dumpMemory():
"""DEPRECATED: This feature was removed."""
# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
#
# Everything before this line comes from libxml.py
# Everything after this line is automatically generated
#
# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+317
View File
@@ -0,0 +1,317 @@
#include <Python.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/catalog.h>
#include <libxml/threads.h>
#include <libxml/nanohttp.h>
#include <libxml/uri.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/debugXML.h>
#include <libxml/HTMLparser.h>
#include <libxml/HTMLtree.h>
#include <libxml/xinclude.h>
#include <libxml/xpointer.h>
#include <libxml/xmlregexp.h>
#include <libxml/xmlautomata.h>
#include <libxml/xmlreader.h>
#include <libxml/xmlsave.h>
#ifdef LIBXML_RELAXNG_ENABLED
#include <libxml/relaxng.h>
#endif
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/xmlschemas.h>
#endif
/*
* for older versions of Python, we don't use PyBytes, but keep PyString
* and don't use Capsule but CObjects
*/
#if PY_VERSION_HEX < 0x02070000
#ifndef PyBytes_Check
#define PyBytes_Check PyString_Check
#define PyBytes_Size PyString_Size
#define PyBytes_AsString PyString_AsString
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_GET_SIZE PyString_GET_SIZE
#endif
#ifndef PyCapsule_New
#define PyCapsule_New PyCObject_FromVoidPtrAndDesc
#define PyCapsule_CheckExact PyCObject_Check
#define PyCapsule_GetPointer(o, n) PyCObject_GetDesc((o))
#endif
#endif
/**
* ATTRIBUTE_UNUSED:
*
* Macro used to signal to GCC unused function parameters
* Repeated here since the definition is not available when
* compiled outside the libxml2 build tree.
*/
#if defined(__GNUC__) || defined(__clang__)
#ifdef ATTRIBUTE_UNUSED
#undef ATTRIBUTE_UNUSED
#endif
#ifndef ATTRIBUTE_UNUSED
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif /* ATTRIBUTE_UNUSED */
#else
#define ATTRIBUTE_UNUSED
#endif
/*
* Macros to ignore deprecation warnings
*/
#if defined(__LCC__)
#define XML_IGNORE_DEPRECATION_WARNINGS _Pragma("diag_suppress 1215")
#define XML_POP_WARNINGS _Pragma("diag_default 1215")
#elif defined(__clang__) || \
(defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
#define XML_IGNORE_DEPRECATION_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#define XML_POP_WARNINGS _Pragma("GCC diagnostic pop")
#elif defined (_MSC_VER) && (_MSC_VER >= 1400)
#define XML_IGNORE_DEPRECATION_WARNINGS \
__pragma(warning(push)) \
__pragma(warning(disable : 4996))
#define XML_POP_WARNINGS __pragma(warning(pop))
#else
#define XML_IGNORE_DEPRECATION_WARNINGS
#define XML_POP_WARNINGS
#endif
#define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlNode_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlNodePtr obj;
} PyxmlNode_Object;
#ifdef LIBXML_XPATH_ENABLED
#define PyxmlXPathContext_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlXPathContext_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlXPathContextPtr obj;
} PyxmlXPathContext_Object;
#define PyxmlXPathParserContext_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlXPathParserContext_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlXPathParserContextPtr obj;
} PyxmlXPathParserContext_Object;
#endif /* LIBXML_XPATH_ENABLED */
#define PyparserCtxt_Get(v) (((v) == Py_None) ? NULL : \
(((PyparserCtxt_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlParserCtxtPtr obj;
} PyparserCtxt_Object;
#define PyValidCtxt_Get(v) (((v) == Py_None) ? NULL : \
(((PyValidCtxt_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlValidCtxtPtr obj;
} PyValidCtxt_Object;
#ifdef LIBXML_CATALOG_ENABLED
#define Pycatalog_Get(v) (((v) == Py_None) ? NULL : \
(((Pycatalog_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlCatalogPtr obj;
} Pycatalog_Object;
#endif /* LIBXML_CATALOG_ENABLED */
#ifdef LIBXML_REGEXP_ENABLED
#define PyxmlReg_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlReg_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlRegexpPtr obj;
} PyxmlReg_Object;
#endif /* LIBXML_REGEXP_ENABLED */
#ifdef LIBXML_READER_ENABLED
#define PyxmlTextReader_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlTextReader_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlTextReaderPtr obj;
} PyxmlTextReader_Object;
#define PyxmlTextReaderLocator_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlTextReaderLocator_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlTextReaderLocatorPtr obj;
} PyxmlTextReaderLocator_Object;
#endif
#define PyURI_Get(v) (((v) == Py_None) ? NULL : \
(((PyURI_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlErrorPtr obj;
} PyError_Object;
#define PyError_Get(v) (((v) == Py_None) ? NULL : \
(((PyError_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlOutputBufferPtr obj;
} PyoutputBuffer_Object;
#define PyoutputBuffer_Get(v) (((v) == Py_None) ? NULL : \
(((PyoutputBuffer_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlParserInputBufferPtr obj;
} PyinputBuffer_Object;
#define PyinputBuffer_Get(v) (((v) == Py_None) ? NULL : \
(((PyinputBuffer_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlURIPtr obj;
} PyURI_Object;
/* FILE * have their own internal representation */
#if PY_MAJOR_VERSION >= 3
FILE *libxml_PyFileGet(PyObject *f);
void libxml_PyFileRelease(FILE *f);
#define PyFile_Get(v) (((v) == Py_None) ? NULL : libxml_PyFileGet(v))
#define PyFile_Release(f) libxml_PyFileRelease(f)
#else
#define PyFile_Get(v) (((v) == Py_None) ? NULL : \
(PyFile_Check(v) ? (PyFile_AsFile(v)) : stdout))
#define PyFile_Release(f)
#endif
#ifdef LIBXML_RELAXNG_ENABLED
typedef struct {
PyObject_HEAD
xmlRelaxNGPtr obj;
} PyrelaxNgSchema_Object;
#define PyrelaxNgSchema_Get(v) (((v) == Py_None) ? NULL : \
(((PyrelaxNgSchema_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlRelaxNGParserCtxtPtr obj;
} PyrelaxNgParserCtxt_Object;
#define PyrelaxNgParserCtxt_Get(v) (((v) == Py_None) ? NULL : \
(((PyrelaxNgParserCtxt_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlRelaxNGValidCtxtPtr obj;
} PyrelaxNgValidCtxt_Object;
#define PyrelaxNgValidCtxt_Get(v) (((v) == Py_None) ? NULL : \
(((PyrelaxNgValidCtxt_Object *)(v))->obj))
#endif /* LIBXML_RELAXNG_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
typedef struct {
PyObject_HEAD
xmlSchemaPtr obj;
} PySchema_Object;
#define PySchema_Get(v) (((v) == Py_None) ? NULL : \
(((PySchema_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlSchemaParserCtxtPtr obj;
} PySchemaParserCtxt_Object;
#define PySchemaParserCtxt_Get(v) (((v) == Py_None) ? NULL : \
(((PySchemaParserCtxt_Object *)(v))->obj))
typedef struct {
PyObject_HEAD
xmlSchemaValidCtxtPtr obj;
} PySchemaValidCtxt_Object;
#define PySchemaValidCtxt_Get(v) (((v) == Py_None) ? NULL : \
(((PySchemaValidCtxt_Object *)(v))->obj))
#endif /* LIBXML_SCHEMAS_ENABLED */
PyObject * libxml_intWrap(int val);
PyObject * libxml_longWrap(long val);
PyObject * libxml_xmlCharPtrWrap(xmlChar *str);
PyObject * libxml_constxmlCharPtrWrap(const xmlChar *str);
PyObject * libxml_charPtrWrap(char *str);
PyObject * libxml_constcharPtrWrap(const char *str);
PyObject * libxml_charPtrConstWrap(const char *str);
PyObject * libxml_xmlCharPtrConstWrap(const xmlChar *str);
PyObject * libxml_xmlDocPtrWrap(xmlDocPtr doc);
PyObject * libxml_xmlNodePtrWrap(xmlNodePtr node);
PyObject * libxml_xmlAttrPtrWrap(xmlAttrPtr attr);
PyObject * libxml_xmlNsPtrWrap(xmlNsPtr ns);
PyObject * libxml_xmlAttributePtrWrap(xmlAttributePtr ns);
PyObject * libxml_xmlElementPtrWrap(xmlElementPtr ns);
PyObject * libxml_doubleWrap(double val);
PyObject * libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt);
#ifdef LIBXML_XPATH_ENABLED
PyObject * libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt);
PyObject * libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt);
PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj);
xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj);
#endif
PyObject * libxml_xmlValidCtxtPtrWrap(xmlValidCtxtPtr valid);
#ifdef LIBXML_CATALOG_ENABLED
PyObject * libxml_xmlCatalogPtrWrap(xmlCatalogPtr obj);
#endif
PyObject * libxml_xmlURIPtrWrap(xmlURIPtr uri);
PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer);
PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer);
#ifdef LIBXML_REGEXP_ENABLED
PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp);
#endif /* LIBXML_REGEXP_ENABLED */
#ifdef LIBXML_READER_ENABLED
PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader);
PyObject * libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator);
#endif
#ifdef LIBXML_RELAXNG_ENABLED
PyObject * libxml_xmlRelaxNGPtrWrap(xmlRelaxNGPtr ctxt);
PyObject * libxml_xmlRelaxNGParserCtxtPtrWrap(xmlRelaxNGParserCtxtPtr ctxt);
PyObject * libxml_xmlRelaxNGValidCtxtPtrWrap(xmlRelaxNGValidCtxtPtr valid);
#endif /* LIBXML_RELAXNG_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
PyObject * libxml_xmlSchemaPtrWrap(xmlSchemaPtr ctxt);
PyObject * libxml_xmlSchemaParserCtxtPtrWrap(xmlSchemaParserCtxtPtr ctxt);
PyObject * libxml_xmlSchemaValidCtxtPtrWrap(xmlSchemaValidCtxtPtr valid);
#endif /* LIBXML_SCHEMAS_ENABLED */
PyObject * libxml_xmlErrorPtrWrap(const xmlError *error);
PyObject * libxml_xmlSchemaSetValidErrors(PyObject * self, PyObject * args);
PyObject * libxml_xmlRegisterInputCallback(PyObject *self, PyObject *args);
PyObject * libxml_xmlUnregisterInputCallback(PyObject *self, PyObject *args);
PyObject * libxml_xmlNodeRemoveNsDef(PyObject * self, PyObject * args);
int libxml_deprecationWarning(const char *func);
+113
View File
@@ -0,0 +1,113 @@
pymod = import('python')
py = pymod.find_installation('python3', required: false)
if py.found() == true
message('Installing python modules to', py.get_install_dir())
pygenerated = custom_target(
'Python generated files',
input: doxygen_docs[1],
output: [
'libxml2-py.h',
'libxml2-export.c',
'libxml2-py.c',
'libxml2.py',
],
command: [ py, files('generator.py'), meson.current_build_dir() ],
install: true,
install_dir: [ false, false, false, py.get_install_dir() ],
)
pygenerated_dep = declare_dependency(
sources : [pygenerated[0]],
)
libxml2mod_src = [
files('libxml.c', 'types.c'),
pygenerated[2],
]
py.extension_module(
'libxml2mod',
libxml2mod_src,
dependencies: [
py.dependency(),
xml_dep,
pygenerated_dep,
],
include_directories: [config_dir, '.'],
install: true,
)
py.install_sources(files('drv_libxml2.py'))
setup_py = configuration_data()
setup_py.set('prefix', get_option('prefix'))
setup_py.set('LIBXML_VERSION', meson.project_version())
setup_py.set('WITH_ICONV', want_iconv.to_int())
setup_py.set('WITH_ICU', want_icu.to_int())
setup_py.set('WITH_ZLIB', want_zlib.to_int())
setup_py.set('WITH_THREADS', want_threads.to_int())
configure_file(
input: 'setup.py.in',
output: 'setup.py',
configuration: setup_py,
)
python_tests = [
'attribs.py',
'build.py',
'compareNodes.py',
'ctxterror.py',
'cutnpaste.py',
'dtdvalid.py',
'error.py',
'inbuf.py',
'indexes.py',
'input_callback.py',
'nsdel.py',
'outbuf.py',
'push.py',
'pushSAX.py',
'pushSAXhtml.py',
'reader.py',
'reader2.py',
'reader3.py',
'reader4.py',
'reader5.py',
'reader6.py',
'reader7.py',
'reader8.py',
'readererr.py',
'readernext.py',
'regexp.py',
'relaxng.py',
'resolver.py',
'schema.py',
'serialize.py',
'sync.py',
'thread2.py',
'tst.py',
'tstLastError.py',
'tstURI.py',
'tstmem.py',
'tstxpath.py',
'unicode.py',
'validDTD.py',
'validRNG.py',
'validSchemas.py',
'validate.py',
'walker.py',
'xpath.py',
'xpathext.py',
'xpathleak.py',
'xpathns.py',
'xpathret.py',
]
foreach file : python_tests
test(file, py, args: [ file ],
workdir: meson.current_source_dir() / 'tests',
env: { 'PYTHONPATH': meson.current_build_dir() })
endforeach
endif
+3
View File
@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
+255
View File
@@ -0,0 +1,255 @@
#!/usr/bin/env python3
#
# Setup script for libxml2 and libxslt if found
#
import sys, os
try:
from setuptools import setup, Extension
except ImportError:
try:
# Using distutils, for python < 3.12
from distutils.core import setup, Extension
except ImportError:
# distutils is not present in python 3.12 and greater
print("setuptools is required for python >= 3.12")
sys.exit(1)
# Below ROOT, we expect to find include, include/libxml2, lib and bin.
# On *nix, it is not needed (but should not harm),
# on Windows, it is set by configure.js.
ROOT = r'@prefix@'
# Thread-enabled libxml2
with_threads = @WITH_THREADS@
# Features of libxml2 requiring external DLLs
with_iconv = @WITH_ICONV@
with_zlib = @WITH_ZLIB@
with_icu = @WITH_ICU@
icu_series = 69
if icu_series is not None:
icu_series_s = str(icu_series)
else:
icu_series_s = ''
# If bundling DLLs, check the following to ensure things are correct
# (Check the value of `icu_series` above as well)
iconv_dll = 'iconv.dll'
zlib_dll = 'zlib1.dll'
icu_dlls = ['icuuc%s.dll' % icu_series_s, 'icudt%s.dll' % icu_series_s]
# If this flag is set (windows only),
# a private copy of the dlls are included in the package.
# If this flag is not set, the libxml2 and libxslt
# dlls must be found somewhere in the PATH at runtime.
WITHDLLS = 1 and sys.platform.startswith('win')
if WITHDLLS:
def altImport(s):
s = s.replace("import libxml2mod","from libxmlmods import libxml2mod")
return s
def missing(file):
if os.access(file, os.R_OK) == 0:
return 1
return 0
try:
HOME = os.environ['HOME']
except:
HOME="C:"
if sys.platform.startswith('win'):
libraryPrefix = 'lib'
platformLibs = []
else:
libraryPrefix = ''
platformLibs = ["m","z"]
# those are examined to find
# - libxml2/libxml/tree.h
# - libxslt/xsltconfig.h
includes_dir = [
"/usr/include",
"/usr/local/include",
"/opt/include",
os.path.join(ROOT,'include'),
HOME
];
xml_includes=""
for dir in includes_dir:
if not missing(dir + "/libxml2/libxml/tree.h"):
xml_includes=dir + "/libxml2"
break;
if xml_includes == "":
print("failed to find headers for libxml2: update includes_dir")
sys.exit(1)
# those are added in the linker search path for libraries
libdirs = [
os.path.join(ROOT,'lib'),
]
xml_files = ["libxml.c", "libxml.py", "libxml_wrap.h", "types.c",
"xmlgenerator.py", "README", "TODO", "drv_libxml2.py"]
xslt_files = ["libxslt-api.xml", "libxslt-python-api.xml",
"libxslt.c", "libxsl.py", "libxslt_wrap.h",
"xsltgenerator.py"]
if missing("libxml2-py.c") or missing("libxml2.py"):
try:
try:
import xmlgenerator
except:
import generator
except:
print("failed to find and generate stubs for libxml2, aborting ...")
print(sys.exc_info()[0], sys.exc_info()[1])
sys.exit(1)
with_xslt=0
if missing("libxslt-py.c") or missing("libxslt.py"):
if missing("xsltgenerator.py") or missing("libxslt-api.xml"):
print("libxslt stub generator not found, libxslt not built")
else:
try:
import xsltgenerator
except:
print("failed to generate stubs for libxslt, aborting ...")
print(sys.exc_info()[0], sys.exc_info()[1])
else:
head = open("libxsl.py", "r")
generated = open("libxsltclass.py", "r")
result = open("libxslt.py", "w")
for line in head.readlines():
if WITHDLLS:
result.write(altImport(line))
else:
result.write(line)
for line in generated.readlines():
result.write(line)
head.close()
generated.close()
result.close()
with_xslt=1
else:
with_xslt=1
if with_xslt == 1:
xslt_includes=""
for dir in includes_dir:
if not missing(dir + "/libxslt/xsltconfig.h"):
xslt_includes=dir + "/libxslt"
break;
if xslt_includes == "":
print("failed to find headers for libxslt: update includes_dir")
with_xslt = 0
if WITHDLLS:
# libxml dlls (expected in ROOT/bin)
dlls = [ 'libxml2.dll' ]
if with_zlib == 1:
dlls.append(zlib_dll)
if with_iconv == 1:
dlls.append(iconv_dll)
if with_icu == 1:
dlls += icu_dlls
if with_xslt == 1:
dlls += ['libxslt.dll','libexslt.dll']
packaged_dlls = [os.path.join(ROOT,'bin',dll) for dll in dlls]
# create __init__.py for the libxmlmods package
if not os.path.exists("libxmlmods"):
os.mkdir("libxmlmods")
open("libxmlmods/__init__.py","w").close()
packaged_dlls = [os.path.join(ROOT,'bin',dll) for dll in dlls]
descr = "libxml2 package"
modules = [ 'libxml2', 'drv_libxml2' ]
if WITHDLLS:
modules.append('libxmlmods.__init__')
c_files = ['libxml2-py.c', 'libxml.c', 'types.c' ]
includes= [xml_includes]
libs = [libraryPrefix + "xml2"] + platformLibs
macros = []
if with_threads:
macros.append(('_REENTRANT','1'))
if with_xslt == 1:
descr = "libxml2 and libxslt package"
if not sys.platform.startswith('win'):
#
# We are gonna build 2 identical shared libs with merge initializing
# both libxml2mod and libxsltmod
#
c_files = c_files + ['libxslt-py.c', 'libxslt.c']
xslt_c_files = c_files
macros.append(('MERGED_MODULES', '1'))
else:
#
# On windows the MERGED_MODULE option is not needed
# (and does not work)
#
xslt_c_files = ['libxslt-py.c', 'libxslt.c', 'types.c']
libs.insert(0, libraryPrefix + 'exslt')
libs.insert(0, libraryPrefix + 'xslt')
includes.append(xslt_includes)
modules.append('libxslt')
extens=[Extension('libxml2mod', c_files, include_dirs=includes,
library_dirs=libdirs,
libraries=libs, define_macros=macros)]
if with_xslt == 1:
extens.append(Extension('libxsltmod', xslt_c_files, include_dirs=includes,
library_dirs=libdirs,
libraries=libs, define_macros=macros))
if missing("MANIFEST"):
manifest = open("MANIFEST", "w")
manifest.write("setup.py\n")
for file in xml_files:
manifest.write(file + "\n")
if with_xslt == 1:
for file in xslt_files:
manifest.write(file + "\n")
manifest.close()
if WITHDLLS:
ext_package = "libxmlmods"
if sys.version >= "2.2":
base = "lib/site-packages/"
else:
base = ""
data_files = [(base+"libxmlmods",packaged_dlls)]
else:
ext_package = None
data_files = []
setup (name = "libxml2-python",
# On *nix, the version number is created from setup.py.in
# On windows, it is set by configure.js
version = "@LIBXML_VERSION@",
description = descr,
author = "Daniel Veillard",
author_email = "veillard@redhat.com",
url = "https://gitlab.gnome.org/GNOME/libxml2",
license="MIT License",
py_modules=modules,
ext_modules=extens,
ext_package=ext_package,
data_files=data_files,
)
sys.exit(0)
+77
View File
@@ -0,0 +1,77 @@
PYTESTS= \
build.py \
attribs.py \
tst.py \
tstxpath.py \
xpathext.py \
push.py \
pushSAX.py \
pushSAXhtml.py \
error.py \
serialize.py\
validate.py \
tstURI.py \
cutnpaste.py\
xpathret.py \
xpath.py \
outbuf.py \
inbuf.py \
input_callback.py \
resolver.py \
regexp.py \
reader.py \
reader2.py \
reader3.py \
reader4.py \
reader5.py \
reader6.py \
reader7.py \
reader8.py \
readernext.py \
walker.py \
nsdel.py \
ctxterror.py\
readererr.py\
relaxng.py \
schema.py \
thread2.py \
sync.py \
tstLastError.py \
indexes.py \
dtdvalid.py \
tstmem.py \
validDTD.py \
validSchemas.py \
validRNG.py \
compareNodes.py \
xpathns.py \
xpathleak.py \
unicode.py
XMLS= \
tst.xml \
valid.xml \
invalid.xml \
test.dtd
EXTRA_DIST = $(PYTESTS) $(XMLS) setup_test.py
CLEANFILES = core tmp.xml *.pyc
if WITH_PYTHON
check-local:
@for f in $(XMLS) ; do test -f $$f || $(LN_S) $(srcdir)/$$f . ; done
@echo "## running Python regression tests"
@(export PYTHONPATH="..:../.libs:$(srcdir)/..:$$PYTHONPATH" ; \
export LD_LIBRARY_PATH="$(top_builddir)/.libs:$$LD_LIBRARY_PATH" ; \
export DYLD_LIBRARY_PATH="$(top_builddir)/.libs:$$DYLD_LIBRARY_PATH" ; \
export PATH="$(top_builddir)/.libs:$$PATH" ; \
for test in $(PYTESTS) ; do \
log=`$(PYTHON) $(srcdir)/$$test` ; \
if [ "$$?" -ne 0 ] ; then \
echo "-- $$test" ; \
echo "$$log" ; \
exit 1 ; \
fi ; \
done)
endif
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
#
# Testing XML document serialization
#
doc = libxml2.readDoc(
"""<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE test [
<!ELEMENT test (#PCDATA) >
<!ATTLIST test xmlns:abc CDATA #FIXED "http://abc.org" >
<!ATTLIST test abc:attr CDATA #FIXED "def" >
]>
<test />
""", None, None, libxml2.XML_PARSE_DTDATTR)
elem = doc.getRootElement()
attr = elem.hasNsProp('attr', 'http://abc.org')
print(attr.serialize())
if attr == None:
print("Failed to find defaulted attribute abc:attr")
sys.exit(1)
doc.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
# Memory debug specific
libxml2.debugMemory(1)
doc = libxml2.newDoc("1.0")
comment = doc.newDocComment("This is a generated document")
doc.addChild(comment)
pi = libxml2.newPI("test", "PI content")
doc.addChild(pi)
root = doc.newChild(None, "doc", None)
ns = root.newNs("http://example.com/doc", "my")
root.setNs(ns)
elem = root.newChild(None, "foo", "bar")
elem.setBase("http://example.com/imgs")
elem.setProp("img", "image.gif")
doc.saveFile("tmp.xml")
doc.freeDoc()
doc = libxml2.parseFile("tmp.xml")
comment = doc.children
if comment.type != "comment" or \
comment.content != "This is a generated document":
print("error rereading comment")
sys.exit(1)
pi = comment.next
if pi.type != "pi" or pi.name != "test" or pi.content != "PI content":
print("error rereading PI")
sys.exit(1)
root = pi.next
if root.name != "doc":
print("error rereading root")
sys.exit(1)
ns = root.ns()
if ns.name != "my" or ns.content != "http://example.com/doc":
print("error rereading namespace")
sys.exit(1)
elem = root.children
if elem.name != "foo":
print("error rereading elem")
sys.exit(1)
if elem.getBase(None) != "http://example.com/imgs":
print("error rereading base")
sys.exit(1)
if elem.prop("img") != "image.gif":
print("error rereading property")
sys.exit(1)
doc.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
#
# Testing XML Node comparison and Node hash-value
#
doc = libxml2.parseDoc("""<root><foo/></root>""")
root = doc.getRootElement()
# Create two different objects which point to foo
foonode1 = root.children
foonode2 = root.children
# Now check that [in]equality tests work ok
if not ( foonode1 == foonode2 ):
print("Error comparing nodes with ==, nodes should be equal but are unequal")
sys.exit(1)
if not ( foonode1 != root ):
print("Error comparing nodes with ==, nodes should not be equal but are equal")
sys.exit(1)
if not ( foonode1 != root ):
print("Error comparing nodes with !=, nodes should not be equal but are equal")
if ( foonode1 != foonode2 ):
print("Error comparing nodes with !=, nodes should be equal but are unequal")
# Next check that the hash function for the objects also works ok
if not (hash(foonode1) == hash(foonode2)):
print("Error hash values for two equal nodes are different")
sys.exit(1)
if not (hash(foonode1) != hash(root)):
print("Error hash values for two unequal nodes are not different")
sys.exit(1)
if hash(foonode1) == hash(root):
print("Error hash values for two unequal nodes are equal")
sys.exit(1)
# Basic tests successful
doc.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
#
# This test exercise the redirection of error messages with a
# functions defined in Python.
#
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
expect="""--> (3) xmlns: URI foo is not absolute
--> (4) Opening and ending tag mismatch: x line 1 and y
"""
err=""
def callback(arg,msg,severity,reserved):
global err
err = err + "%s (%d) %s" % (arg,severity,msg)
s = """<x xmlns="foo"></y>"""
parserCtxt = libxml2.createPushParser(None,"",0,"test.xml")
parserCtxt.setErrorHandler(callback, "-->")
if parserCtxt.getErrorHandler() != (callback,"-->"):
print("getErrorHandler failed")
sys.exit(1)
parserCtxt.parseChunk(s,len(s),1)
doc = parserCtxt.doc()
doc.freeDoc()
parserCtxt = None
if err != expect:
print("error")
print("received %s" %(err))
print("expected %s" %(expect))
sys.exit(1)
i = 10000
while i > 0:
parserCtxt = libxml2.createPushParser(None,"",0,"test.xml")
parserCtxt.setErrorHandler(callback, "-->")
parserCtxt.parseChunk(s,len(s),1)
doc = parserCtxt.doc()
doc.freeDoc()
parserCtxt = None
err = ""
i = i - 1
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
#
# Testing XML document serialization
#
source = libxml2.parseDoc("""<?xml version="1.0"?>
<root xmlns:foo="http://example.org/foo"
xmlns:bar="http://example.org/bar">
<include xmlns="http://example.org/include">
<fragment><foo:elem bar="tricky"/></fragment>
</include>
</root>
""")
target = libxml2.parseDoc("""<?xml version="1.0"?>
<root xmlns:foobar="http://example.org/bar"/>""")
fragment = source.xpathEval("//*[name()='fragment']")[0]
dest = target.getRootElement()
# do a cut and paste operation
fragment.unlinkNode()
dest.addChild(fragment)
# do the namespace fixup
dest.reconciliateNs(target)
# The source tree can be freed at that point
source.freeDoc()
# check the resulting tree
str = dest.serialize()
if str != """<root xmlns:foobar="http://example.org/bar" xmlns:default="http://example.org/include" xmlns:foo="http://example.org/foo"><default:fragment><foo:elem bar="tricky"/></default:fragment></root>""":
print("reconciliateNs() failed")
sys.exit(1)
target.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
# Memory debug specific
libxml2.debugMemory(1)
dtd="""<!ELEMENT foo EMPTY>"""
instance="""<?xml version="1.0"?>
<foo></foo>"""
dtd = libxml2.parseDTD(None, 'test.dtd')
ctxt = libxml2.newValidCtxt()
doc = libxml2.parseDoc(instance)
ret = doc.validateDtd(ctxt, dtd)
if ret != 1:
print("error doing DTD validation")
sys.exit(1)
doc.freeDoc()
dtd.freeDtd()
del dtd
del ctxt
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
#
# This test exercise the redirection of error messages with a
# functions defined in Python.
#
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
expect='--> I/O --> warning : --> failed to load "missing.xml": No such file or directory\n'
err=""
def callback(ctx, str):
global err
err = err + "%s %s" % (ctx, str)
got_exc = 0
libxml2.registerErrorHandler(callback, "-->")
try:
doc = libxml2.parseFile("missing.xml")
except libxml2.parserError:
got_exc = 1
if got_exc == 0:
print("Failed to get a parser exception")
sys.exit(1)
if err != expect:
print("error")
print("received %s" %(err))
print("expected %s" %(expect))
sys.exit(1)
i = 10000
while i > 0:
try:
doc = libxml2.parseFile("missing.xml")
except libxml2.parserError:
got_exc = 1
err = ""
i = i - 1
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
i = 0
while i < 5000:
f = str_io("foobar")
buf = libxml2.inputBuffer(f)
i = i + 1
del f
del buf
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env python3
# -*- coding: ISO-8859-1 -*-
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
ctxt = None
class callback:
def __init__(self, startd, starte, ende, delta, endd):
self.startd = startd
self.starte = starte
self.ende = ende
self.endd = endd
self.delta = delta
self.count = 0
def startDocument(self):
global ctxt
if ctxt.byteConsumed() != self.startd:
print("document start at wrong index: %d expecting %d\n" % (
ctxt.byteConsumed(), self.startd))
sys.exit(1)
def endDocument(self):
global ctxt
expect = self.ende + self.delta * (self.count - 1) + self.endd
if ctxt.byteConsumed() != expect:
print("document end at wrong index: %d expecting %d\n" % (
ctxt.byteConsumed(), expect))
sys.exit(1)
def startElement(self, tag, attrs):
global ctxt
if tag == "bar1":
expect = self.starte + self.delta * self.count
if ctxt.byteConsumed() != expect:
print("element start at wrong index: %d expecting %d\n" % (
ctxt.byteConsumed(), expect))
sys.exit(1)
def endElement(self, tag):
global ctxt
if tag == "bar1":
expect = self.ende + self.delta * self.count
if ctxt.byteConsumed() != expect:
print("element end at wrong index: %d expecting %d\n" % (
ctxt.byteConsumed(), expect))
sys.exit(1)
self.count = self.count + 1
def characters(self, data):
pass
#
# First run a pure UTF-8 test
#
handler = callback(0, 13, 27, 198, 183)
ctxt = libxml2.createPushParser(handler, "<foo>\n", 6, "test.xml")
chunk = """ <bar1>chars1</bar1>
<bar2>chars2</bar2>
<bar3>chars3</bar3>
<bar4>chars4</bar4>
<bar5>chars5</bar5>
<bar6>&lt;s6</bar6>
<bar7>chars7</bar7>
<bar8>&#38;8</bar8>
<bar9>chars9</bar9>
"""
i = 0
while i < 10000:
ctxt.parseChunk(chunk, len(chunk), 0)
i = i + 1
chunk = "</foo>"
ctxt.parseChunk(chunk, len(chunk), 1)
ctxt=None
#
# Then run a test relying on ISO-Latin-1
#
handler = callback(43, 57, 71, 198, 183)
chunk="""<?xml version="1.0" encoding="ISO-8859-1"?>
<foo>
"""
ctxt = libxml2.createPushParser(handler, chunk, len(chunk), "test.xml")
chunk = """ <bar1>chars1</bar1>
<bar2>chars2</bar2>
<bar3>chars3</bar3>
<bar4>chàrs4</bar4>
<bar5>chars5</bar5>
<bar6>&lt;s6</bar6>
<bar7>chars7</bar7>
<bar8>&#38;8</bar8>
<bar9>très 9</bar9>
"""
i = 0
while i < 10000:
ctxt.parseChunk(chunk, len(chunk), 0)
i = i + 1
chunk = "</foo>"
ctxt.parseChunk(chunk, len(chunk), 1)
ctxt=None
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+149
View File
@@ -0,0 +1,149 @@
#!/usr/bin/env python3
#
# This tests custom input callbacks
#
import sys
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# We implement a new scheme, py://strings/ that will reference this dictionary
pystrings = {
'catalogs/catalog.xml' :
'''<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<rewriteSystem systemIdStartString="http://example.com/dtds/" rewritePrefix="../dtds/"/>
</catalog>''',
'xml/sample.xml' :
'''<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root SYSTEM "http://example.com/dtds/sample.dtd">
<root>&sample.entity;</root>''',
'dtds/sample.dtd' :
'''
<!ELEMENT root (#PCDATA)>
<!ENTITY sample.entity "replacement text">'''
}
prefix = "py://strings/"
startURL = prefix + "xml/sample.xml"
catURL = prefix + "catalogs/catalog.xml"
def my_input_cb(URI):
if not(URI.startswith(prefix)):
return None
path = URI[len(prefix):]
if path not in pystrings:
return None
return str_io(pystrings[path])
def run_test(desc, docpath, catalog, exp_status="verified", exp_err=[], test_callback=None,
root_name="root", root_content="replacement text"):
opts = libxml2.XML_PARSE_DTDLOAD | libxml2.XML_PARSE_NONET | libxml2.XML_PARSE_COMPACT
actual_err = []
def my_global_error_cb(ctx, msg):
actual_err.append((-1, msg))
def my_ctx_error_cb(arg, msg, severity, reserved):
actual_err.append((severity, msg))
libxml2.registerErrorHandler(my_global_error_cb, None)
try:
parser = libxml2.createURLParserCtxt(docpath, opts)
parser.setErrorHandler(my_ctx_error_cb, None)
if catalog is not None:
parser.addLocalCatalog(catalog)
if test_callback is not None:
test_callback()
parser.parseDocument()
doc = parser.doc()
actual_status = "loaded"
e = doc.getRootElement()
if e.name == root_name and e.content == root_content:
actual_status = "verified"
doc.freeDoc()
except libxml2.parserError:
actual_status = "not loaded"
if actual_status != exp_status:
print("Test '%s' failed: expect status '%s', actual '%s'" % (desc, exp_status, actual_status))
sys.exit(1)
elif actual_err != exp_err:
print("Test '%s' failed" % desc)
print("Expect errors:")
for s,m in exp_err: print(" [%2d] '%s'" % (s,m))
print("Actual errors:")
for s,m in actual_err: print(" [%2d] '%s'" % (s,m))
sys.exit(1)
# Check that we cannot read custom schema without custom callback
run_test(desc="Loading entity without custom callback",
docpath=startURL, catalog=None,
exp_status="not loaded", exp_err=[
(-1, "I/O "),
(-1, "warning : "),
(-1, "failed to load \"py://strings/xml/sample.xml\": No such file or directory\n")
])
# Register handler and try to load the same entity
libxml2.registerInputCallback(my_input_cb)
run_test(desc="Loading entity with custom callback",
docpath=startURL, catalog=None,
exp_status="loaded", exp_err=[
( 4, 'failed to load "http://example.com/dtds/sample.dtd": Attempt to load network entity\n'),
( 4, "Entity 'sample.entity' not defined\n")
])
# Register a catalog (also accessible via pystr://) and retry
run_test(desc="Loading entity with custom callback and catalog",
docpath=startURL, catalog=catURL)
# Unregister custom callback when parser is already created
run_test(desc="Loading entity and unregistering callback",
docpath=startURL, catalog=catURL,
test_callback=lambda: libxml2.popInputCallbacks(),
exp_status="loaded", exp_err=[
( 3, "failed to load \"py://strings/dtds/sample.dtd\": No such file or directory\n"),
( 4, "Entity 'sample.entity' not defined\n")
])
# Try to load the document again
run_test(desc="Retry loading document after unregistering callback",
docpath=startURL, catalog=catURL,
exp_status="not loaded", exp_err=[
(-1, "I/O "),
(-1, "warning : "),
(-1, "failed to load \"py://strings/xml/sample.xml\": No such file or directory\n")
])
# But should be able to read standard I/O yet...
run_test(desc="Loading using standard i/o after unregistering callback",
docpath="tst.xml", catalog=None,
root_name='doc', root_content='bar')
# Now pop ALL input callbacks, should fail to load even standard I/O
try:
while True:
libxml2.popInputCallbacks()
except IndexError:
pass
run_test(desc="Loading using standard i/o after unregistering all callbacks",
docpath="tst.xml", catalog=None,
exp_status="not loaded", exp_err=[
(-1, "I/O "),
(-1, "warning : "),
(-1, "failed to load \"tst.xml\": No such file or directory\n")
])
print("OK")
sys.exit(0);
+6
View File
@@ -0,0 +1,6 @@
<!DOCTYPE doc [
<!ELEMENT doc (a, b, a)>
<!ELEMENT a EMPTY>
<!ELEMENT b EMPTY>
]>
<doc><b/><a/><b/></doc>
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
#
# this test exercise the XPath basic engine, parser, etc, and
# allows to detect memory leaks
#
import sys
import setup_test
import libxml2
instance="""<?xml version="1.0"?>
<tag xmlns:foo='urn:foo' xmlns:bar='urn:bar' xmlns:baz='urn:baz' />"""
def namespaceDefs(node):
n = node.nsDefs()
while n:
yield n
n = n.next
def checkNamespaceDefs(node, count):
nsList = list(namespaceDefs(node))
#print nsList
if len(nsList) != count :
raise Exception("Error: saw %d namespace declarations. Expected %d" % (len(nsList), count))
# Memory debug specific
libxml2.debugMemory(1)
# Remove single namespace
doc = libxml2.parseDoc(instance)
node = doc.getRootElement()
checkNamespaceDefs(node, 3)
ns = node.removeNsDef('urn:bar')
checkNamespaceDefs(node, 2)
ns.freeNsList()
doc.freeDoc()
# Remove all namespaces
doc = libxml2.parseDoc(instance)
node = doc.getRootElement()
checkNamespaceDefs(node, 3)
ns = node.removeNsDef(None)
checkNamespaceDefs(node, 0)
ns.freeNsList()
doc.freeDoc()
# Remove a namespace referred to by a child
doc = libxml2.newDoc("1.0")
root = doc.newChild(None, "root", None)
namespace = root.newNs("http://example.com/sample", "s")
child = root.newChild(namespace, "child", None)
root.removeNsDef("http://example.com/sample")
doc.reconciliateNs(root)
namespace.freeNsList()
doc.serialize() # This should not segfault
doc.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+110
View File
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
def testSimpleBufferWrites():
f = str_io()
buf = libxml2.createOutputBuffer(f, "ISO-8859-1")
buf.write(3, "foo")
buf.writeString("bar")
buf.close()
if f.getvalue() != "foobar":
print("Failed to save to StringIO")
sys.exit(1)
def testSaveDocToBuffer():
"""
Regression test for bug #154294.
"""
input = '<foo>Hello</foo>'
expected = '''\
<?xml version="1.0" encoding="UTF-8"?>
<foo>Hello</foo>
'''
f = str_io()
buf = libxml2.createOutputBuffer(f, 'UTF-8')
doc = libxml2.parseDoc(input)
doc.saveFileTo(buf, 'UTF-8')
doc.freeDoc()
if f.getvalue() != expected:
print('xmlDoc.saveFileTo() call failed.')
print(' got: %s' % repr(f.getvalue()))
print('expected: %s' % repr(expected))
sys.exit(1)
def testSaveFormattedDocToBuffer():
input = '<outer><inner>Some text</inner><inner/></outer>'
# The formatted and non-formatted versions of the output.
expected = ('''\
<?xml version="1.0" encoding="UTF-8"?>
<outer><inner>Some text</inner><inner/></outer>
''', '''\
<?xml version="1.0" encoding="UTF-8"?>
<outer>
<inner>Some text</inner>
<inner/>
</outer>
''')
doc = libxml2.parseDoc(input)
for i in (0, 1):
f = str_io()
buf = libxml2.createOutputBuffer(f, 'UTF-8')
doc.saveFormatFileTo(buf, 'UTF-8', i)
if f.getvalue() != expected[i]:
print('xmlDoc.saveFormatFileTo() call failed.')
print(' got: %s' % repr(f.getvalue()))
print('expected: %s' % repr(expected[i]))
sys.exit(1)
doc.freeDoc()
def testSaveIntoOutputBuffer():
"""
Similar to the previous two tests, except this time we invoke the save
methods on the output buffer object and pass in an XML node object.
"""
input = '<foo>Hello</foo>'
expected = '''\
<?xml version="1.0" encoding="UTF-8"?>
<foo>Hello</foo>
'''
f = str_io()
doc = libxml2.parseDoc(input)
buf = libxml2.createOutputBuffer(f, 'UTF-8')
buf.saveFileTo(doc, 'UTF-8')
if f.getvalue() != expected:
print('outputBuffer.saveFileTo() call failed.')
print(' got: %s' % repr(f.getvalue()))
print('expected: %s' % repr(expected))
sys.exit(1)
f = str_io()
buf = libxml2.createOutputBuffer(f, 'UTF-8')
buf.saveFormatFileTo(doc, 'UTF-8', 1)
if f.getvalue() != expected:
print('outputBuffer.saveFormatFileTo() call failed.')
print(' got: %s' % repr(f.getvalue()))
print('expected: %s' % repr(expected))
sys.exit(1)
doc.freeDoc()
if __name__ == '__main__':
# Memory debug specific
libxml2.debugMemory(1)
testSimpleBufferWrites()
testSaveDocToBuffer()
testSaveFormattedDocToBuffer()
testSaveIntoOutputBuffer()
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
ctxt = libxml2.createPushParser(None, "<foo", 4, "test.xml")
ctxt.parseChunk("/>", 2, 1)
doc = ctxt.doc()
ctxt=None
if doc.name != "test.xml":
print("document name error")
sys.exit(1)
root = doc.children
if root.name != "foo":
print("root element name error")
sys.exit(1)
doc.freeDoc()
i = 10000
while i > 0:
ctxt = libxml2.createPushParser(None, "<foo", 4, "test.xml")
ctxt.parseChunk("/>", 2, 1)
doc = ctxt.doc()
doc.freeDoc()
i = i -1
ctxt=None
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
log = ""
class callback:
def startDocument(self):
global log
log = log + "startDocument:"
def endDocument(self):
global log
log = log + "endDocument:"
def startElement(self, tag, attrs):
global log
log = log + "startElement %s %s:" % (tag, attrs)
def endElement(self, tag):
global log
log = log + "endElement %s:" % (tag)
def characters(self, data):
global log
log = log + "characters: %s:" % (data)
def warning(self, msg):
global log
log = log + "warning: %s:" % (msg)
def error(self, msg):
global log
log = log + "error: %s:" % (msg)
def fatalError(self, msg):
global log
log = log + "fatalError: %s:" % (msg)
handler = callback()
ctxt = libxml2.createPushParser(handler, "<foo", 4, "test.xml")
chunk = " url='tst'>b"
ctxt.parseChunk(chunk, len(chunk), 0)
chunk = "ar</foo>"
ctxt.parseChunk(chunk, len(chunk), 1)
ctxt=None
reference = "startDocument:startElement foo {'url': 'tst'}:characters: bar:endElement foo:endDocument:"
if log != reference:
print("Error got: %s" % log)
print("Exprected: %s" % reference)
sys.exit(1)
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
log = ""
class callback:
def startDocument(self):
global log
log = log + "startDocument:"
def endDocument(self):
global log
log = log + "endDocument:"
def startElement(self, tag, attrs):
global log
log = log + "startElement %s %s:" % (tag, attrs)
def endElement(self, tag):
global log
log = log + "endElement %s:" % (tag)
def characters(self, data):
global log
log = log + "characters: %s:" % (data)
def warning(self, msg):
global log
log = log + "warning: %s:" % (msg)
def error(self, msg):
global log
log = log + "error: %s:" % (msg)
def fatalError(self, msg):
global log
log = log + "fatalError: %s:" % (msg)
handler = callback()
ctxt = libxml2.htmlCreatePushParser(handler, "<foo", 4, "test.xml")
chunk = " url='tst'>b"
ctxt.htmlParseChunk(chunk, len(chunk), 0)
chunk = "ar</foo>"
ctxt.htmlParseChunk(chunk, len(chunk), 1)
ctxt=None
reference = """startDocument:startElement html None:startElement body None:startElement foo {'url': 'tst'}:characters: bar:endElement foo:endElement body:endElement html:endDocument:"""
if log != reference:
print("Error got: %s" % log)
print("Exprected: %s" % reference)
sys.exit(1)
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+446
View File
@@ -0,0 +1,446 @@
#!/usr/bin/env python3
# -*- coding: ISO-8859-1 -*-
#
# this tests the basic APIs of the XmlTextReader interface
#
import setup_test
import libxml2
import sys
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
f = str_io("""<a><b b1="b1"/><c>content of c</c></a>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test1")
ret = reader.Read()
if ret != 1:
print("test1: Error reading to first element")
sys.exit(1)
if reader.Name() != "a" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 1 or reader.HasAttributes() != 0:
print("test1: Error reading the first element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test1: Error reading to second element")
sys.exit(1)
if reader.Name() != "b" or reader.IsEmptyElement() != 1 or \
reader.NodeType() != 1 or reader.HasAttributes() != 1:
print("test1: Error reading the second element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test1: Error reading to third element")
sys.exit(1)
if reader.Name() != "c" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 1 or reader.HasAttributes() != 0:
print("test1: Error reading the third element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test1: Error reading to text node")
sys.exit(1)
if reader.Name() != "#text" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 3 or reader.HasAttributes() != 0 or \
reader.Value() != "content of c":
print("test1: Error reading the text node")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test1: Error reading to end of third element")
sys.exit(1)
if reader.Name() != "c" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 15 or reader.HasAttributes() != 0:
print("test1: Error reading the end of third element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test1: Error reading to end of first element")
sys.exit(1)
if reader.Name() != "a" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 15 or reader.HasAttributes() != 0:
print("test1: Error reading the end of first element")
sys.exit(1)
ret = reader.Read()
if ret != 0:
print("test1: Error reading to end of document")
sys.exit(1)
#
# example from the XmlTextReader docs
#
f = str_io("""<test xmlns:dt="urn:datatypes" dt:type="int"/>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test2")
ret = reader.Read()
if ret != 1:
print("Error reading test element")
sys.exit(1)
if reader.GetAttributeNo(0) != "urn:datatypes" or \
reader.GetAttributeNo(1) != "int" or \
reader.GetAttributeNs("type", "urn:datatypes") != "int" or \
reader.GetAttribute("dt:type") != "int":
print("error reading test attributes")
sys.exit(1)
#
# example from the XmlTextReader docs
#
f = str_io("""<root xmlns:a="urn:456">
<item>
<ref href="a:b"/>
</item>
</root>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test3")
ret = reader.Read()
while ret == 1:
if reader.Name() == "ref":
if reader.LookupNamespace("a") != "urn:456":
print("error resolving namespace prefix")
sys.exit(1)
break
ret = reader.Read()
if ret != 1:
print("Error finding the ref element")
sys.exit(1)
#
# Home made example for the various attribute access functions
#
f = str_io("""<testattr xmlns="urn:1" xmlns:a="urn:2" b="b" a:b="a:b"/>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test4")
ret = reader.Read()
if ret != 1:
print("Error reading the testattr element")
sys.exit(1)
#
# Attribute exploration by index
#
if reader.MoveToAttributeNo(0) != 1:
print("Failed moveToAttribute(0)")
sys.exit(1)
if reader.Value() != "urn:1":
print("Failed to read attribute(0)")
sys.exit(1)
if reader.Name() != "xmlns":
print("Failed to read attribute(0) name")
sys.exit(1)
if reader.MoveToAttributeNo(1) != 1:
print("Failed moveToAttribute(1)")
sys.exit(1)
if reader.Value() != "urn:2":
print("Failed to read attribute(1)")
sys.exit(1)
if reader.Name() != "xmlns:a":
print("Failed to read attribute(1) name")
sys.exit(1)
if reader.MoveToAttributeNo(2) != 1:
print("Failed moveToAttribute(2)")
sys.exit(1)
if reader.Value() != "b":
print("Failed to read attribute(2)")
sys.exit(1)
if reader.Name() != "b":
print("Failed to read attribute(2) name")
sys.exit(1)
if reader.MoveToAttributeNo(3) != 1:
print("Failed moveToAttribute(3)")
sys.exit(1)
if reader.Value() != "a:b":
print("Failed to read attribute(3)")
sys.exit(1)
if reader.Name() != "a:b":
print("Failed to read attribute(3) name")
sys.exit(1)
#
# Attribute exploration by name
#
if reader.MoveToAttribute("xmlns") != 1:
print("Failed moveToAttribute('xmlns')")
sys.exit(1)
if reader.Value() != "urn:1":
print("Failed to read attribute('xmlns')")
sys.exit(1)
if reader.MoveToAttribute("xmlns:a") != 1:
print("Failed moveToAttribute('xmlns')")
sys.exit(1)
if reader.Value() != "urn:2":
print("Failed to read attribute('xmlns:a')")
sys.exit(1)
if reader.MoveToAttribute("b") != 1:
print("Failed moveToAttribute('b')")
sys.exit(1)
if reader.Value() != "b":
print("Failed to read attribute('b')")
sys.exit(1)
if reader.MoveToAttribute("a:b") != 1:
print("Failed moveToAttribute('a:b')")
sys.exit(1)
if reader.Value() != "a:b":
print("Failed to read attribute('a:b')")
sys.exit(1)
if reader.MoveToAttributeNs("b", "urn:2") != 1:
print("Failed moveToAttribute('b', 'urn:2')")
sys.exit(1)
if reader.Value() != "a:b":
print("Failed to read attribute('b', 'urn:2')")
sys.exit(1)
#
# Go back and read in sequence
#
if reader.MoveToElement() != 1:
print("Failed to move back to element")
sys.exit(1)
if reader.MoveToFirstAttribute() != 1:
print("Failed to move to first attribute")
sys.exit(1)
if reader.Value() != "urn:1":
print("Failed to read attribute(0)")
sys.exit(1)
if reader.Name() != "xmlns":
print("Failed to read attribute(0) name")
sys.exit(1)
if reader.MoveToNextAttribute() != 1:
print("Failed to move to next attribute")
sys.exit(1)
if reader.Value() != "urn:2":
print("Failed to read attribute(1)")
sys.exit(1)
if reader.Name() != "xmlns:a":
print("Failed to read attribute(1) name")
sys.exit(1)
if reader.MoveToNextAttribute() != 1:
print("Failed to move to next attribute")
sys.exit(1)
if reader.Value() != "b":
print("Failed to read attribute(2)")
sys.exit(1)
if reader.Name() != "b":
print("Failed to read attribute(2) name")
sys.exit(1)
if reader.MoveToNextAttribute() != 1:
print("Failed to move to next attribute")
sys.exit(1)
if reader.Value() != "a:b":
print("Failed to read attribute(3)")
sys.exit(1)
if reader.Name() != "a:b":
print("Failed to read attribute(3) name")
sys.exit(1)
if reader.MoveToNextAttribute() != 0:
print("Failed to detect last attribute")
sys.exit(1)
#
# a couple of tests for namespace nodes
#
f = str_io("""<a xmlns="http://example.com/foo"/>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test6")
ret = reader.Read()
if ret != 1:
print("test6: failed to Read()")
sys.exit(1)
ret = reader.MoveToFirstAttribute()
if ret != 1:
print("test6: failed to MoveToFirstAttribute()")
sys.exit(1)
if reader.NamespaceUri() != "http://www.w3.org/2000/xmlns/" or \
reader.LocalName() != "xmlns" or reader.Name() != "xmlns" or \
reader.Value() != "http://example.com/foo" or reader.NodeType() != 2:
print("test6: failed to read the namespace node")
sys.exit(1)
f = str_io("""<a xmlns:prefix="http://example.com/foo"/>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test7")
ret = reader.Read()
if ret != 1:
print("test7: failed to Read()")
sys.exit(1)
ret = reader.MoveToFirstAttribute()
if ret != 1:
print("test7: failed to MoveToFirstAttribute()")
sys.exit(1)
if reader.NamespaceUri() != "http://www.w3.org/2000/xmlns/" or \
reader.LocalName() != "prefix" or reader.Name() != "xmlns:prefix" or \
reader.Value() != "http://example.com/foo" or reader.NodeType() != 2:
print("test7: failed to read the namespace node")
sys.exit(1)
#
# Test for a limit case:
#
f = str_io("""<a/>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test8")
ret = reader.Read()
if ret != 1:
print("test8: failed to read the node")
sys.exit(1)
if reader.Name() != "a" or reader.IsEmptyElement() != 1:
print("test8: failed to analyze the node")
sys.exit(1)
ret = reader.Read()
if ret != 0:
print("test8: failed to detect the EOF")
sys.exit(1)
#
# Another test provided by Stéphane Bidoul and checked with C#
#
def tst_reader(s):
f = str_io(s)
input = libxml2.inputBuffer(f)
reader = input.newTextReader("tst")
res = ""
while reader.Read():
res=res + "%s (%s) [%s] %d %d\n" % (reader.NodeType(),reader.Name(),
reader.Value(), reader.IsEmptyElement(),
reader.Depth())
if reader.NodeType() == 1: # Element
while reader.MoveToNextAttribute():
res = res + "-- %s (%s) [%s] %d %d\n" % (reader.NodeType(),
reader.Name(),reader.Value(),
reader.IsEmptyElement(), reader.Depth())
return res
doc="""<a><b b1="b1"/><c>content of c</c></a>"""
expect="""1 (a) [None] 0 0
1 (b) [None] 1 1
-- 2 (b1) [b1] 0 2
1 (c) [None] 0 1
3 (#text) [content of c] 0 2
15 (c) [None] 0 1
15 (a) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test5 failed")
print(res)
sys.exit(1)
doc="""<test><b/><c/></test>"""
expect="""1 (test) [None] 0 0
1 (b) [None] 1 1
1 (c) [None] 1 1
15 (test) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test9 failed")
print(res)
sys.exit(1)
doc="""<a><b>bbb</b><c>ccc</c></a>"""
expect="""1 (a) [None] 0 0
1 (b) [None] 0 1
3 (#text) [bbb] 0 2
15 (b) [None] 0 1
1 (c) [None] 0 1
3 (#text) [ccc] 0 2
15 (c) [None] 0 1
15 (a) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test10 failed")
print(res)
sys.exit(1)
doc="""<test a="a"/>"""
expect="""1 (test) [None] 1 0
-- 2 (a) [a] 0 1
"""
res = tst_reader(doc)
if res != expect:
print("test11 failed")
print(res)
sys.exit(1)
doc="""<test><a>aaa</a><b/></test>"""
expect="""1 (test) [None] 0 0
1 (a) [None] 0 1
3 (#text) [aaa] 0 2
15 (a) [None] 0 1
1 (b) [None] 1 1
15 (test) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test12 failed")
print(res)
sys.exit(1)
doc="""<test><p></p></test>"""
expect="""1 (test) [None] 0 0
1 (p) [None] 0 1
15 (p) [None] 0 1
15 (test) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test13 failed")
print(res)
sys.exit(1)
doc="""<p></p>"""
expect="""1 (p) [None] 0 0
15 (p) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test14 failed")
print(res)
sys.exit(1)
#
# test from bug #108801
#
doc="""<?xml version="1.0" standalone="no"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
]>
<article>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</article>
"""
expect="""10 (article) [None] 0 0
1 (article) [None] 0 0
3 (#text) [
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
] 0 1
15 (article) [None] 0 0
"""
res = tst_reader(doc)
if res != expect:
print("test15 failed")
print(res)
sys.exit(1)
#
# cleanup for memory allocation counting
#
del f
del input
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+337
View File
@@ -0,0 +1,337 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# this tests the DTD validation with the XmlTextReader interface
#
import sys
import glob
import os
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
err = ""
basedir = os.path.dirname(os.path.realpath(__file__))
dir_prefix = os.path.realpath(os.path.join(basedir, "..", "..", "test", "valid"))
# This dictionary reflects the contents of the files
# ../../test/valid/*.xml.err that are not empty, except that
# the file paths in the messages start with ../../test/
expect = {
'766956':
"""{0}/dtds/766956.dtd:2: parser error : PEReference: expecting ';'
%ä%ent;
^
{0}/dtds/766956.dtd:2: parser error : Content error in the external subset
%ä%ent;
^
Entity: line 1:
value
^
""".format(dir_prefix),
'781333':
"""{0}/781333.xml:4: element a: validity error : Element a content does not follow the DTD, expecting ( ..., got
<a/>
^
{0}/781333.xml:5: element a: validity error : Element a content does not follow the DTD, Expecting more children
^
""".format(dir_prefix),
'cond_sect2':
"""{0}/dtds/cond_sect2.dtd:15: parser error : Parameter entity must match extSubsetDecl
%ent;
^
Entity: line 1:
]]>
^
{0}/dtds/cond_sect2.dtd:15: parser error : Content error in the external subset
%ent;
^
Entity: line 1:
]]>
^
""".format(dir_prefix),
'rss':
"""{0}/rss.xml:177: element rss: validity error : Element rss does not carry attribute version
</rss>
^
""".format(dir_prefix),
't8':
"""{0}/t8.xml:6: parser error : Content error in the internal subset
%defroot; %defmiddle; %deftest;
^
Entity: line 1:
&lt;!ELEMENT root (middle) >
^
""".format(dir_prefix),
't8a':
"""{0}/t8a.xml:6: parser error : Content error in the internal subset
%defroot;%defmiddle;%deftest;
^
Entity: line 1:
&lt;!ELEMENT root (middle) >
^
""".format(dir_prefix),
'xlink':
"""{0}/xlink.xml:450: element termdef: validity error : ID dt-arc already defined
<p><termdef id="dt-arc" term="Arc">An <ter
^
validity error : attribute def line 199 references an unknown ID "dt-xlg"
""".format(dir_prefix),
}
# Add prefix_dir and extension to the keys
expect = {os.path.join(dir_prefix, key + ".xml"): val for key, val in expect.items()}
def callback(ctx, str):
global err
err = err + "%s" % (str)
libxml2.registerErrorHandler(callback, "")
parsing_error_files = ["766956", "cond_sect2", "t8", "t8a", "pe-in-text-decl"]
expect_parsing_error = [os.path.join(dir_prefix, f + ".xml") for f in parsing_error_files]
valid_files = glob.glob(os.path.join(dir_prefix, "*.x*"))
assert valid_files, "found no valid files in '{}'".format(dir_prefix)
valid_files.sort()
failures = 0
for file in valid_files:
err = ""
reader = libxml2.newTextReaderFilename(file)
#print "%s:" % (file)
reader.SetParserProp(libxml2.PARSER_VALIDATE, 1)
ret = reader.Read()
while ret == 1:
ret = reader.Read()
if ret != 0 and file not in expect_parsing_error:
print("Error parsing and validating %s" % (file))
#sys.exit(1)
if file in expect and err != expect[file]:
failures += 1
print("Error: ", err)
if file in expect:
print("Expected: ", expect[file])
if failures:
print("Failed %d tests" % failures)
sys.exit(1)
#
# another separate test based on Stephane Bidoul one
#
s = """
<!DOCTYPE test [
<!ELEMENT test (x,b)>
<!ELEMENT x (c)>
<!ELEMENT b (#PCDATA)>
<!ELEMENT c (#PCDATA)>
<!ENTITY x "<x><c>xxx</c></x>">
]>
<test>
&x;
<b>bbb</b>
</test>
"""
expect="""10,test
1,test
14,#text
1,x
1,c
3,#text
15,c
15,x
14,#text
1,b
3,#text
15,b
14,#text
15,test
"""
res=""
err=""
input = libxml2.inputBuffer(str_io(s))
reader = input.newTextReader("test2")
reader.SetParserProp(libxml2.PARSER_LOADDTD,1)
reader.SetParserProp(libxml2.PARSER_DEFAULTATTRS,1)
reader.SetParserProp(libxml2.PARSER_SUBST_ENTITIES,1)
reader.SetParserProp(libxml2.PARSER_VALIDATE,1)
while reader.Read() == 1:
res = res + "%s,%s\n" % (reader.NodeType(),reader.Name())
if res != expect:
print("test2 failed: unexpected output")
print(res)
sys.exit(1)
if err != "":
print("test2 failed: validation error found")
print(err)
sys.exit(1)
#
# Another test for external entity parsing and validation
#
s = """<!DOCTYPE test [
<!ELEMENT test (x)>
<!ELEMENT x (#PCDATA)>
<!ENTITY e SYSTEM "tst.ent">
]>
<test>
&e;
</test>
"""
tst_ent = """<x>hello</x>"""
expect="""10 test
1 test
14 #text
1 x
3 #text
15 x
14 #text
15 test
"""
res=""
def myResolver(URL, ID, ctxt):
if URL == "tst.ent":
return(str_io(tst_ent))
return None
libxml2.setEntityLoader(myResolver)
input = libxml2.inputBuffer(str_io(s))
reader = input.newTextReader("test3")
reader.SetParserProp(libxml2.PARSER_LOADDTD,1)
reader.SetParserProp(libxml2.PARSER_DEFAULTATTRS,1)
reader.SetParserProp(libxml2.PARSER_SUBST_ENTITIES,1)
reader.SetParserProp(libxml2.PARSER_VALIDATE,1)
while reader.Read() == 1:
res = res + "%s %s\n" % (reader.NodeType(),reader.Name())
if res != expect:
print("test3 failed: unexpected output")
print(res)
sys.exit(1)
if err != "":
print("test3 failed: validation error found")
print(err)
sys.exit(1)
#
# Another test for recursive entity parsing, validation, and replacement of
# entities, making sure the entity ref node doesn't show up in that case
#
s = """<!DOCTYPE test [
<!ELEMENT test (x, x)>
<!ELEMENT x (y)>
<!ELEMENT y (#PCDATA)>
<!ENTITY x "<x>&y;</x>">
<!ENTITY y "<y>yyy</y>">
]>
<test>
&x;
&x;
</test>"""
expect="""10 test 0
1 test 0
14 #text 1
1 x 1
1 y 2
3 #text 3
15 y 2
15 x 1
14 #text 1
1 x 1
1 y 2
3 #text 3
15 y 2
15 x 1
14 #text 1
15 test 0
"""
res=""
err=""
input = libxml2.inputBuffer(str_io(s))
reader = input.newTextReader("test4")
reader.SetParserProp(libxml2.PARSER_LOADDTD,1)
reader.SetParserProp(libxml2.PARSER_DEFAULTATTRS,1)
reader.SetParserProp(libxml2.PARSER_SUBST_ENTITIES,1)
reader.SetParserProp(libxml2.PARSER_VALIDATE,1)
while reader.Read() == 1:
res = res + "%s %s %d\n" % (reader.NodeType(),reader.Name(),reader.Depth())
if res != expect:
print("test4 failed: unexpected output")
print(res)
sys.exit(1)
if err != "":
print("test4 failed: validation error found")
print(err)
sys.exit(1)
#
# The same test but without entity substitution this time
#
s = """<!DOCTYPE test [
<!ELEMENT test (x, x)>
<!ELEMENT x (y)>
<!ELEMENT y (#PCDATA)>
<!ENTITY x "<x>&y;</x>">
<!ENTITY y "<y>yyy</y>">
]>
<test>
&x;
&x;
</test>"""
expect="""10 test 0
1 test 0
14 #text 1
5 x 1
14 #text 1
5 x 1
14 #text 1
15 test 0
"""
res=""
err=""
input = libxml2.inputBuffer(str_io(s))
reader = input.newTextReader("test5")
reader.SetParserProp(libxml2.PARSER_VALIDATE,1)
while reader.Read() == 1:
res = res + "%s %s %d\n" % (reader.NodeType(),reader.Name(),reader.Depth())
if res != expect:
print("test5 failed: unexpected output")
print(res)
sys.exit(1)
if err != "":
print("test5 failed: validation error found")
print(err)
sys.exit(1)
#
# cleanup
#
del input
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
#
# this tests the entities substitutions with the XmlTextReader interface
#
import sys
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
docstr="""<?xml version='1.0'?>
<!DOCTYPE doc [
<!ENTITY tst "<p>test</p>">
]>
<doc>&tst;</doc>"""
# Memory debug specific
libxml2.debugMemory(1)
#
# First test, normal don't substitute entities.
#
f = str_io(docstr)
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test_noent")
ret = reader.Read()
if ret != 1:
print("Error reading to root")
sys.exit(1)
if reader.Name() == "doc" or reader.NodeType() == 10:
ret = reader.Read()
if ret != 1:
print("Error reading to root")
sys.exit(1)
if reader.Name() != "doc" or reader.NodeType() != 1:
print("test_normal: Error reading the root element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_normal: Error reading to the entity")
sys.exit(1)
if reader.Name() != "tst" or reader.NodeType() != 5:
print("test_normal: Error reading the entity")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_normal: Error reading to the end of root")
sys.exit(1)
if reader.Name() != "doc" or reader.NodeType() != 15:
print("test_normal: Error reading the end of the root element")
sys.exit(1)
ret = reader.Read()
if ret != 0:
print("test_normal: Error detecting the end")
sys.exit(1)
#
# Second test, completely substitute the entities.
#
f = str_io(docstr)
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test_noent")
reader.SetParserProp(libxml2.PARSER_SUBST_ENTITIES, 1)
ret = reader.Read()
if ret != 1:
print("Error reading to root")
sys.exit(1)
if reader.Name() == "doc" or reader.NodeType() == 10:
ret = reader.Read()
if ret != 1:
print("Error reading to root")
sys.exit(1)
if reader.Name() != "doc" or reader.NodeType() != 1:
print("test_noent: Error reading the root element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_noent: Error reading to the entity content")
sys.exit(1)
if reader.Name() != "p" or reader.NodeType() != 1:
print("test_noent: Error reading the p element from entity")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_noent: Error reading to the text node")
sys.exit(1)
if reader.NodeType() != 3 or reader.Value() != "test":
print("test_noent: Error reading the text node")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_noent: Error reading to the end of p element")
sys.exit(1)
if reader.Name() != "p" or reader.NodeType() != 15:
print("test_noent: Error reading the end of the p element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_noent: Error reading to the end of root")
sys.exit(1)
if reader.Name() != "doc" or reader.NodeType() != 15:
print("test_noent: Error reading the end of the root element")
sys.exit(1)
ret = reader.Read()
if ret != 0:
print("test_noent: Error detecting the end")
sys.exit(1)
#
# third test, crazy stuff about empty element in external parsed entities
#
s = """<!DOCTYPE struct [
<!ENTITY simplestruct2.ent SYSTEM "simplestruct2.ent">
]>
<struct>&simplestruct2.ent;</struct>
"""
expect="""10 struct 0 0
1 struct 0 0
1 descr 1 1
15 struct 0 0
"""
res=""
simplestruct2_ent="""<descr/>"""
def myResolver(URL, ID, ctxt):
if URL == "simplestruct2.ent":
return(str_io(simplestruct2_ent))
return None
libxml2.setEntityLoader(myResolver)
input = libxml2.inputBuffer(str_io(s))
reader = input.newTextReader("test3")
reader.SetParserProp(libxml2.PARSER_SUBST_ENTITIES,1)
while reader.Read() == 1:
res = res + "%s %s %d %d\n" % (reader.NodeType(),reader.Name(),
reader.Depth(),reader.IsEmptyElement())
if res != expect:
print("test3 failed: unexpected output")
print(res)
sys.exit(1)
#
# cleanup
#
del f
del input
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
#
# this tests the basic APIs of the XmlTextReader interface
#
import setup_test
import libxml2
import sys
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
def tst_reader(s):
f = str_io(s)
input = libxml2.inputBuffer(f)
reader = input.newTextReader("tst")
res = ""
while reader.Read():
res=res + "%s (%s) [%s] %d\n" % (reader.NodeType(),reader.Name(),
reader.Value(), reader.IsEmptyElement())
if reader.NodeType() == 1: # Element
while reader.MoveToNextAttribute():
res = res + "-- %s (%s) [%s]\n" % (reader.NodeType(),
reader.Name(),reader.Value())
return res
expect="""1 (test) [None] 0
1 (b) [None] 1
1 (c) [None] 1
15 (test) [None] 0
"""
res = tst_reader("""<test><b/><c/></test>""")
if res != expect:
print("Did not get the expected error message:")
print(res)
sys.exit(1)
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
#
# this tests the Expand() API of the xmlTextReader interface
# this extract the Dragon bibliography entries from the XML specification
#
import setup_test
import libxml2
import os
import sys
# Memory debug specific
libxml2.debugMemory(1)
expect="""<bibl id="Aho" key="Aho/Ullman">Aho, Alfred V.,
Ravi Sethi, and Jeffrey D. Ullman.
<emph>Compilers: Principles, Techniques, and Tools</emph>.
Reading: Addison-Wesley, 1986, rpt. corr. 1988.</bibl>"""
basedir = os.path.dirname(os.path.realpath(__file__))
f = open(os.path.join(basedir, '../../test/valid/REC-xml-19980210.xml'), 'rb')
input = libxml2.inputBuffer(f)
reader = input.newTextReader("REC")
res=""
while reader.Read() > 0:
while reader.Name() == 'bibl':
node = reader.Expand() # expand the subtree
if node.xpathEval("@id = 'Aho'"): # use XPath on it
res = res + node.serialize()
if reader.Next() != 1: # skip the subtree
break;
if res != expect:
print("Error: didn't get the expected output")
print("got '%s'" % (res))
print("expected '%s'" % (expect))
#
# cleanup
#
del input
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env python3
#
# this tests the entities substitutions with the XmlTextReader interface
#
import sys
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
schema="""<element name="foo" xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<oneOrMore>
<element name="label">
<text/>
</element>
<optional>
<element name="opt">
<empty/>
</element>
</optional>
<element name="item">
<data type="byte"/>
</element>
</oneOrMore>
</element>
"""
# Memory debug specific
libxml2.debugMemory(1)
#
# Parse the Relax NG Schemas
#
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
rngs = rngp.relaxNGParse()
del rngp
#
# Parse and validate the correct document
#
docstr="""<foo>
<label>some text</label>
<item>100</item>
</foo>"""
f = str_io(docstr)
input = libxml2.inputBuffer(f)
reader = input.newTextReader("correct")
reader.RelaxNGSetSchema(rngs)
ret = reader.Read()
while ret == 1:
ret = reader.Read()
if ret != 0:
print("Error parsing the document")
sys.exit(1)
if reader.IsValid() != 1:
print("Document failed to validate")
sys.exit(1)
#
# Parse and validate the incorrect document
#
docstr="""<foo>
<label>some text</label>
<item>1000</item>
</foo>"""
err=""
# RNG errors are not as good as before , TODO
#expect="""RNG validity error: file error line 3 element text
#Type byte doesn't allow value '1000'
#RNG validity error: file error line 3 element text
#Error validating datatype byte
#RNG validity error: file error line 3 element text
#Element item failed to validate content
#"""
expect="""Type byte doesn't allow value '1000'
Error validating datatype byte
Element item failed to validate content
"""
def callback(ctx, str):
global err
err = err + "%s" % (str)
libxml2.registerErrorHandler(callback, "")
f = str_io(docstr)
input = libxml2.inputBuffer(f)
reader = input.newTextReader("error")
reader.RelaxNGSetSchema(rngs)
ret = reader.Read()
while ret == 1:
ret = reader.Read()
if ret != 0:
print("Error parsing the document")
sys.exit(1)
if reader.IsValid() != 0:
print("Document failed to detect the validation error")
sys.exit(1)
if err != expect:
print("Did not get the expected error message:")
print(err)
sys.exit(1)
#
# cleanup
#
del f
del input
del reader
del rngs
libxml2.relaxNGCleanupTypes()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env python3
#
# this tests the entities substitutions with the XmlTextReader interface
#
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
result = ""
def processNode(reader):
global result
result = result + "%d %d %s %d\n" % (reader.Depth(), reader.NodeType(),
reader.Name(), reader.IsEmptyElement())
#
# Parse a document testing the readerForxxx API
#
docstr="""<foo>
<label>some text</label>
<item>100</item>
</foo>"""
expect="""0 1 foo 0
1 14 #text 0
1 1 label 0
2 3 #text 0
1 15 label 0
1 14 #text 0
1 1 item 0
2 3 #text 0
1 15 item 0
1 14 #text 0
0 15 foo 0
"""
result = ""
reader = libxml2.readerForDoc(docstr, "test1", None, 0)
ret = reader.Read()
while ret == 1:
processNode(reader)
ret = reader.Read()
if ret != 0:
print("Error parsing the document test1")
sys.exit(1)
if result != expect:
print("Unexpected result for test1")
print(result)
sys.exit(1)
#
# Reuse the reader for another document testing the ReaderNewxxx API
#
docstr="""<foo>
<label>some text</label>
<item>1000</item>
</foo>"""
expect="""0 1 foo 0
1 14 #text 0
1 1 label 0
2 3 #text 0
1 15 label 0
1 14 #text 0
1 1 item 0
2 3 #text 0
1 15 item 0
1 14 #text 0
0 15 foo 0
"""
result = ""
reader.NewDoc(docstr, "test2", None, 0)
ret = reader.Read()
while ret == 1:
processNode(reader)
ret = reader.Read()
if ret != 0:
print("Error parsing the document test2")
sys.exit(1)
if result != expect:
print("Unexpected result for test2")
print(result)
sys.exit(1)
#
# cleanup
#
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
#
# this tests the entities substitutions with the XmlTextReader interface
#
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
#
# Parse a document testing the Close() API
#
docstr="""<foo>
<label>some text</label>
<item>100</item>
</foo>"""
reader = libxml2.readerForDoc(docstr, "test1", None, 0)
ret = reader.Read()
ret = reader.Read()
ret = reader.Close()
if ret != 0:
print("Error closing the document test1")
sys.exit(1)
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
#
# this tests the basic APIs of the XmlTextReader interface
#
import setup_test
import libxml2
import sys
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
expect="""--> (3) test1:1:xmlns: URI foo is not absolute
--> (4) test1:1:Opening and ending tag mismatch: c line 1 and a
"""
err=""
def myErrorHandler(arg,msg,severity,locator):
global err
err = err + "%s (%d) %s:%d:%s" % (arg,severity,locator.BaseURI(),locator.LineNumber(),msg)
f = str_io("""<a xmlns="foo"><b b1="b1"/><c>content of c</a>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test1")
reader.SetErrorHandler(myErrorHandler,"-->")
while reader.Read() == 1:
pass
if err != expect:
print("error")
print("received %s" %(err))
print("expected %s" %(expect))
sys.exit(1)
reader.SetErrorHandler(None,None)
if reader.GetErrorHandler() != (None,None):
print("GetErrorHandler failed")
sys.exit(1)
#
# cleanup for memory allocation counting
#
del f
del input
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
# -*- coding: ISO-8859-1 -*-
#
# this tests the next API of the XmlTextReader interface
#
import setup_test
import libxml2
import sys
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
f = str_io("""<a><b><c /></b><d>content of d</d></a>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test_next")
ret = reader.Read()
if ret != 1:
print("test_next: Error reading to first element")
sys.exit(1)
if reader.Name() != "a" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 1 or reader.HasAttributes() != 0:
print("test_next: Error reading the first element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_next: Error reading to second element")
sys.exit(1)
if reader.Name() != "b" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 1 or reader.HasAttributes() != 0:
print("test_next: Error reading the second element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_next: Error reading to third element")
sys.exit(1)
if reader.Name() != "c" or reader.NodeType() != 1 or \
reader.HasAttributes() != 0:
print("test_next: Error reading the third element")
sys.exit(1)
ret = reader.Read()
if ret != 1:
print("test_next: Error reading to end of third element")
sys.exit(1)
if reader.Name() != "b" or reader.NodeType() != 15:
print("test_next: Error reading to end of second element")
sys.exit(1)
ret = reader.Next()
if ret != 1:
print("test_next: Error moving to third element")
sys.exit(1)
if reader.Name() != "d" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 1 or reader.HasAttributes() != 0:
print("test_next: Error reading third element")
sys.exit(1)
ret = reader.Next()
if ret != 1:
print("test_next: Error reading to end of first element")
sys.exit(1)
if reader.Name() != "a" or reader.IsEmptyElement() != 0 or \
reader.NodeType() != 15 or reader.HasAttributes() != 0:
print("test_next: Error reading the end of first element")
sys.exit(1)
ret = reader.Read()
if ret != 0:
print("test_next: Error reading to end of document")
sys.exit(1)
#
# cleanup for memory allocation counting
#
del f
del input
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
def check_regex(regex, inside, outside):
re = libxml2.regexpCompile(regex)
for c in inside:
if re.regexpExec(c) != 1:
print("error checking inside", repr(regex), repr(c))
sys.exit(1)
for c in outside:
if re.regexpExec(c) != 0:
print("error checking outside", repr(regex), repr(c))
sys.exit(1)
if re.regexpIsDeterminist() != 1:
print("error checking determinism")
sys.exit(1)
del re
check_regex("a|b", "ab", ["ab", ""])
# https://gitlab.gnome.org/GNOME/libxml2/-/issues/1086
check_regex(r"[\t-\r]", "\t\n\r", ["a", "(", ""])
check_regex("[\\t-\\r]", "\t\n\r", ["a", "(", ""])
check_regex(r"[\[-\]]", "[]\\", "Z^")
check_regex(r"[\*-/]", "*+,-./", "()0")
# Non-standard escape sequences
check_regex(r"[\u0041-\u005A]", "ABCMYZ", ["a", "0", "[", ""])
check_regex(r"[\u0009\u0061-\u007A]", "\tabcmyz", ["A", "0", "{", "", "\n"])
check_regex(r"[\!-\%]", '!"#$%', ["&", " ", "a", ""])
check_regex(r"[\:-\>]", ':;<=>', ["?", "9", "@", ""])
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
# Memory debug specific
libxml2.debugMemory(1)
schema="""<?xml version="1.0"?>
<element name="foo"
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:a="http://relaxng.org/ns/annotation/1.0"
xmlns:ex1="http://www.example.com/n1"
xmlns:ex2="http://www.example.com/n2">
<a:documentation>A foo element.</a:documentation>
<element name="ex1:bar1">
<empty/>
</element>
<element name="ex2:bar2">
<empty/>
</element>
</element>
"""
instance="""<?xml version="1.0"?>
<foo><pre1:bar1 xmlns:pre1="http://www.example.com/n1"/><pre2:bar2 xmlns:pre2="http://www.example.com/n2"/></foo>"""
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
rngs = rngp.relaxNGParse()
ctxt = rngs.relaxNGNewValidCtxt()
doc = libxml2.parseDoc(instance)
ret = doc.relaxNGValidateDoc(ctxt)
if ret != 0:
print("error doing RelaxNG validation")
sys.exit(1)
doc.freeDoc()
del rngp
del rngs
del ctxt
libxml2.relaxNGCleanupTypes()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
try:
import StringIO
str_io = StringIO.StringIO
except:
import io
str_io = io.StringIO
# Memory debug specific
libxml2.debugMemory(1)
def myResolver(URL, ID, ctxt):
return(str_io("<foo/>"))
libxml2.setEntityLoader(myResolver)
doc = libxml2.parseFile("doesnotexist.xml")
root = doc.children
if root.name != "foo":
print("root element name error")
sys.exit(1)
doc.freeDoc()
i = 0
while i < 5000:
doc = libxml2.parseFile("doesnotexist.xml")
root = doc.children
if root.name != "foo":
print("root element name error")
sys.exit(1)
doc.freeDoc()
i = i + 1
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
# Memory debug specific
libxml2.debugMemory(1)
schema="""<?xml version="1.0" encoding="iso-8859-1"?>
<schema xmlns = "http://www.w3.org/2001/XMLSchema">
<element name = "Customer">
<complexType>
<sequence>
<element name = "FirstName" type = "string" />
<element name = "MiddleInitial" type = "string" />
<element name = "LastName" type = "string" />
</sequence>
<attribute name = "customerID" type = "integer" />
</complexType>
</element>
</schema>"""
instance="""<?xml version="1.0" encoding="iso-8859-1"?>
<Customer customerID = "24332">
<FirstName>Raymond</FirstName>
<MiddleInitial>G</MiddleInitial>
<LastName>Bayliss</LastName>
</Customer>
"""
ctxt_parser = libxml2.schemaNewMemParserCtxt(schema, len(schema))
ctxt_schema = ctxt_parser.schemaParse()
ctxt_valid = ctxt_schema.schemaNewValidCtxt()
doc = libxml2.parseDoc(instance)
ret = doc.schemaValidateDoc(ctxt_valid)
if ret != 0:
print("error doing schema validation")
sys.exit(1)
doc.freeDoc()
del ctxt_parser
del ctxt_schema
del ctxt_valid
libxml2.schemaCleanupTypes()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+144
View File
@@ -0,0 +1,144 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
#
# Testing XML document serialization
#
doc = libxml2.parseDoc("""<root><foo>hello</foo></root>""")
str = doc.serialize()
if str != """<?xml version="1.0"?>
<root><foo>hello</foo></root>
""":
print("error serializing XML document 1")
sys.exit(1)
str = doc.serialize("iso-8859-1")
if str != """<?xml version="1.0" encoding="iso-8859-1"?>
<root><foo>hello</foo></root>
""":
print("error serializing XML document 2")
sys.exit(1)
str = doc.serialize(format=1)
if str != """<?xml version="1.0"?>
<root>
<foo>hello</foo>
</root>
""":
print("error serializing XML document 3")
sys.exit(1)
str = doc.serialize("iso-8859-1", 1)
if str != """<?xml version="1.0" encoding="iso-8859-1"?>
<root>
<foo>hello</foo>
</root>
""":
print("error serializing XML document 4")
sys.exit(1)
#
# Test serializing a subnode
#
root = doc.getRootElement()
str = root.serialize()
if str != """<root><foo>hello</foo></root>""":
print("error serializing XML root 1")
sys.exit(1)
str = root.serialize("iso-8859-1")
if str != """<root><foo>hello</foo></root>""":
print("error serializing XML root 2")
sys.exit(1)
str = root.serialize(format=1)
if str != """<root>
<foo>hello</foo>
</root>""":
print("error serializing XML root 3")
sys.exit(1)
str = root.serialize("iso-8859-1", 1)
if str != """<root>
<foo>hello</foo>
</root>""":
print("error serializing XML root 4")
sys.exit(1)
doc.freeDoc()
#
# Testing HTML document serialization
#
doc = libxml2.htmlParseDoc("""<html><head><title>Hello</title><body><p>hello</body></html>""", None)
str = doc.serialize()
if str != """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head><title>Hello</title></head><body><p>hello</p></body></html>
""":
print("error serializing HTML document 1")
sys.exit(1)
str = doc.serialize("ISO-8859-1")
if str != """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head><meta charset="ISO-8859-1"><title>Hello</title></head><body><p>hello</p></body></html>
""":
print("error serializing HTML document 2")
sys.exit(1)
str = doc.serialize(format=1)
if str != """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head><title>Hello</title></head>
<body><p>hello</p></body>
</html>
""":
print("error serializing HTML document 3")
sys.exit(1)
str = doc.serialize("iso-8859-1", 1)
if str != """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta charset="iso-8859-1">
<title>Hello</title>
</head>
<body><p>hello</p></body>
</html>
""":
print("error serializing HTML document 4", str)
sys.exit(1)
#
# Test serializing a subnode
#
doc.htmlSetMetaEncoding(None)
root = doc.getRootElement()
str = root.serialize()
if str != """<html><head><title>Hello</title></head><body><p>hello</p></body></html>""":
print("error serializing HTML root 1")
sys.exit(1)
str = root.serialize("ISO-8859-1")
if str != """<html><head><meta charset="ISO-8859-1"><title>Hello</title></head><body><p>hello</p></body></html>""":
print("error serializing HTML root 2")
sys.exit(1)
str = root.serialize(format=1)
if str != """<html>
<head><title>Hello</title></head>
<body><p>hello</p></body>
</html>""":
print("error serializing HTML root 3")
sys.exit(1)
str = root.serialize("iso-8859-1", 1)
if str != """<html>
<head>
<meta charset="iso-8859-1">
<title>Hello</title>
</head>
<body><p>hello</p></body>
</html>""":
print("error serializing HTML root 4")
sys.exit(1)
doc.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+5
View File
@@ -0,0 +1,5 @@
import os
import sys
if hasattr(os, 'add_dll_directory'):
os.add_dll_directory(os.path.join(os.getcwd(), '..', '..', '.libs'))
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
log = ""
class callback:
def startDocument(self):
global log
log = log + "startDocument:"
def endDocument(self):
global log
log = log + "endDocument:"
def startElement(self, tag, attrs):
global log
log = log + "startElement %s %s:" % (tag, attrs)
def endElement(self, tag):
global log
log = log + "endElement %s:" % (tag)
def characters(self, data):
global log
log = log + "characters: %s:" % (data)
def warning(self, msg):
global log
log = log + "warning: %s:" % (msg)
def error(self, msg):
global log
log = log + "error: %s:" % (msg)
def fatalError(self, msg):
global log
log = log + "fatalError: %s:" % (msg)
handler = callback()
log=""
chunk="""<foo><bar2/>"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference = "startDocument:startElement foo None:startElement bar2 None:endElement bar2:"
if log != reference:
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
log=""
chunk="""<foo><bar2></bar2>"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference = "startDocument:startElement foo None:startElement bar2 None:endElement bar2:"
if log != reference:
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
log=""
chunk="""<foo><bar2>"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference = "startDocument:startElement foo None:startElement bar2 None:"
if log != reference:
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
log=""
chunk="""<foo><bar2 a="1" b='2' />"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference1 = "startDocument:startElement foo None:startElement bar2 {'a': '1', 'b': '2'}:endElement bar2:"
reference2 = "startDocument:startElement foo None:startElement bar2 {'b': '2', 'a': '1'}:endElement bar2:"
if log not in (reference1, reference2):
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
log=""
chunk="""<foo><bar2 a="1" b='2' >"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference1 = "startDocument:startElement foo None:startElement bar2 {'a': '1', 'b': '2'}:"
reference2 = "startDocument:startElement foo None:startElement bar2 {'b': '2', 'a': '1'}:"
if log not in (reference1, reference2):
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
log=""
chunk="""<foo><bar2 a="1" b='2' ></bar2>"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference1 = "startDocument:startElement foo None:startElement bar2 {'a': '1', 'b': '2'}:endElement bar2:"
reference2 = "startDocument:startElement foo None:startElement bar2 {'b': '2', 'a': '1'}:endElement bar2:"
if log not in (reference1, reference2):
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
log=""
chunk="""<foo><bar2 a="b='1' />"""
ctxt = libxml2.createPushParser(handler, None, 0, "test.xml")
ctxt.parseChunk(chunk, len(chunk), 0)
ctxt=None
reference = "startDocument:startElement foo None:"
if log != reference:
print("Error got: %s" % log)
print("Expected: %s" % reference)
sys.exit(1)
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+1
View File
@@ -0,0 +1 @@
<!ELEMENT foo EMPTY>
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env python3
import string, sys, time
try:
from _thread import get_ident
except:
from thread import get_ident
from threading import Thread, Lock
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
THREADS_COUNT = 15
failed = 0
class ErrorHandler:
def __init__(self):
self.errors = []
self.lock = Lock()
def handler(self,ctx,str):
self.lock.acquire()
self.errors.append(str)
self.lock.release()
def getPedanticParserDefault():
old = libxml2.pedanticParserDefault(0)
libxml2.pedanticParserDefault(old)
return old
def test(expectedPedanticParserDefault):
time.sleep(1)
global failed
# check a per thread-global
if expectedPedanticParserDefault != getPedanticParserDefault():
failed = 1
print("FAILED to obtain correct value for " \
"pedanticParserDefault in thread %d" % get_ident())
# check the global error handler
# (which is NOT per-thread in the python bindings)
try:
doc = libxml2.parseFile("bad.xml")
except:
pass
else:
assert "failed"
# global error handler
eh = ErrorHandler()
libxml2.registerErrorHandler(eh.handler,"")
# set on the main thread only
libxml2.pedanticParserDefault(1)
test(1)
ec = len(eh.errors)
if ec == 0:
print("FAILED: should have obtained errors")
sys.exit(1)
ts = []
for i in range(THREADS_COUNT):
# expect 0 for pedanticParserDefault because
# the new value has been set on the main thread only
ts.append(Thread(target=test,args=(0,)))
for t in ts:
t.start()
for t in ts:
t.join()
if len(eh.errors) != ec+THREADS_COUNT*ec:
print("FAILED: did not obtain the correct number of errors")
sys.exit(1)
# set pedanticParserDefault for future new threads
libxml2.thrDefPedanticParserDefaultValue(1)
ts = []
for i in range(THREADS_COUNT):
# expect 1 for pedanticParserDefault
ts.append(Thread(target=test,args=(1,)))
for t in ts:
t.start()
for t in ts:
t.join()
if len(eh.errors) != ec+THREADS_COUNT*ec*2:
print("FAILED: did not obtain the correct number of errors")
sys.exit(1)
if failed:
print("FAILED")
sys.exit(1)
# Memory debug specific
libxml2.cleanupParser()
# Note that this can leak memory on Windows if the global state
# destructors weren't run yet. They should be called eventually,
# so this leak should be harmless.
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
doc = libxml2.parseFile("tst.xml")
if doc.name != "tst.xml":
print("doc.name failed")
sys.exit(1)
root = doc.children
if root.name != "doc":
print("root.name failed")
sys.exit(1)
child = root.children
if child.name != "foo":
print("child.name failed")
sys.exit(1)
doc.freeDoc()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+1
View File
@@ -0,0 +1 @@
<doc><foo>bar</foo></doc>
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
import sys, unittest
import setup_test
import libxml2
class TestCase(unittest.TestCase):
def runTest(self):
self.test1()
self.test2()
def setUp(self):
libxml2.debugMemory(1)
def tearDown(self):
libxml2.cleanupParser()
if libxml2.debugMemory(1) != 0:
self.fail("Memory leak %d bytes" % (libxml2.debugMemory(1),))
else:
print("OK")
def failUnlessXmlError(self,f,args,exc,domain,code,message,level,file,line):
"""Run function f, with arguments args and expect an exception exc;
when the exception is raised, check the libxml2.lastError for
expected values."""
# disable the default error handler
def noerr(ctx, str):
pass
# None is not acceptable as function.
libxml2.registerErrorHandler(noerr,None)
try:
f(*args)
except exc:
e = libxml2.lastError()
if e is None:
self.fail("lastError not set")
if 0:
print("domain = ",e.domain())
print("code = ",e.code())
print("message =",repr(e.message()))
print("level =",e.level())
print("file =",e.file())
print("line =",e.line())
print()
self.assertEqual(domain,e.domain())
self.assertEqual(code,e.code())
self.assertEqual(message,e.message())
self.assertEqual(level,e.level())
self.assertEqual(file,e.file())
self.assertEqual(line,e.line())
else:
self.fail("exception %s should have been raised" % exc)
def test1(self):
"""Test readFile with a file that does not exist"""
self.failUnlessXmlError(libxml2.readFile,
("dummy.xml",None,0),
libxml2.treeError,
domain=libxml2.XML_FROM_IO,
code=libxml2.XML_IO_ENOENT,
message='failed to load "dummy.xml": No such file or directory\n',
level=libxml2.XML_ERR_WARNING,
file=None,
line=0)
def test2(self):
"""Test a well-formedness error: we get the last error only"""
s = "<x>\n<a>\n</x>"
self.failUnlessXmlError(libxml2.readMemory,
(s,len(s),"dummy.xml",None,0),
libxml2.treeError,
domain=libxml2.XML_FROM_PARSER,
code=libxml2.XML_ERR_TAG_NAME_MISMATCH,
message='Opening and ending tag mismatch: a line 2 and x\n',
level=libxml2.XML_ERR_FATAL,
file='dummy.xml',
line=3)
if __name__ == "__main__":
test = TestCase()
test.setUp()
test.test1()
test.test2()
test.tearDown()
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
uri = libxml2.parseURI("http://example.org:8088/foo/bar?query=simple#fragid")
if uri.scheme() != 'http':
print("Error parsing URI: wrong scheme")
sys.exit(1)
if uri.server() != 'example.org':
print("Error parsing URI: wrong server")
sys.exit(1)
if uri.port() != 8088:
print("Error parsing URI: wrong port")
sys.exit(1)
if uri.path() != '/foo/bar':
print("Error parsing URI: wrong path")
sys.exit(1)
if uri.query() != 'query=simple':
print("Error parsing URI: wrong query")
sys.exit(1)
if uri.fragment() != 'fragid':
print("Error parsing URI: wrong query")
sys.exit(1)
uri.setScheme("https")
uri.setPort(223)
uri.setFragment(None)
result=uri.saveUri()
if result != "https://example.org:223/foo/bar?query=simple":
print("Error modifying or saving the URI")
uri = None
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
import setup_test
import libxml2
try:
import libxml2mod
except ModuleNotFoundError:
from libxmlmods import libxml2mod
import sys
def error(msg, data):
pass
# Memory debug specific
libxml2.debugMemory(1)
dtd="""<!ELEMENT foo EMPTY>"""
instance="""<?xml version="1.0"?>
<foo></foo>"""
dtd = libxml2.parseDTD(None, 'test.dtd')
ctxt = libxml2.newValidCtxt()
libxml2mod.xmlSetValidErrors(ctxt._o, error, error)
doc = libxml2.parseDoc(instance)
ret = doc.validateDtd(ctxt, dtd)
if ret != 1:
print("error doing DTD validation")
sys.exit(1)
doc.freeDoc()
dtd.freeDtd()
del dtd
del ctxt
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
#memory debug specific
libxml2.debugMemory(1)
called = ""
def foo(ctx, x):
global called
#
# test that access to the XPath evaluation contexts
#
pctxt = libxml2.xpathParserContext(_obj=ctx)
ctxt = pctxt.context()
called = ctxt.function()
return x + 1
def bar(ctxt, x):
return "%d" % (x + 2)
doc = libxml2.parseFile("tst.xml")
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//*")
if len(res) != 2:
print("xpath query: wrong node set size")
sys.exit(1)
if res[0].name != "doc" or res[1].name != "foo":
print("xpath query: wrong node set value")
sys.exit(1)
libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
libxml2.registerXPathFunction(ctxt._o, "bar", None, bar)
i = 10000
while i > 0:
res = ctxt.xpathEval("foo(1)")
if res != 2:
print("xpath extension failure")
sys.exit(1)
i = i - 1
i = 10000
while i > 0:
res = ctxt.xpathEval("bar(1)")
if res != "3":
print("xpath extension failure got %s expecting '3'")
sys.exit(1)
i = i - 1
doc.freeDoc()
ctxt.xpathFreeContext()
if called != "foo":
print("xpath function: failed to access the context")
print("xpath function: %s" % (called))
sys.exit(1)
#memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+61
View File
@@ -0,0 +1,61 @@
from io import BytesIO, StringIO
import libxml2
import sys
from xml.sax.handler import ContentHandler
from xml.sax.xmlreader import InputSource
import xml.sax
# Test data: an XML file with a 100,000 Unicode smileys, which expand
# into 400,000 bytes after UTF-8 encoding.
SMILEY = '\U0001f600'
TEXT = 100_000 * SMILEY
XML_STRING = '<?xml version="1.0" encoding="UTF-8" ?>\n<root>' + TEXT + '</root>'
XML_BYTES = XML_STRING.encode('utf-8')
def RunTest(test_name, source):
expected = TEXT
received = ''
class TestHandler(ContentHandler):
def characters(self, content):
nonlocal received
received += content
reader = xml.sax.make_parser(['drv_libxml2'])
reader.setContentHandler(TestHandler())
reader.parse(source)
if expected != received:
print(test_name, 'failed!')
print('Expected length:', len(expected))
print('Received length:', len(received))
print('Expected text: (prefix only)', expected[:100])
print('Received text: (prefix only)', received[:100])
sys.exit(1)
def TestBytesInput():
source = InputSource()
source.setByteStream(BytesIO(XML_BYTES))
RunTest('TestBytesInput', source)
def TestStringInput():
source = InputSource()
source.setCharacterStream(StringIO(XML_STRING))
RunTest('TestStringInput', source)
# Memory debug specific
libxml2.debugMemory(1)
TestBytesInput()
TestStringInput()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+4
View File
@@ -0,0 +1,4 @@
<!DOCTYPE doc [
<!ELEMENT doc EMPTY>
]>
<doc/>
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
ARG = 'test string'
class ErrorHandler:
def __init__(self):
self.errors = []
def handler(self, msg, data):
if data != ARG:
raise Exception("Error handler did not receive correct argument")
self.errors.append(msg)
# Memory debug specific
libxml2.debugMemory(1)
dtd="""<!ELEMENT foo EMPTY>"""
valid="""<?xml version="1.0"?>
<foo></foo>"""
invalid="""<?xml version="1.0"?>
<foo><bar/></foo>"""
dtd = libxml2.parseDTD(None, 'test.dtd')
ctxt = libxml2.newValidCtxt()
e = ErrorHandler()
ctxt.setValidityErrorHandler(e.handler, e.handler, ARG)
# Test valid document
doc = libxml2.parseDoc(valid)
ret = doc.validateDtd(ctxt, dtd)
if ret != 1 or e.errors:
print("error doing DTD validation")
sys.exit(1)
doc.freeDoc()
# Test invalid document
doc = libxml2.parseDoc(invalid)
ret = doc.validateDtd(ctxt, dtd)
if ret != 0 or not e.errors:
print("Error: document supposed to be invalid")
doc.freeDoc()
dtd.freeDtd()
del dtd
del ctxt
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
ARG = 'test string'
class ErrorHandler:
def __init__(self):
self.errors = []
def handler(self, msg, data):
if data != ARG:
raise Exception("Error handler did not receive correct argument")
self.errors.append(msg)
# Memory debug specific
libxml2.debugMemory(1)
schema="""<?xml version="1.0"?>
<element name="foo"
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:a="http://relaxng.org/ns/annotation/1.0"
xmlns:ex1="http://www.example.com/n1"
xmlns:ex2="http://www.example.com/n2">
<a:documentation>A foo element.</a:documentation>
<element name="ex1:bar1">
<empty/>
</element>
<element name="ex2:bar2">
<empty/>
</element>
</element>
"""
valid="""<?xml version="1.0"?>
<foo><pre1:bar1 xmlns:pre1="http://www.example.com/n1"/><pre2:bar2 xmlns:pre2="http://www.example.com/n2"/></foo>"""
invalid="""<?xml version="1.0"?>
<foo><pre1:bar1 xmlns:pre1="http://www.example.com/n1">bad</pre1:bar1><pre2:bar2 xmlns:pre2="http://www.example.com/n2"/></foo>"""
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
rngs = rngp.relaxNGParse()
ctxt = rngs.relaxNGNewValidCtxt()
e = ErrorHandler()
ctxt.setValidityErrorHandler(e.handler, e.handler, ARG)
# Test valid document
doc = libxml2.parseDoc(valid)
ret = doc.relaxNGValidateDoc(ctxt)
if ret != 0 or e.errors:
print("error doing RelaxNG validation")
sys.exit(1)
doc.freeDoc()
# Test invalid document
doc = libxml2.parseDoc(invalid)
ret = doc.relaxNGValidateDoc(ctxt)
if ret == 0 or not e.errors:
print("Error: document supposed to be RelaxNG invalid")
sys.exit(1)
doc.freeDoc()
del rngp
del rngs
del ctxt
libxml2.relaxNGCleanupTypes()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
ARG = 'test string'
class ErrorHandler:
def __init__(self):
self.errors = []
def handler(self, msg, data):
if data != ARG:
raise Exception("Error handler did not receive correct argument")
self.errors.append(msg)
# Memory debug specific
libxml2.debugMemory(1)
schema="""<?xml version="1.0" encoding="iso-8859-1"?>
<schema xmlns = "http://www.w3.org/2001/XMLSchema">
<element name = "Customer">
<complexType>
<sequence>
<element name = "FirstName" type = "string" />
<element name = "MiddleInitial" type = "string" />
<element name = "LastName" type = "string" />
</sequence>
<attribute name = "customerID" type = "integer" />
</complexType>
</element>
</schema>"""
valid="""<?xml version="1.0" encoding="iso-8859-1"?>
<Customer customerID = "24332">
<FirstName>Raymond</FirstName>
<MiddleInitial>G</MiddleInitial>
<LastName>Bayliss</LastName>
</Customer>
"""
invalid="""<?xml version="1.0" encoding="iso-8859-1"?>
<Customer customerID = "24332">
<MiddleInitial>G</MiddleInitial>
<LastName>Bayliss</LastName>
</Customer>
"""
e = ErrorHandler()
ctxt_parser = libxml2.schemaNewMemParserCtxt(schema, len(schema))
ctxt_schema = ctxt_parser.schemaParse()
ctxt_valid = ctxt_schema.schemaNewValidCtxt()
ctxt_valid.setValidityErrorHandler(e.handler, e.handler, ARG)
# Test valid document
doc = libxml2.parseDoc(valid)
ret = doc.schemaValidateDoc(ctxt_valid)
if ret != 0 or e.errors:
print("error doing schema validation")
sys.exit(1)
doc.freeDoc()
# Test invalid document
doc = libxml2.parseDoc(invalid)
ret = doc.schemaValidateDoc(ctxt_valid)
if ret == 0 or not e.errors:
print("Error: document supposer to be schema invalid")
sys.exit(1)
doc.freeDoc()
del ctxt_parser
del ctxt_schema
del ctxt_valid
libxml2.schemaCleanupTypes()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
ctxt = libxml2.createFileParserCtxt("valid.xml")
ctxt.validate(1)
ctxt.parseDocument()
doc = ctxt.doc()
valid = ctxt.isValid()
if doc.name != "valid.xml":
print("doc.name failed")
sys.exit(1)
root = doc.children
if root.name != "doc":
print("root.name failed")
sys.exit(1)
if valid != 1:
print("validity check failed")
sys.exit(1)
doc.freeDoc()
i = 1000
while i > 0:
ctxt = libxml2.createFileParserCtxt("valid.xml")
ctxt.validate(1)
ctxt.parseDocument()
doc = ctxt.doc()
valid = ctxt.isValid()
doc.freeDoc()
if valid != 1:
print("validity check failed")
sys.exit(1)
i = i - 1
#deactivate error messages from the validation
def noerr(ctx, str):
pass
libxml2.registerErrorHandler(noerr, None)
ctxt = libxml2.createFileParserCtxt("invalid.xml")
ctxt.validate(1)
ctxt.parseDocument()
doc = ctxt.doc()
valid = ctxt.isValid()
if doc.name != "invalid.xml":
print("doc.name failed")
sys.exit(1)
root = doc.children
if root.name != "doc":
print("root.name failed")
sys.exit(1)
if valid != 0:
print("validity check failed")
sys.exit(1)
doc.freeDoc()
i = 1000
while i > 0:
ctxt = libxml2.createFileParserCtxt("invalid.xml")
ctxt.validate(1)
ctxt.parseDocument()
doc = ctxt.doc()
valid = ctxt.isValid()
doc.freeDoc()
if valid != 0:
print("validity check failed")
sys.exit(1)
i = i - 1
del ctxt
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+144
View File
@@ -0,0 +1,144 @@
#!/usr/bin/env python3
#
# this tests the entities substitutions with the XmlTextReader interface
#
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
result = ""
def processNode(reader):
global result
result = result + "%d %d %s %d\n" % (reader.Depth(), reader.NodeType(),
reader.Name(), reader.IsEmptyElement())
#
# Parse a document testing the readerForxxx API
#
docstr="""<foo>
<label>some text</label>
<item>100</item>
</foo>"""
expect="""0 1 foo 0
1 14 #text 0
1 1 label 0
2 3 #text 0
1 15 label 0
1 14 #text 0
1 1 item 0
2 3 #text 0
1 15 item 0
1 14 #text 0
0 15 foo 0
"""
result = ""
doc = libxml2.parseDoc(docstr)
reader = doc.readerWalker();
ret = reader.Read()
while ret == 1:
processNode(reader)
ret = reader.Read()
if ret != 0:
print("Error parsing the document test1")
sys.exit(1)
if result != expect:
print("Unexpected result for test1")
print(result)
sys.exit(1)
doc.freeDoc()
#
# Reuse the reader for another document testing the ReaderNewWalker API
#
docstr="""<foo>
<label>some text</label>
<item>1000</item>
</foo>"""
expect="""0 1 foo 0
1 14 #text 0
1 1 label 0
2 3 #text 0
1 15 label 0
1 14 #text 0
1 1 item 0
2 3 #text 0
1 15 item 0
1 14 #text 0
0 15 foo 0
"""
result = ""
doc = libxml2.parseDoc(docstr)
reader.NewWalker(doc)
ret = reader.Read()
while ret == 1:
processNode(reader)
ret = reader.Read()
if ret != 0:
print("Error parsing the document test2")
sys.exit(1)
if result != expect:
print("Unexpected result for test2")
print(result)
sys.exit(1)
doc.freeDoc()
#
# Reuse the reader for another document testing the ReaderNewxxx API
#
docstr="""<foo>
<label>some text</label>
<item>1000</item>
</foo>"""
expect="""0 1 foo 0
1 14 #text 0
1 1 label 0
2 3 #text 0
1 15 label 0
1 14 #text 0
1 1 item 0
2 3 #text 0
1 15 item 0
1 14 #text 0
0 15 foo 0
"""
result = ""
reader.NewDoc(docstr, "test3", None, 0)
ret = reader.Read()
while ret == 1:
processNode(reader)
ret = reader.Read()
if ret != 0:
print("Error parsing the document test3")
sys.exit(1)
if result != expect:
print("Unexpected result for test3")
print(result)
sys.exit(1)
#
# cleanup
#
del reader
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
#
# this test exercise the XPath basic engine, parser, etc, and
# allows to detect memory leaks
#
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
doc = libxml2.parseFile("tst.xml")
if doc.name != "tst.xml":
print("doc.name error")
sys.exit(1);
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//*")
if len(res) != 2:
print("xpath query: wrong node set size")
sys.exit(1)
if res[0].name != "doc" or res[1].name != "foo":
print("xpath query: wrong node set value")
sys.exit(1)
ctxt.setContextNode(res[0])
res = ctxt.xpathEval("foo")
if len(res) != 1:
print("xpath query: wrong node set size")
sys.exit(1)
if res[0].name != "foo":
print("xpath query: wrong node set value")
sys.exit(1)
doc.freeDoc()
ctxt.xpathFreeContext()
i = 1000
while i > 0:
doc = libxml2.parseFile("tst.xml")
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//*")
doc.freeDoc()
ctxt.xpathFreeContext()
i = i -1
del ctxt
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
def foo(ctx, x):
return x + 1
def bar(ctx, x):
return "%d" % (x + 2)
doc = libxml2.parseFile("tst.xml")
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//*")
if len(res) != 2:
print("xpath query: wrong node set size")
sys.exit(1)
if res[0].name != "doc" or res[1].name != "foo":
print("xpath query: wrong node set value")
sys.exit(1)
libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
libxml2.registerXPathFunction(ctxt._o, "bar", None, bar)
i = 10000
while i > 0:
res = ctxt.xpathEval("foo(1)")
if res != 2:
print("xpath extension failure")
sys.exit(1)
i = i - 1
i = 10000
while i > 0:
res = ctxt.xpathEval("bar(1)")
if res != "3":
print("xpath extension failure got %s expecting '3'")
sys.exit(1)
i = i - 1
doc.freeDoc()
ctxt.xpathFreeContext()
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
import setup_test
import libxml2
import sys
libxml2.debugMemory(True)
expect="""--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
--> Invalid expression
"""
err=""
def callback(ctx, str):
global err
err = err + "%s %s" % (ctx, str)
libxml2.registerErrorHandler(callback, "-->")
doc = libxml2.parseDoc("<fish/>")
ctxt = doc.xpathNewContext()
ctxt.setContextNode(doc)
badexprs = (
":false()", "bad:()", "bad(:)", ":bad(:)", "bad:(:)", "bad:bad(:)",
"a:/b", "/c:/d", "//e:/f", "g://h"
)
for expr in badexprs:
try:
ctxt.xpathEval(expr)
except libxml2.xpathError:
pass
else:
print("Unexpectedly legal expression:", expr)
ctxt.xpathFreeContext()
doc.freeDoc()
if err != expect:
print("error")
print("received %s" %(err))
print("expected %s" %(expect))
sys.exit(1)
libxml2.cleanupParser()
leakedbytes = libxml2.debugMemory(True)
if leakedbytes == 0:
print("OK")
else:
print("Memory leak", leakedbytes, "bytes")
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
#
import setup_test
import libxml2
expect=' xmlns:a="urn:whatevar"'
# Memory debug specific
libxml2.debugMemory(1)
d = libxml2.parseDoc("<a:a xmlns:a='urn:whatevar'/>")
res=""
for n in d.xpathEval("//namespace::*"):
res = res + n.serialize()
del n
d.freeDoc()
if res != expect:
print("test5 failed: unexpected output")
print(res)
del res
del d
# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import sys
import setup_test
import libxml2
#memory debug specific
libxml2.debugMemory(1)
#
# A document hosting the nodes returned from the extension function
#
mydoc = libxml2.newDoc("1.0")
def foo(ctx, str):
global mydoc
#
# test returning a node set works as expected
#
parent = mydoc.newDocNode(None, 'p', None)
mydoc.addChild(parent)
node = mydoc.newDocText(str)
parent.addChild(node)
return [parent]
doc = libxml2.parseFile("tst.xml")
ctxt = doc.xpathNewContext()
libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
res = ctxt.xpathEval("foo('hello')")
if type(res) != type([]):
print("Failed to return a nodeset")
sys.exit(1)
if len(res) != 1:
print("Unexpected nodeset size")
sys.exit(1)
node = res[0]
if node.name != 'p':
print("Unexpected nodeset element result")
sys.exit(1)
node = node.children
if node.type != 'text':
print("Unexpected nodeset element children type")
sys.exit(1)
if node.content != 'hello':
print("Unexpected nodeset element children content")
sys.exit(1)
doc.freeDoc()
mydoc.freeDoc()
ctxt.xpathFreeContext()
#memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print("OK")
else:
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
+895
View File
@@ -0,0 +1,895 @@
/*
* types.c: converter functions between the internal representation
* and the Python objects
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
#include "libxml_wrap.h"
#include <libxml/xpathInternals.h>
#include <string.h>
#if PY_MAJOR_VERSION >= 3
#define PY_IMPORT_STRING_SIZE PyUnicode_FromStringAndSize
#define PY_IMPORT_STRING PyUnicode_FromString
#define PY_IMPORT_INT PyLong_FromLong
#else
#define PY_IMPORT_STRING_SIZE PyString_FromStringAndSize
#define PY_IMPORT_STRING PyString_FromString
#define PY_IMPORT_INT PyInt_FromLong
#endif
#if PY_MAJOR_VERSION >= 3
#include <stdio.h>
#include <stdint.h>
#ifdef _WIN32
#include <windows.h>
#include <crtdbg.h>
/* Taken from info on MSDN site, as we may not have the Windows WDK/DDK headers */
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
} DUMMYUNIONNAME;
ULONG_PTR Information;
} IO_STATUS_BLOCK;
typedef struct _FILE_ACCESS_INFORMATION {
ACCESS_MASK AccessFlags;
} FILE_ACCESS_INFORMATION;
typedef NTSTATUS (*t_NtQueryInformationFile) (HANDLE FileHandle,
IO_STATUS_BLOCK *IoStatusBlock,
PVOID FileInformation,
ULONG Length,
int FileInformationClass); /* this is an Enum */
#if (defined (_MSC_VER) && _MSC_VER >= 1400)
/*
* This is the (empty) invalid parameter handler
* that is used for Visual C++ 2005 (and later) builds
* so that we can use this instead of the system automatically
* aborting the process.
*
* This is necessary as we use _get_oshandle() to check the validity
* of the file descriptors as we close them, so when an invalid file
* descriptor is passed into that function as we check on it, we get
* -1 as the result, instead of the gspawn helper program aborting.
*
* Please see http://msdn.microsoft.com/zh-tw/library/ks2530z6%28v=vs.80%29.aspx
* for an explanation on this.
*/
void
myInvalidParameterHandler(const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
unsigned int line,
uintptr_t pReserved)
{
}
#endif
#else
#include <unistd.h>
#include <fcntl.h>
#endif
FILE *
libxml_PyFileGet(PyObject *f) {
FILE *res;
const char *mode;
int fd = PyObject_AsFileDescriptor(f);
#ifdef _WIN32
intptr_t w_fh = -1;
HMODULE hntdll = NULL;
IO_STATUS_BLOCK status_block;
FILE_ACCESS_INFORMATION ai;
t_NtQueryInformationFile NtQueryInformationFile;
BOOL is_read = FALSE;
BOOL is_write = FALSE;
BOOL is_append = FALSE;
#if (defined (_MSC_VER) && _MSC_VER >= 1400)
/* set up our empty invalid parameter handler */
_invalid_parameter_handler oldHandler, newHandler;
newHandler = myInvalidParameterHandler;
oldHandler = _set_invalid_parameter_handler(newHandler);
/* Disable the message box for assertions. */
_CrtSetReportMode(_CRT_ASSERT, 0);
#endif
w_fh = _get_osfhandle(fd);
if (w_fh == -1)
return(NULL);
hntdll = GetModuleHandleW(L"ntdll.dll");
if (hntdll == NULL)
return(NULL);
NtQueryInformationFile = (t_NtQueryInformationFile) (void (*)(void))
GetProcAddress(hntdll, "NtQueryInformationFile");
if (NtQueryInformationFile != NULL &&
(NtQueryInformationFile((HANDLE)w_fh,
&status_block,
&ai,
sizeof(FILE_ACCESS_INFORMATION),
8) == 0)) /* 8 means "FileAccessInformation" */
{
if (ai.AccessFlags & FILE_READ_DATA)
is_read = TRUE;
if (ai.AccessFlags & FILE_WRITE_DATA)
is_write = TRUE;
if (ai.AccessFlags & FILE_APPEND_DATA)
is_append = TRUE;
if (is_write) {
if (is_read) {
if (is_append)
mode = "a+";
else
mode = "rw";
} else {
if (is_append)
mode = "a";
else
mode = "w";
}
} else {
if (is_append)
mode = "r+";
else
mode = "r";
}
}
FreeLibrary(hntdll);
if (!is_write && !is_read) /* also happens if we did not load or run NtQueryInformationFile() successfully */
return(NULL);
#else
int flags;
/*
* macOS returns O_RDWR for standard streams, but fails to write to
* stdout or stderr when opened with fdopen(dup_fd, "rw").
*/
switch (fd) {
case STDIN_FILENO:
mode = "r";
break;
case STDOUT_FILENO:
case STDERR_FILENO:
mode = "w";
break;
default:
/*
* Get the flags on the fd to understand how it was opened
*/
flags = fcntl(fd, F_GETFL, 0);
switch (flags & O_ACCMODE) {
case O_RDWR:
if (flags & O_APPEND)
mode = "a+";
else
mode = "rw";
break;
case O_RDONLY:
if (flags & O_APPEND)
mode = "r+";
else
mode = "r";
break;
case O_WRONLY:
if (flags & O_APPEND)
mode = "a";
else
mode = "w";
break;
default:
return(NULL);
}
}
#endif
/*
* the FILE struct gets a new fd, so that it can be closed
* independently of the file descriptor given. The risk though is
* lack of sync. So at the python level sync must be implemented
* before and after a conversion took place. No way around it
* in the Python3 infrastructure !
* The duplicated fd and FILE * will be released in the subsequent
* call to libxml_PyFileRelease() which must be generated accordingly
*/
fd = dup(fd);
if (fd == -1)
return(NULL);
res = fdopen(fd, mode);
if (res == NULL) {
close(fd);
return(NULL);
}
return(res);
}
void libxml_PyFileRelease(FILE *f) {
if (f != NULL)
fclose(f);
}
#endif
PyObject *
libxml_intWrap(int val)
{
PyObject *ret;
ret = PY_IMPORT_INT((long) val);
return (ret);
}
PyObject *
libxml_longWrap(long val)
{
PyObject *ret;
ret = PyLong_FromLong(val);
return (ret);
}
PyObject *
libxml_doubleWrap(double val)
{
PyObject *ret;
ret = PyFloat_FromDouble((double) val);
return (ret);
}
PyObject *
libxml_charPtrWrap(char *str)
{
PyObject *ret;
if (str == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PY_IMPORT_STRING(str);
xmlFree(str);
return (ret);
}
PyObject *
libxml_charPtrConstWrap(const char *str)
{
PyObject *ret;
if (str == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PY_IMPORT_STRING(str);
return (ret);
}
PyObject *
libxml_xmlCharPtrWrap(xmlChar * str)
{
PyObject *ret;
if (str == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PY_IMPORT_STRING((char *) str);
xmlFree(str);
return (ret);
}
PyObject *
libxml_xmlCharPtrConstWrap(const xmlChar * str)
{
PyObject *ret;
if (str == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PY_IMPORT_STRING((char *) str);
return (ret);
}
PyObject *
libxml_constcharPtrWrap(const char *str)
{
PyObject *ret;
if (str == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PY_IMPORT_STRING(str);
return (ret);
}
PyObject *
libxml_constxmlCharPtrWrap(const xmlChar * str)
{
PyObject *ret;
if (str == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PY_IMPORT_STRING((char *) str);
return (ret);
}
PyObject *
libxml_xmlDocPtrWrap(xmlDocPtr doc)
{
PyObject *ret;
if (doc == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
/* TODO: look at deallocation */
ret = PyCapsule_New((void *) doc, (char *) "xmlDocPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlNodePtrWrap(xmlNodePtr node)
{
PyObject *ret;
if (node == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) node, (char *) "xmlNodePtr", NULL);
return (ret);
}
PyObject *
libxml_xmlURIPtrWrap(xmlURIPtr uri)
{
PyObject *ret;
if (uri == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) uri, (char *) "xmlURIPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlNsPtrWrap(xmlNsPtr ns)
{
PyObject *ret;
if (ns == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) ns, (char *) "xmlNsPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlAttrPtrWrap(xmlAttrPtr attr)
{
PyObject *ret;
if (attr == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) attr, (char *) "xmlAttrPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlAttributePtrWrap(xmlAttributePtr attr)
{
PyObject *ret;
if (attr == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) attr, (char *) "xmlAttributePtr", NULL);
return (ret);
}
PyObject *
libxml_xmlElementPtrWrap(xmlElementPtr elem)
{
PyObject *ret;
if (elem == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) elem, (char *) "xmlElementPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) ctxt, (char *) "xmlParserCtxtPtr", NULL);
return (ret);
}
#ifdef LIBXML_XPATH_ENABLED
PyObject *
libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *) ctxt, (char *) "xmlXPathContextPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret = PyCapsule_New((void *)ctxt, (char *)"xmlXPathParserContextPtr", NULL);
return (ret);
}
/**
* libxml_xmlXPathDestructNsNode:
* cap: xmlNsPtr namespace node capsule object
*
* This function is called if and when a namespace node returned in
* an XPath node set is to be destroyed. That's the only kind of
* object returned in node set not directly linked to the original
* xmlDoc document, see xmlXPathNodeSetDupNs.
*/
#if PY_VERSION_HEX < 0x02070000
static void
libxml_xmlXPathDestructNsNode(void *cap, void *desc ATTRIBUTE_UNUSED)
#else
static void
libxml_xmlXPathDestructNsNode(PyObject *cap)
#endif
{
#if PY_VERSION_HEX < 0x02070000
xmlXPathNodeSetFreeNs((xmlNsPtr) cap);
#else
xmlXPathNodeSetFreeNs((xmlNsPtr) PyCapsule_GetPointer(cap, "xmlNsPtr"));
#endif
}
PyObject *
libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj)
{
PyObject *ret;
if (obj == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
switch (obj->type) {
case XPATH_XSLT_TREE: {
if ((obj->nodesetval == NULL) ||
(obj->nodesetval->nodeNr == 0) ||
(obj->nodesetval->nodeTab == NULL)) {
ret = PyList_New(0);
} else {
int i, len = 0;
xmlNodePtr node;
node = obj->nodesetval->nodeTab[0]->children;
while (node != NULL) {
len++;
node = node->next;
}
ret = PyList_New(len);
node = obj->nodesetval->nodeTab[0]->children;
for (i = 0;i < len;i++) {
PyList_SetItem(ret, i, libxml_xmlNodePtrWrap(node));
node = node->next;
}
}
/*
* Return now, do not free the object passed down
*/
return (ret);
}
case XPATH_NODESET:
if ((obj->nodesetval == NULL)
|| (obj->nodesetval->nodeNr == 0)) {
ret = PyList_New(0);
} else {
int i;
xmlNodePtr node;
ret = PyList_New(obj->nodesetval->nodeNr);
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
node = obj->nodesetval->nodeTab[i];
if (node->type == XML_NAMESPACE_DECL) {
PyObject *ns = PyCapsule_New((void *) node,
(char *) "xmlNsPtr",
libxml_xmlXPathDestructNsNode);
PyList_SetItem(ret, i, ns);
/* make sure the xmlNsPtr is not destroyed now */
obj->nodesetval->nodeTab[i] = NULL;
} else {
PyList_SetItem(ret, i, libxml_xmlNodePtrWrap(node));
}
}
}
break;
case XPATH_BOOLEAN:
ret = PY_IMPORT_INT((long) obj->boolval);
break;
case XPATH_NUMBER:
ret = PyFloat_FromDouble(obj->floatval);
break;
case XPATH_STRING:
ret = PY_IMPORT_STRING((char *) obj->stringval);
break;
default:
Py_INCREF(Py_None);
ret = Py_None;
}
xmlXPathFreeObject(obj);
return (ret);
}
xmlXPathObjectPtr
libxml_xmlXPathObjectPtrConvert(PyObject *obj)
{
xmlXPathObjectPtr ret = NULL;
if (obj == NULL) {
return (NULL);
}
if (PyFloat_Check (obj)) {
ret = xmlXPathNewFloat((double) PyFloat_AS_DOUBLE(obj));
} else if (PyLong_Check(obj)) {
#ifdef PyLong_AS_LONG
ret = xmlXPathNewFloat((double) PyLong_AS_LONG(obj));
#else
ret = xmlXPathNewFloat((double) PyInt_AS_LONG(obj));
#endif
#ifdef PyBool_Check
} else if (PyBool_Check (obj)) {
if (obj == Py_True) {
ret = xmlXPathNewBoolean(1);
}
else {
ret = xmlXPathNewBoolean(0);
}
#endif
} else if (PyBytes_Check (obj)) {
xmlChar *str;
str = xmlStrndup((const xmlChar *) PyBytes_AS_STRING(obj),
PyBytes_GET_SIZE(obj));
ret = xmlXPathWrapString(str);
#ifdef PyUnicode_Check
} else if (PyUnicode_Check (obj)) {
#if PY_VERSION_HEX >= 0x03030000
xmlChar *str;
const char *tmp;
Py_ssize_t size;
/* tmp doesn't need to be deallocated */
tmp = PyUnicode_AsUTF8AndSize(obj, &size);
str = xmlStrndup((const xmlChar *) tmp, (int) size);
ret = xmlXPathWrapString(str);
#else
xmlChar *str = NULL;
PyObject *b;
b = PyUnicode_AsUTF8String(obj);
if (b != NULL) {
str = xmlStrndup((const xmlChar *) PyBytes_AS_STRING(b),
PyBytes_GET_SIZE(b));
Py_DECREF(b);
}
ret = xmlXPathWrapString(str);
#endif
#endif
} else if (PyList_Check (obj)) {
int i;
PyObject *node;
xmlNodePtr cur;
xmlNodeSetPtr set;
set = xmlXPathNodeSetCreate(NULL);
for (i = 0; i < PyList_Size(obj); i++) {
node = PyList_GetItem(obj, i);
if ((node == NULL) || (node->ob_type == NULL))
continue;
cur = NULL;
if (PyCapsule_CheckExact(node)) {
cur = PyxmlNode_Get(node);
} else if ((PyObject_HasAttrString(node, (char *) "_o")) &&
(PyObject_HasAttrString(node, (char *) "get_doc"))) {
PyObject *wrapper;
wrapper = PyObject_GetAttrString(node, (char *) "_o");
if (wrapper != NULL)
cur = PyxmlNode_Get(wrapper);
} else {
}
if (cur != NULL) {
xmlXPathNodeSetAdd(set, cur);
}
}
ret = xmlXPathWrapNodeSet(set);
} else {
}
return (ret);
}
#endif /* LIBXML_XPATH_ENABLED */
PyObject *
libxml_xmlValidCtxtPtrWrap(xmlValidCtxtPtr valid)
{
PyObject *ret;
if (valid == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) valid,
(char *) "xmlValidCtxtPtr", NULL);
return (ret);
}
#ifdef LIBXML_CATALOG_ENABLED
PyObject *
libxml_xmlCatalogPtrWrap(xmlCatalogPtr catal)
{
PyObject *ret;
if (catal == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) catal,
(char *) "xmlCatalogPtr", NULL);
return (ret);
}
#endif /* LIBXML_CATALOG_ENABLED */
PyObject *
libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer)
{
PyObject *ret;
if (buffer == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) buffer,
(char *) "xmlOutputBufferPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer)
{
PyObject *ret;
if (buffer == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) buffer,
(char *) "xmlParserInputBufferPtr", NULL);
return (ret);
}
#ifdef LIBXML_REGEXP_ENABLED
PyObject *
libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp)
{
PyObject *ret;
if (regexp == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) regexp,
(char *) "xmlRegexpPtr", NULL);
return (ret);
}
#endif /* LIBXML_REGEXP_ENABLED */
#ifdef LIBXML_READER_ENABLED
PyObject *
libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader)
{
PyObject *ret;
if (reader == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) reader,
(char *) "xmlTextReaderPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator)
{
PyObject *ret;
if (locator == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) locator,
(char *) "xmlTextReaderLocatorPtr", NULL);
return (ret);
}
#endif /* LIBXML_READER_ENABLED */
#ifdef LIBXML_RELAXNG_ENABLED
PyObject *
libxml_xmlRelaxNGPtrWrap(xmlRelaxNGPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) ctxt,
(char *) "xmlRelaxNGPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlRelaxNGParserCtxtPtrWrap(xmlRelaxNGParserCtxtPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) ctxt,
(char *) "xmlRelaxNGParserCtxtPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlRelaxNGValidCtxtPtrWrap(xmlRelaxNGValidCtxtPtr valid)
{
PyObject *ret;
if (valid == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) valid,
(char *) "xmlRelaxNGValidCtxtPtr", NULL);
return (ret);
}
#endif /* LIBXML_RELAXNG_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
PyObject *
libxml_xmlSchemaPtrWrap(xmlSchemaPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) ctxt,
(char *) "xmlSchemaPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlSchemaParserCtxtPtrWrap(xmlSchemaParserCtxtPtr ctxt)
{
PyObject *ret;
if (ctxt == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) ctxt,
(char *) "xmlSchemaParserCtxtPtr", NULL);
return (ret);
}
PyObject *
libxml_xmlSchemaValidCtxtPtrWrap(xmlSchemaValidCtxtPtr valid)
{
PyObject *ret;
if (valid == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
ret =
PyCapsule_New((void *) valid,
(char *) "xmlSchemaValidCtxtPtr", NULL);
return (ret);
}
#endif /* LIBXML_SCHEMAS_ENABLED */
static void
libxml_xmlDestructError(PyObject *cap) {
xmlErrorPtr err = (xmlErrorPtr) PyCapsule_GetPointer(cap, "xmlErrorPtr");
xmlResetError(err);
xmlFree(err);
}
PyObject *
libxml_xmlErrorPtrWrap(const xmlError *error)
{
PyObject *ret;
xmlErrorPtr copy;
if (error == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
copy = xmlMalloc(sizeof(*copy));
if (copy == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
memset(copy, 0, sizeof(*copy));
xmlCopyError(error, copy);
ret = PyCapsule_New(copy, "xmlErrorPtr", libxml_xmlDestructError);
return (ret);
}