8000 cpython/Modules/_elementtree.c at 3.3 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content 8000

Latest commit

 

History

History
3718 lines (3125 loc) · 105 KB

File metadata and controls

3718 lines (3125 loc) · 105 KB
/*
* ElementTree
* $Id: _elementtree.c 3473 2009-01-11 22:53:55Z fredrik $
*
* elementtree accelerator
*
* History:
* 1999-06-20 fl created (as part of sgmlop)
* 2001-05-29 fl effdom edition
* 2003-02-27 fl elementtree edition (alpha)
* 2004-06-03 fl updates for elementtree 1.2
* 2005-01-05 fl major optimization effort
* 2005-01-11 fl first public release (cElementTree 0.8)
* 2005-01-12 fl split element object into base and extras
* 2005-01-13 fl use tagged pointers for tail/text (cElementTree 0.9)
* 2005-01-17 fl added treebuilder close method
* 2005-01-17 fl fixed crash in getchildren
* 2005-01-18 fl removed observer api, added iterparse (cElementTree 0.9.3)
* 2005-01-23 fl revised iterparse api; added namespace event support (0.9.8)
* 2005-01-26 fl added VERSION module property (cElementTree 1.0)
* 2005-01-28 fl added remove method (1.0.1)
* 2005-03-01 fl added iselement function; fixed makeelement aliasing (1.0.2)
* 2005-03-13 fl export Comment and ProcessingInstruction/PI helpers
* 2005-03-26 fl added Comment and PI support to XMLParser
* 2005-03-27 fl event optimizations; complain about bogus events
* 2005-08-08 fl fixed read error handling in parse
* 2005-08-11 fl added runtime test for copy workaround (1.0.3)
* 2005-12-13 fl added expat_capi support (for xml.etree) (1.0.4)
* 2005-12-16 fl added support for non-standard encodings
* 2006-03-08 fl fixed a couple of potential null-refs and leaks
* 2006-03-12 fl merge in 2.5 ssize_t changes
* 2007-08-25 fl call custom builder's close method from XMLParser
* 2007-08-31 fl added iter, extend from ET 1.3
* 2007-09-01 fl fixed ParseErr 527E or exception, setslice source type, etc
* 2007-09-03 fl fixed handling of negative insert indexes
* 2007-09-04 fl added itertext from ET 1.3
* 2007-09-06 fl added position attribute to ParseError exception
* 2008-06-06 fl delay error reporting in iterparse (from Hrvoje Niksic)
*
* Copyright (c) 1999-2009 by Secret Labs AB. All rights reserved.
* Copyright (c) 1999-2009 by Fredrik Lundh.
*
* info@pythonware.com
* http://www.pythonware.com
*/
/* Licensed to PSF under a Contributor Agreement. */
/* See http://www.python.org/psf/license for licensing details. */
#include "Python.h"
#include "structmember.h"
#define VERSION "1.0.6"
/* -------------------------------------------------------------------- */
/* configuration */
/* Leave defined to include the expat-based XMLParser type */
#define USE_EXPAT
/* An element can hold this many children without extra memory
allocations. */
#define STATIC_CHILDREN 4
/* For best performance, chose a value so that 80-90% of all nodes
have no more than the given number of children. Set this to zero
to minimize the size of the element structure itself (this only
helps if you have lots of leaf nodes with attributes). */
/* Also note that pymalloc always allocates blocks in multiples of
eight bytes. For the current C version of ElementTree, this means
that the number of children should be an even number, at least on
32-bit platforms. */
/* -------------------------------------------------------------------- */
#if 0
static int memory = 0;
#define ALLOC(size, comment)\
do { memory += size; printf("%8d - %s\n", memory, comment); } while (0)
#define RELEASE(size, comment)\
do { memory -= size; printf("%8d - %s\n", memory, comment); } while (0)
#else
#define ALLOC(size, comment)
#define RELEASE(size, comment)
#endif
/* compiler tweaks */
#if defined(_MSC_VER)
#define LOCAL(type) static __inline type __fastcall
#else
#define LOCAL(type) static type
#endif
/* macros used to store 'join' flags in string object pointers. note
that all use of text and tail as object pointers must be wrapped in
JOIN_OBJ. see comments in the ElementObject definition for more
info. */
#define JOIN_GET(p) ((Py_uintptr_t) (p) & 1)
#define JOIN_SET(p, flag) ((void*) ((Py_uintptr_t) (JOIN_OBJ(p)) | (flag)))
#define JOIN_OBJ(p) ((PyObject*) ((Py_uintptr_t) (p) & ~(Py_uintptr_t)1))
/* Py_CLEAR for a PyObject* that uses a join flag. Pass the pointer by
* reference since this function sets it to NULL.
*/
static void _clear_joined_ptr(PyObject **p)
{
if (*p) {
PyObject *tmp = JOIN_OBJ(*p);
*p = NULL;
Py_DECREF(tmp);
}
}
/* Types defined by this extension */
static PyTypeObject Element_Type;
static PyType B94A Object ElementIter_Type;
static PyTypeObject TreeBuilder_Type;
static PyTypeObject XMLParser_Type;
/* glue functions (see the init function for details) */
static PyObject* elementtree_parseerror_obj;
static PyObject* elementtree_deepcopy_obj;
static PyObject* elementpath_obj;
/* helpers */
LOCAL(PyObject*)
deepcopy(PyObject* object, PyObject* memo)
{
/* do a deep copy of the given object */
PyObject* args;
PyObject* result;
if (!elementtree_deepcopy_obj) {
PyErr_SetString(
PyExc_RuntimeError,
"deepcopy helper not found"
);
return NULL;
}
args = PyTuple_Pack(2, object, memo);
if (!args)
return NULL;
result = PyObject_CallObject(elementtree_deepcopy_obj, args);
Py_DECREF(args);
return result;
}
LOCAL(PyObject*)
list_join(PyObject* list)
{
/* join list elements (destroying the list in the process) */
PyObject* joiner;
PyObject* result;
joiner = PyUnicode_FromStringAndSize("", 0);
if (!joiner)
return NULL;
result = PyUnicode_Join(joiner, list);
Py_DECREF(joiner);
if (result)
Py_DECREF(list);
return result;
}
/* Is the given object an empty dictionary?
*/
static int
is_empty_dict(PyObject *obj)
{
return PyDict_CheckExact(obj) && PyDict_Size(obj) == 0;
}
/* -------------------------------------------------------------------- */
/* the Element type */
typedef struct {
/* attributes (a dictionary object), or None if no attributes */
PyObject* attrib;
/* child elements */
int length; /* actual number of items */
int allocated; /* allocated items */
/* this either points to _children or to a malloced buffer */
PyObject* *children;
PyObject* _children[STATIC_CHILDREN];
} ElementObjectExtra;
typedef struct {
PyObject_HEAD
/* element tag (a string). */
PyObject* tag;
/* text before first child. note that this is a tagged pointer;
use JOIN_OBJ to get the object pointer. the join flag is used
to distinguish lists created by the tree builder from lists
assigned to the attribute by application code; the former
should be joined before being returned to the user, the latter
should be left intact. */
PyObject* text;
/* text after this element, in parent. note that this is a tagged
pointer; use JOIN_OBJ to get the object pointer. */
PyObject* tail;
ElementObjectExtra* extra;
PyObject *weakreflist; /* For tp_weaklistoffset */
} ElementObject;
#define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type)
/* -------------------------------------------------------------------- */
/* Element constructors and destructor */
LOCAL(int)
create_extra(ElementObject* self, PyObject* attrib)
{
self->extra = PyObject_Malloc(sizeof(ElementObjectExtra));
if (!self->extra)
return -1;
if (!attrib)
attrib = Py_None;
Py_INCREF(attrib);
self->extra->attrib = attrib;
self->extra->length = 0;
self->extra->allocated = STATIC_CHILDREN;
self->extra->children = self->extra->_children;
return 0;
}
LOCAL(void)
dealloc_extra(ElementObject* self)
{
ElementObjectExtra *myextra;
int i;
if (!self->extra)
return;
/* Avoid DECREFs calling into this code again (cycles, etc.)
*/
myextra = self->extra;
self->extra = NULL;
Py_DECREF(myextra->attrib);
for (i = 0; i < myextra->length; i++)
Py_DECREF(myextra->children[i]);
if (myextra->children != myextra->_children)
PyObject_Free(myextra->children);
PyObject_Free(myextra);
}
/* Convenience internal function to create new Element objects with the given
* tag and attributes.
*/
LOCAL(PyObject*)
create_new_element(PyObject* tag, PyObject* attrib)
{
ElementObject* self;
self = PyObject_GC_New(ElementObject, &Element_Type);
if (self == NULL)
return NULL;
self->extra = NULL;
if (attrib != Py_None && !is_empty_dict(attrib)) {
if (create_extra(self, attrib) < 0) {
PyObject_Del(self);
return NULL;
}
}
Py_INCREF(tag);
self->tag = tag;
Py_INCREF(Py_None);
self->text = Py_None;
Py_INCREF(Py_None);
self->tail = Py_None;
self->weakreflist = NULL;
ALLOC(sizeof(ElementObject), "create element");
PyObject_GC_Track(self);
return (PyObject*) self;
}
static PyObject *
element_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
ElementObject *e = (ElementObject *)type->tp_alloc(type, 0);
if (e != NULL) {
Py_INCREF(Py_None);
e->tag = Py_None;
Py_INCREF(Py_None);
e->text = Py_None;
Py_INCREF(Py_None);
e->tail = Py_None;
e->extra = NULL;
e->weakreflist = NULL;
}
return (PyObject *)e;
}
/* Helper function for extracting the attrib dictionary from a keywords dict.
* This is required by some constructors/functions in this module that can
* either accept attrib as a keyword argument or all attributes splashed
* directly into *kwds.
*
* Return a dictionary with the content of kwds merged into the content of
* attrib. If there is no attrib keyword, return a copy of kwds.
*/
static PyObject*
get_attrib_from_keywords(PyObject *kwds)
{
PyObject *attrib_str = PyUnicode_FromString("attrib");
PyObject *attrib = PyDict_GetItem(kwds, attrib_str);
if (attrib) {
/* If attrib was found in kwds, copy its value and remove it from
* kwds
*/
if (!PyDict_Check(attrib)) {
Py_DECREF(attrib_str);
PyErr_Format(PyExc_TypeError, "attrib must be dict, not %.100s",
Py_TYPE(attrib)->tp_name);
return NULL;
}
attrib = PyDict_Copy(attrib);
PyDict_DelItem(kwds, attrib_str);
} else {
attrib = PyDict_New();
}
Py_DECREF(attrib_str);
if (attrib)
if (PyDict_Update(attrib, kwds) < 0)
return NULL;
return attrib;
}
static int
element_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *tag;
PyObject *tmp;
PyObject *attrib = NULL;
ElementObject *self_elem;
if (!PyArg_ParseTuple(args, "O|O!:Element", &tag, &PyDict_Type, &attrib))
return -1;
if (attrib) {
/* attrib passed as positional arg */
attrib = PyDict_Copy(attrib);
if (!attrib)
return -1;
if (kwds) {
if (PyDict_Update(attrib, kwds) < 0) {
Py_DECREF(attrib);
return -1;
}
}
} else if (kwds) {
/* have keywords args */
attrib = get_attrib_from_keywords(kwds);
if (!attrib)
return -1;
}
self_elem = (ElementObject *)self;
if (attrib != NULL && !is_empty_dict(attrib)) {
if (create_extra(self_elem, attrib) < 0) {
Py_DECREF(attrib);
return -1;
}
}
/* We own a reference to attrib here and it's no longer needed. */
Py_XDECREF(attrib);
/* Replace the objects already pointed to by tag, text and tail. */
tmp = self_elem->tag;
Py_INCREF(tag);
self_elem->tag = tag;
Py_DECREF(tmp);
tmp = self_elem->text;
Py_INCREF(Py_None);
self_elem->text = Py_None;
Py_DECREF(JOIN_OBJ(tmp));
tmp = self_elem->tail;
Py_INCREF(Py_None);
self_elem->tail = Py_None;
Py_DECREF(JOIN_OBJ(tmp));
return 0;
}
LOCAL(int)
element_resize(ElementObject* self, int extra)
{
int size;
PyObject* *children;
/* make sure self->children can hold the given number of extra
elements. set an exception and return -1 if allocation failed */
if (!self->extra)
create_extra(self, NULL);
size = self->extra->length + extra;
if (size > self->extra->allocated) {
/* use Python 2.4's list growth strategy */
size = (size >> 3) + (size < 9 ? 3 : 6) + size;
/* Coverity CID #182 size_error: Allocating 1 bytes to pointer "children"
* which needs at least 4 bytes.
* Although it's a false alarm always assume at least one child to
* be safe.
*/
size = size ? size : 1;
if (self->extra->children != self->extra->_children) {
/* Coverity CID #182 size_error: Allocating 1 bytes to pointer
* "children", which needs at least 4 bytes. Although it's a
* false alarm always assume at least one child to be safe.
*/
children = PyObject_Realloc(self->extra->children,
size * sizeof(PyObject*));
if (!children)
goto nomemory;
} else {
children = PyObject_Malloc(size * sizeof(PyObject*));
if (!children)
goto nomemory;
/* copy existing children from static area to malloc buffer */
memcpy(children, self->extra->children,
self->extra->length * sizeof(PyObject*));
}
self->extra->children = children;
self->extra->allocated = size;
}
return 0;
nomemory:
PyErr_NoMemory();
return -1;
}
LOCAL(int)
element_add_subelement(ElementObject* self, PyObject* element)
{
/* add a child element to a parent */
if (element_resize(self, 1) < 0)
return -1;
Py_INCREF(element);
self->extra->children[self->extra->length] = element;
self->extra->length++;
return 0;
}
LOCAL(PyObject*)
element_get_attrib(ElementObject* self)
{
/* return borrowed reference to attrib dictionary */
/* note: this function assumes that the extra section exists */
PyObject* res = self->extra->attrib;
if (res == Py_None) {
/* create missing dictionary */
res = PyDict_New();
if (!res)
return NULL;
Py_DECREF(Py_None);
self->extra->attrib = res;
}
return res;
}
LOCAL(PyObject*)
element_get_text(ElementObject* self)
{
/* return borrowed reference to text attribute */
PyObject* res = self->text;
if (JOIN_GET(res)) {
res = JOIN_OBJ(res);
if (PyList_CheckExact(res)) {
res = list_join(res);
if (!res)
return NULL;
self->text = res;
}
}
return res;
}
LOCAL(PyObject*)
element_get_tail(ElementObject* self)
{
/* return borrowed reference to text attribute */
PyObject* res = self->tail;
if (JOIN_GET(res)) {
res = JOIN_OBJ(res);
if (PyList_CheckExact(res)) {
res = list_join(res);
if (!res)
return NULL;
self->tail = res;
}
}
return res;
}
static PyObject*
subelement(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject* elem;
ElementObject* parent;
PyObject* tag;
PyObject* attrib = NULL;
if (!PyArg_ParseTuple(args, "O!O|O!:SubElement",
&Element_Type, &parent, &tag,
&PyDict_Type, &attrib))
return NULL;
if (attrib) {
/* attrib passed as positional arg */
attrib = PyDict_Copy(attrib);
if (!attrib)
return NULL;
if (kwds) {
if (PyDict_Update(attrib, kwds) < 0) {
return NULL;
}
}
} else if (kwds) {
/* have keyword args */
attrib = get_attrib_from_keywords(kwds);
if (!attrib)
return NULL;
} else {
/* no attrib arg, no kwds, so no attribute */
Py_INCREF(Py_None);
attrib = Py_None;
}
elem = create_new_element(tag, attrib);
Py_DECREF(attrib);
if (element_add_subelement(parent, elem) < 0) {
Py_DECREF(elem);
return NULL;
}
return elem;
}
static int
element_gc_traverse(ElementObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->tag);
Py_VISIT(JOIN_OBJ(self->text));
Py_VISIT(JOIN_OBJ(self->tail));
if (self->extra) {
int i;
Py_VISIT(self->extra->attrib);
for (i = 0; i < self->extra->length; ++i)
Py_VISIT(self->extra->children[i]);
}
return 0;
}
static int
element_gc_clear(ElementObject *self)
{
Py_CLEAR(self->tag);
_clear_joined_ptr(&self->text);
_clear_joined_ptr(&self->tail);
/* After dropping all references from extra, it's no longer valid anyway,
* so fully deallocate it.
*/
dealloc_extra(self);
return 0;
}
static void
element_dealloc(ElementObject* self)
{
PyObject_GC_UnTrack(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
/* element_gc_clear clears all references and deallocates extra
*/
element_gc_clear(self);
RELEASE(sizeof(ElementObject), "destroy element");
Py_TYPE(self)->tp_free((PyObject *)self);
}
/* -------------------------------------------------------------------- */
/* methods (in alphabetical order) */
static PyObject*
element_append(ElementObject* self, PyObject* args)
{
PyObject* element;
if (!PyArg_ParseTuple(args, "O!:append", &Element_Type, &element))
return NULL;
if (element_add_subelement(self, element) < 0)
return NULL;
Py_RETURN_NONE;
}
static PyObject*
element_clearmethod(ElementObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":clear"))
return NULL;
dealloc_extra(self);
Py_INCREF(Py_None);
Py_DECREF(JOIN_OBJ(self->text));
self->text = Py_None;
Py_INCREF(Py_None);
Py_DECREF(JOIN_OBJ(self->tail));
self->tail = Py_None;
Py_RETURN_NONE;
}
static PyObject*
element_copy(ElementObject* self, PyObject* args)
{
int i;
ElementObject* element;
if (!PyArg_ParseTuple(args, ":__copy__"))
return NULL;
element = (ElementObject*) create_new_element(
self->tag, (self->extra) ? self->extra->attrib : Py_None
);
if (!element)
return NULL;
Py_DECREF(JOIN_OBJ(element->text));
element->text = self->text;
Py_INCREF(JOIN_OBJ(element->text));
Py_DECREF(JOIN_OBJ(element->tail));
element->tail = self->tail;
Py_INCREF(JOIN_OBJ(element->tail));
if (self->extra) {
if (element_resize(element, self->extra->length) < 0) {
Py_DECREF(element);
return NULL;
}
for (i = 0; i < self->extra->length; i++) {
Py_INCREF(self->extra->children[i]);
element->extra->children[i] = self->extra->children[i];
}
element->extra->length = self->extra->length;
}
return (PyObject*) element;
}
static PyObject*
element_deepcopy(ElementObject* self, PyObject* args)
{
int i;
ElementObject* element;
PyObject* tag;
PyObject* attrib;
PyObject* text;
PyObject* tail;
PyObject* id;
PyObject* memo;
if (!PyArg_ParseTuple(args, "O:__deepcopy__", &memo))
return NULL;
tag = deepcopy(self->tag, memo);
if (!tag)
return NULL;
if (self->extra) {
attrib = deepcopy(self->extra->attrib, memo);
if (!attrib) {
Py_DECREF(tag);
return NULL;
}
} else {
Py_INCREF(Py_None);
attrib = Py_None;
}
element = (ElementObject*) create_new_element(tag, attrib);
Py_DECREF(tag);
Py_DECREF(attrib);
if (!element)
return NULL;
text = deepcopy(JOIN_OBJ(self->text), memo);
if (!text)
goto error;
Py_DECREF(element->text);
element->text = JOIN_SET(text, JOIN_GET(self->text));
tail = deepcopy(JOIN_OBJ(self->tail), memo);
if (!tail)
goto error;
Py_DECREF(element->tail);
element->tail = JOIN_SET(tail, JOIN_GET(self->tail));
if (self->extra) {
if (element_resize(element, self->extra->length) < 0)
goto error;
for (i = 0; i < self->extra->length; i++) {
PyObject* child = deepcopy(self->extra->children[i], memo);
if (!child) {
element->extra->length = i;
goto error;
}
element->extra->children[i] = child;
}
element->extra->length = self->extra->length;
}
/* add object to memo dictionary (so deepcopy won't visit it again) */
id = PyLong_FromSsize_t((Py_uintptr_t) self);
if (!id)
goto error;
i = PyDict_SetItem(memo, id, (PyObject*) element);
Py_DECREF(id);
if (i < 0)
goto error;
return (PyObject*) element;
error:
Py_DECREF(element);
return NULL;
}
static PyObject*
element_sizeof(PyObject* myself, PyObject* args)
{
ElementObject *self = (ElementObject*)myself;
Py_ssize_t result = sizeof(ElementObject);
if (self->extra) {
result += sizeof(ElementObjectExtra);
if (self->extra->children != self->extra->_children)
result += sizeof(PyObject*) * self->extra->allocated;
}
return PyLong_FromSsize_t(result);
}
/* dict keys for getstate/setstate. */
#define PICKLED_TAG "tag"
#define PICKLED_CHILDREN "_children"
#define PICKLED_ATTRIB "attrib"
#define PICKLED_TAIL "tail"
#define PICKLED_TEXT "text"
/* __getstate__ returns a fabricated instance dict as in the pure-Python
* Element implementation, for interoperability/interchangeability. This
* makes the pure-Python implementation details an API, but (a) there aren't
* any unnecessary structures there; and (b) it buys compatibility with 3.2
* pickles. See issue #16076.
*/
static PyObject *
element_getstate(ElementObject *self)
{
int i, noattrib;
PyObject *instancedict = NULL, *children;
/* Build a list of children. */
children = PyList_New(self->extra ? self->extra->length : 0);
if (!children)
return NULL;
for (i = 0; i < PyList_GET_SIZE(children); i++) {
PyObject *child = self->extra->children[i];
Py_INCREF(child);
PyList_SET_ITEM(children, i, child);
}
/* Construct the state object. */
noattrib = (self->extra == NULL || self->extra->attrib == Py_None);
if (noattrib)
instancedict = Py_BuildValue("{sOsOs{}sOsO}",
PICKLED_TAG, self->tag,
PICKLED_CHILDREN, children,
PICKLED_ATTRIB,
PICKLED_TEXT, JOIN_OBJ(self->text),
PICKLED_TAIL, JOIN_OBJ(self->tail));
else
instancedict = Py_BuildValue("{sOsOsOsOsO}",
PICKLED_TAG, self->tag,
PICKLED_CHILDREN, children,
PICKLED_ATTRIB, self->extra->attrib,
PICKLED_TEXT, JOIN_OBJ(self->text),
PICKLED_TAIL, JOIN_OBJ(self->tail));
if (instancedict) {
Py_DECREF(children);
return instancedict;
}
else {
for (i = 0; i < PyList_GET_SIZE(children); i++)
Py_DECREF(PyList_GET_ITEM(children, i));
Py_DECREF(children);
return NULL;
}
}
static PyObject *
element_setstate_from_attributes(ElementObject *self,
PyObject *tag,
PyObject *attrib,
PyObject *text,
PyObject *tail,
PyObject *children)
{
Py_ssize_t i, nchildren;
if (!tag) {
PyErr_SetString(PyExc_TypeError, "tag may not be NULL");
return NULL;
}
Py_CLEAR(self->tag);
self->tag = tag;
Py_INCREF(self->tag);
_clear_joined_ptr(&self->text);
self->text = text ? JOIN_SET(text, PyList_CheckExact(text)) : Py_None;
Py_INCREF(JOIN_OBJ(self->text));
_clear_joined_ptr(&self->tail);
self->tail = tail ? JOIN_SET(tail, PyList_CheckExact(tail)) : Py_None;
Py_INCREF(JOIN_OBJ(self->tail));
/* Handle ATTRIB and CHILDREN. */
if (!children && !attrib)
Py_RETURN_NONE;
/* Compute 'nchildren'. */
if (children) {
if (!PyList_Check(children)) {
PyErr_SetString(PyExc_TypeError, "'_children' is not a list");
return NULL;
}
nchildren = PyList_Size(children);
}
else {
nchildren = 0;
}
/* Allocate 'extra'. */
if (element_resize(self, nchildren)) {
return NULL;
}
assert(self->extra && self->extra->allocated >= nchildren);
/* Copy children */
for (i = 0; i < nchildren; i++) {
self->extra->children[i] = PyList_GET_ITEM(children, i);
Py_INCREF(self->extra->children[i]);
}
self->extra->length = nchildren;
self->extra->allocated = nchildren;
/* Stash attrib. */
if (attrib) {
Py_CLEAR(self->extra->attrib);
self->extra->attrib = attrib;
Py_INCREF(attrib);
}
Py_RETURN_NONE;
}
/* __setstate__ for Element instance from the Python implementation.
* 'state' should be the instance dict.
*/
static PyObject *
element_setstate_from_Python(ElementObject *self, PyObject *state)
{
static char *kwlist[] = {PICKLED_TAG, PICKLED_ATTRIB, PICKLED_TEXT,
PICKLED_TAIL, PICKLED_CHILDREN, 0};
PyObject *args;
PyObject *tag, *attrib, *text, *tail, *children;
PyObject *retval;
tag = attrib = text = tail = children = NULL;
args = PyTuple_New(0);
if (!args)
return NULL;
if (PyArg_ParseTupleAndKeywords(args, state, "|$OOOOO", kwlist, &tag,
&attrib, &text, &tail, &children))
retval = element_setstate_from_attributes(self, tag, attrib, text,
tail, children);
else
retval = NULL;
Py_DECREF(args);
return retval;
}
static PyObject *
element_setstate(ElementObject *self, PyObject *state)
{
if (!PyDict_CheckExact(state)) {
PyErr_Format(PyExc_TypeError,
"Don't know how to unpickle \"%.200R\" as an Element",
state);
return NULL;
}
else
return element_setstate_from_Python(self, state);
}
LOCAL(int)
checkpath(PyObject* tag)
{
Py_ssize_t i;
int check = 1;
/* check if a tag contains an xpath character */
#define PATHCHAR(ch) \
(ch == '/' || ch == '*' || ch == '[' || ch == '@' || ch == '.')
0