xml CHANGE hide namespace handling into the XML parser

Adding/removing namespaces can be done automaticcaly inside the parser
functions, so do not bother caller with it.
diff --git a/src/xml.c b/src/xml.c
index 195ce56..89fc353 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -168,6 +168,102 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Add namespace definition into XML context.
+ *
+ * Namespaces from a single element are supposed to be added sequentially together (not interleaved by a namespace from other
+ * element). This mimic namespace visibility, since the namespace defined in element E is not visible from its parents or
+ * siblings. On the other hand, namespace from a parent element can be redefined in a child element. This is also reflected
+ * by lyxml_ns_get() which returns the most recent namespace definition for the given prefix.
+ *
+ * When leaving processing of a subtree of some element (after it is removed from context->elements), caller is supposed to call
+ * lyxml_ns_rm() to remove all the namespaces defined in such an element from the context.
+ *
+ * @param[in] context XML context to work with.
+ * @param[in] prefix Pointer to the namespace prefix as taken from lyxml_get_attribute(). Can be NULL for default namespace.
+ * @param[in] prefix_len Length of the prefix string (since it is not NULL-terminated when returned from lyxml_get_attribute()).
+ * @param[in] uri Namespace URI (value) to store. Value can be obtained via lyxml_get_string() and caller is not supposed to
+ * work with the pointer when the function succeeds. In case of error the value is freed.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lyxml_ns_add(struct lyxml_context *context, const char *prefix, size_t prefix_len, char *uri)
+{
+    struct lyxml_ns *ns;
+
+    ns = malloc(sizeof *ns);
+    LY_CHECK_ERR_RET(!ns, LOGMEM(context->ctx), LY_EMEM);
+
+    /* we need to connect the depth of the element where the namespace is defined with the
+     * namespace record to be able to maintain (remove) the record when the parser leaves
+     * (to its sibling or back to the parent) the element where the namespace was defined */
+    ns->depth = context->elements.count;
+
+    ns->uri = uri;
+    if (prefix) {
+        ns->prefix = strndup(prefix, prefix_len);
+        LY_CHECK_ERR_RET(!ns->prefix, LOGMEM(context->ctx); free(ns->uri); free(ns), LY_EMEM);
+    } else {
+        ns->prefix = NULL;
+    }
+
+    LY_CHECK_ERR_RET(ly_set_add(&context->ns, ns, LY_SET_OPT_USEASLIST) == -1,
+                     free(ns->prefix); free(ns->uri); free(ns), LY_EMEM);
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Remove all the namespaces defined in the element recently closed (removed from the context->elements).
+ *
+ * @param[in] context XML context to work with.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lyxml_ns_rm(struct lyxml_context *context)
+{
+    unsigned int u;
+
+    for (u = context->ns.count - 1; u + 1 > 0; --u) {
+        if (((struct lyxml_ns *)context->ns.objs[u])->depth != context->elements.count + 1) {
+            /* we are done, the namespaces from a single element are supposed to be together */
+            break;
+        }
+        /* remove the ns structure */
+        free(((struct lyxml_ns *)context->ns.objs[u])->prefix);
+        free(((struct lyxml_ns *)context->ns.objs[u])->uri);
+        free(context->ns.objs[u]);
+        --context->ns.count;
+    }
+
+    if (!context->ns.count) {
+        /* cleanup the context's namespaces storage */
+        ly_set_erase(&context->ns, NULL);
+    }
+
+    return LY_SUCCESS;
+}
+
+const struct lyxml_ns *
+lyxml_ns_get(struct lyxml_context *context, const char *prefix, size_t prefix_len)
+{
+    unsigned int u;
+    struct lyxml_ns *ns;
+
+    for (u = context->ns.count - 1; u + 1 > 0; --u) {
+        ns = (struct lyxml_ns *)context->ns.objs[u];
+        if (prefix) {
+            if (!strncmp(prefix, ns->prefix, prefix_len) && ns->prefix[prefix_len] == '\0') {
+                return ns;
+            }
+        } else if (!ns->prefix) {
+            /* default namespace */
+            return ns;
+        }
+    }
+
+    return NULL;
+}
+
 LY_ERR
 lyxml_get_string(struct lyxml_context *context, const char **input, char **buffer, size_t *buffer_size, char **output, size_t *length, int *dynamic)
 {
@@ -190,7 +286,7 @@
     uint32_t n;
     size_t u, newlines;
     bool empty_content = false;
-    LY_ERR rc;
+    LY_ERR rc = LY_SUCCESS;
 
     assert(context);
     assert(context->status == LYXML_ELEM_CONTENT || context->status == LYXML_ATTR_CONTENT);
@@ -402,11 +498,14 @@
             /* remove the closed element record from the tags list */
             free(context->elements.objs[context->elements.count - 1]);
             --context->elements.count;
+
+            /* remove also the namespaces conneted with the element */
+            rc = lyxml_ns_rm(context);
         }
     }
 
     (*input) = in;
-    return LY_SUCCESS;
+    return rc;
 
 #undef BUFSIZE
 #undef BUFSIZE_STEP
@@ -424,7 +523,11 @@
     LY_ERR rc;
     unsigned int c;
     size_t endtag_len;
+    int is_ns = 0;
+    const char *ns_prefix = NULL;
+    size_t ns_prefix_len = 0;
 
+start:
     /* initialize output variables */
     (*prefix) = (*name) = NULL;
     (*prefix_len) = (*name_len) = 0;
@@ -476,6 +579,36 @@
     }
     context->status = LYXML_ATTR_CONTENT;
 
+    is_ns = 0;
+    if (*prefix && *prefix_len == 5 && !strncmp(*prefix, "xmlns", 5)) {
+        is_ns = 1;
+        ns_prefix = *name;
+        ns_prefix_len = *name_len;
+    } else if (*name_len == 5 && !strncmp(*name, "xmlns", 5)) {
+        is_ns = 1;
+    }
+    if (is_ns) {
+        /* instead of attribute, we have namespace specification,
+         * so process it automatically and then move to another attribute (if any) */
+        char *value = NULL;
+        size_t value_len = 0;
+        int dynamic = 0;
+
+        LY_CHECK_RET(lyxml_get_string(context, &in, &value, &value_len, &value, &value_len, &dynamic));
+        if ((rc = lyxml_ns_add(context, ns_prefix, ns_prefix_len, dynamic ? value : strndup(value, value_len)))) {
+            if (dynamic) {
+                free(value);
+                return rc;
+            }
+        }
+        if (context->status == LYXML_ATTRIBUTE) {
+            goto start;
+        } else {
+            (*prefix) = (*name) = NULL;
+            (*prefix_len) = (*name_len) = 0;
+        }
+    }
+
     /* move caller's input */
     (*input) = in;
     return LY_SUCCESS;
@@ -602,6 +735,10 @@
                 /* opening and closing element tags matches, remove record from the opening tags list */
                 free(e);
                 --context->elements.count;
+
+                /* remove also the namespaces conneted with the element */
+                rc = lyxml_ns_rm(context);
+
                 /* do not return element information to announce closing element being currently processed */
                 *name = *prefix = NULL;
                 *name_len = *prefix_len = 0;
@@ -650,82 +787,6 @@
     return LY_SUCCESS;
 }
 
-LY_ERR
-lyxml_ns_add(struct lyxml_context *context, const char *element_name, const char *prefix, size_t prefix_len, char *uri)
-{
-    struct lyxml_ns *ns;
-
-    ns = malloc(sizeof *ns);
-    LY_CHECK_ERR_RET(!ns, LOGMEM(context->ctx), LY_EMEM);
-
-    /* to distinguish 2 elements, we need not only the name, but also its depth in the XML tree.
-     * In case some dictionary is used to store elements' names (so name strings of 2 distinguish nodes
-     * actually points to the same memory), so the depth is necessary to distinguish parent/child nodes
-     * of the same name. Otherwise, the namespace defined in parent could be removed when leaving child node. */
-    ns->element_depth = context->elements.count;
-    ns->element = element_name;
-
-    ns->uri = uri;
-    if (prefix) {
-        ns->prefix = strndup(prefix, prefix_len);
-        LY_CHECK_ERR_RET(!ns->prefix, LOGMEM(context->ctx); free(ns), LY_EMEM);
-    } else {
-        ns->prefix = NULL;
-    }
-
-    LY_CHECK_ERR_RET(ly_set_add(&context->ns, ns, LY_SET_OPT_USEASLIST) == -1, free(ns->prefix), LY_EMEM);
-    return LY_SUCCESS;
-}
-
-const struct lyxml_ns *
-lyxml_ns_get(struct lyxml_context *context, const char *prefix, size_t prefix_len)
-{
-    unsigned int u;
-    struct lyxml_ns *ns;
-
-    for (u = context->ns.count - 1; u + 1 > 0; --u) {
-        ns = (struct lyxml_ns *)context->ns.objs[u];
-        if (prefix) {
-            if (!strncmp(prefix, ns->prefix, prefix_len) && ns->prefix[prefix_len] == '\0') {
-                return ns;
-            }
-        } else if (!ns->prefix) {
-            /* default namespace */
-            return ns;
-        }
-    }
-
-    return NULL;
-}
-
-LY_ERR
-lyxml_ns_rm(struct lyxml_context *context, const char *element_name)
-{
-    unsigned int u;
-
-    for (u = context->ns.count - 1; u + 1 > 0; --u) {
-        if (((struct lyxml_ns *)context->ns.objs[u])->element != element_name ||
-                ((struct lyxml_ns *)context->ns.objs[u])->element_depth != context->elements.count + 1) {
-            /* we are done, the namespaces from a single element are supposed to be together;
-             * the second condition is there to distinguish parent/child elements with the same name
-             * (which are for some reason stored at the same memory chunk), so we need to distinguish
-             * level of the node */
-            break;
-        }
-        /* remove the ns structure */
-        free(((struct lyxml_ns *)context->ns.objs[u])->prefix);
-        free(((struct lyxml_ns *)context->ns.objs[u])->uri);
-        free(context->ns.objs[u]);
-        --context->ns.count;
-    }
-
-    if (!context->ns.count) {
-        /* cleanup the context's namespaces storage */
-        ly_set_erase(&context->ns, NULL);
-    }
-
-    return LY_SUCCESS;
-}
 
 void
 lyxml_context_clear(struct lyxml_context *context)