xml parser CHANGE optimize attribute/namespace structure
compact attribute structure to save some space in cost of a little
bit more complicated attributes manipulation (which is very rare)
diff --git a/src/xml.c b/src/xml.c
index 999f7ed..dfedb99 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -71,47 +71,6 @@
}
void
-lyxml_unlink_attr(struct lyxml_attr *attr)
-{
- struct lyxml_attr *prev;
-
- if (!attr) {
- return;
- }
-
- if (!attr->parent) {
- /* hmm, something is probably wrong */
- attr->next = NULL;
- return;
- }
-
- prev = attr->parent->attr;
- if (prev == attr) {
- /* unlinking the first attribute -> update the element's pointer */
- attr->parent->attr = attr->next;
- } else {
- while (prev && prev->next != attr) {
- prev = prev->next;
- }
-
- if (!prev) {
- /* something is probably broken */
- attr->parent = NULL;
- attr->next = NULL;
- return;
- }
-
- /* fix the previous's attribute pointer to next in the list */
- prev->next = attr->next;
- }
-
- attr->parent = NULL;
- attr->next = NULL;
-
- return;
-}
-
-void
lyxml_unlink_elem(struct lyxml_elem *elem)
{
struct lyxml_elem *parent, *first;
@@ -163,13 +122,36 @@
}
void
-lyxml_free_attr(struct ly_ctx *ctx, struct lyxml_attr *attr)
+lyxml_free_attr(struct ly_ctx *ctx, struct lyxml_elem *parent, struct lyxml_attr *attr)
{
+ struct lyxml_attr *aiter, *aprev;
+
if (!attr) {
return;
}
- lyxml_unlink_attr(attr);
+ if (parent) {
+ /* unlink attribute from the parent's list of attributes */
+ aprev = NULL;
+ for (aiter = parent->attr; aiter; aiter = aiter->next) {
+ if (aiter == attr) {
+ break;
+ }
+ aprev = aiter;
+ }
+ if (!aiter) {
+ /* attribute to remove not found */
+ return;
+ }
+
+ if (!aprev) {
+ /* attribute is first in parent's list of attributes */
+ parent->attr = attr->next;
+ } else {
+ /* reconnect previous attribute to the next */
+ aprev->next = attr->next;
+ }
+ }
lydict_remove(ctx, attr->name);
lydict_remove(ctx, attr->value);
free(attr);
@@ -224,31 +206,6 @@
lyxml_free_elem_(ctx, elem);
}
-int
-lyxml_add_attr(struct lyxml_elem *parent, struct lyxml_attr *attr)
-{
- struct lyxml_attr *a;
-
- assert(parent);
- assert(attr);
-
- /* (re)link attribute to parent */
- if (attr->parent) {
- lyxml_unlink_attr(attr);
- }
- attr->parent = parent;
-
- /* link parent to attribute */
- if (parent->attr) {
- for (a = parent->attr; a->next; a = a->next);
- a->next = attr;
- } else {
- parent->attr = attr;
- }
-
- return EXIT_SUCCESS;
-}
-
const char *
lyxml_get_attr(struct lyxml_elem *elem, const char *name, const char *ns)
{
@@ -657,11 +614,11 @@
}
struct lyxml_attr *
-lyxml_dup_attr(struct ly_ctx *ctx, struct lyxml_attr *attr)
+lyxml_dup_attr(struct ly_ctx *ctx, struct lyxml_elem *parent, struct lyxml_attr *attr)
{
- struct lyxml_attr *result;
+ struct lyxml_attr *result, *a;
- if (!attr) {
+ if (!attr || !parent) {
return NULL;
}
@@ -678,6 +635,27 @@
result->name = lydict_insert(ctx, attr->name, 0);
result->type = attr->type;
+ /* set namespace in case of standard attributes */
+ if (result->type == LYXML_ATTR_STD && attr->ns) {
+ result->ns = get_ns(parent, attr->ns->prefix);
+ }
+
+ /* set parent pointer in case of namespace attribute */
+ if (result->type == LYXML_ATTR_NS) {
+ ((struct lyxml_ns *)result)->parent = parent;
+ }
+
+ /* put attribute into the parent's attributes list */
+ if (parent->attr) {
+ /* go to the end of the list */
+ for (a = parent->attr; a->next; a = a->next);
+ /* and append new attribute */
+ a->next = result;
+ } else {
+ /* add the first attribute in the list */
+ parent->attr = result;
+ }
+
return result;
}
@@ -685,7 +663,7 @@
lyxml_dup_elem(struct ly_ctx *ctx, struct lyxml_elem *elem, struct lyxml_elem *parent, int recursive)
{
struct lyxml_elem *result, *child;
- struct lyxml_attr *attr, *attr_dup;
+ struct lyxml_attr *attr;
if (!elem) {
return NULL;
@@ -709,11 +687,7 @@
/* duplicate attributes */
for (attr = elem->attr; attr; attr = attr->next) {
- attr_dup = lyxml_dup_attr(ctx, attr);
- if (attr->type == LYXML_ATTR_STD && attr->ns) {
- attr_dup->ns = get_ns(result, attr->ns->prefix);
- }
- lyxml_add_attr(result, attr_dup);
+ lyxml_dup_attr(ctx, result, attr);
}
if (!recursive) {
@@ -729,12 +703,12 @@
}
static struct lyxml_attr *
-parse_attr(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml_elem *elem)
+parse_attr(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml_elem *parent)
{
const char *c = data, *start, *delim;
char prefix[32];
int uc;
- struct lyxml_attr *attr = NULL;
+ struct lyxml_attr *attr = NULL, *a;
unsigned int size;
/* check if it is attribute or namespace */
@@ -742,6 +716,7 @@
/* namespace */
attr = calloc(1, sizeof (struct lyxml_ns));
attr->type = LYXML_ATTR_NS;
+ ((struct lyxml_ns *)attr)->parent = parent;
c += 5;
if (*c != ':') {
/* default namespace, prefix will be empty */
@@ -772,7 +747,7 @@
/* look for the prefix in namespaces */
memcpy(prefix, data, c - data);
prefix[c - data] = '\0';
- attr->ns = get_ns(elem, prefix);
+ attr->ns = get_ns(parent, prefix);
}
c += size;
uc = getutf8(c, &size);
@@ -804,10 +779,22 @@
}
*len = c + size + 1 - data; /* +1 is delimiter size */
+
+ /* put attribute into the parent's attributes list */
+ if (parent->attr) {
+ /* go to the end of the list */
+ for (a = parent->attr; a->next; a = a->next);
+ /* and append new attribute */
+ a->next = attr;
+ } else {
+ /* add the first attribute in the list */
+ parent->attr = attr;
+ }
+
return attr;
error:
- lyxml_free_attr(ctx, attr);
+ lyxml_free_attr(ctx, NULL, attr);
return NULL;
}
@@ -1039,7 +1026,6 @@
if (!attr) {
goto error;
}
- lyxml_add_attr(elem, attr);
c += size; /* move after processed attribute */
/* check namespace */