Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of libdom.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
  6.  * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
  7.  */
  8.  
  9. #include <assert.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13.  
  14. #include <libwapcaplet/libwapcaplet.h>
  15.  
  16. #include <dom/dom.h>
  17. #include <dom/core/attr.h>
  18. #include <dom/core/element.h>
  19. #include <dom/core/node.h>
  20. #include <dom/core/string.h>
  21. #include <dom/core/document.h>
  22. #include <dom/events/events.h>
  23.  
  24. #include "core/attr.h"
  25. #include "core/document.h"
  26. #include "core/element.h"
  27. #include "core/node.h"
  28. #include "core/namednodemap.h"
  29. #include "utils/validate.h"
  30. #include "utils/namespace.h"
  31. #include "utils/utils.h"
  32. #include "utils/list.h"
  33. #include "events/mutation_event.h"
  34.  
  35. struct dom_element_vtable _dom_element_vtable = {
  36.         {
  37.                 {
  38.                         DOM_NODE_EVENT_TARGET_VTABLE
  39.                 },
  40.                 DOM_NODE_VTABLE_ELEMENT
  41.         },
  42.         DOM_ELEMENT_VTABLE
  43. };
  44.  
  45. static struct dom_element_protected_vtable element_protect_vtable = {
  46.         {
  47.                 DOM_NODE_PROTECT_VTABLE_ELEMENT
  48.         },
  49.         DOM_ELEMENT_PROTECT_VTABLE
  50. };
  51.  
  52.  
  53. typedef struct dom_attr_list {
  54.         struct list_entry list; /**< Linked list links to prev/next entries */
  55.        
  56.         struct dom_attr *attr;
  57.  
  58.         struct dom_string *name;
  59.         struct dom_string *namespace;
  60. } dom_attr_list;
  61.  
  62.  
  63. /**
  64.  * Destroy element's class cache
  65.  *
  66.  * \param ele  The element
  67.  */
  68. static void _dom_element_destroy_classes(struct dom_element *ele)
  69. {
  70.         /* Destroy the pre-separated class names */
  71.         if (ele->classes != NULL) {
  72.                 unsigned int class;
  73.                 for (class = 0; class < ele->n_classes; class++) {
  74.                         lwc_string_unref(ele->classes[class]);
  75.                 }
  76.                 free(ele->classes);
  77.         }
  78.  
  79.         ele->n_classes = 0;
  80.         ele->classes = NULL;
  81. }
  82.  
  83.  
  84. /**
  85.  * Create element's class cache from class attribute value
  86.  *
  87.  * \param ele    The element
  88.  * \param value  The class attribute value
  89.  *
  90.  * Destroys any existing cached classes.
  91.  */
  92. static dom_exception _dom_element_create_classes(struct dom_element *ele,
  93.                 const char *value)
  94. {
  95.         const char *pos;
  96.         lwc_string **classes = NULL;
  97.         uint32_t n_classes = 0;
  98.  
  99.         /* Any existing cached classes are replaced; destroy them */
  100.         _dom_element_destroy_classes(ele);
  101.  
  102.         /* Count number of classes */
  103.         for (pos = value; *pos != '\0'; ) {
  104.                 if (*pos != ' ') {
  105.                         while (*pos != ' ' && *pos != '\0')
  106.                                 pos++;
  107.                         n_classes++;
  108.                 } else {
  109.                         while (*pos == ' ')
  110.                                 pos++;
  111.                 }
  112.         }
  113.  
  114.         /* If there are some, unpack them */
  115.         if (n_classes > 0) {
  116.                 classes = malloc(n_classes * sizeof(lwc_string *));
  117.                 if (classes == NULL)
  118.                         return DOM_NO_MEM_ERR;
  119.  
  120.                 for (pos = value, n_classes = 0;
  121.                                 *pos != '\0'; ) {
  122.                         if (*pos != ' ') {
  123.                                 const char *s = pos;
  124.                                 while (*pos != ' ' && *pos != '\0')
  125.                                         pos++;
  126.                                 if (lwc_intern_string(s, pos - s,
  127.                                                 &classes[n_classes++]) !=
  128.                                                 lwc_error_ok)
  129.                                         goto error;
  130.                         } else {
  131.                                 while (*pos == ' ')
  132.                                         pos++;
  133.                         }
  134.                 }
  135.         }
  136.  
  137.         ele->n_classes = n_classes;
  138.         ele->classes = classes;
  139.  
  140.         return DOM_NO_ERR;
  141. error:
  142.         while (n_classes > 0)
  143.                 lwc_string_unref(classes[--n_classes]);
  144.  
  145.         free(classes);
  146.                
  147.         return DOM_NO_MEM_ERR;
  148. }
  149.  
  150. /* Attribute linked list releated functions */
  151.  
  152. /**
  153.  * Get the next attribute in the list
  154.  *
  155.  * \param n  The attribute list node
  156.  * \return The next attribute node
  157.  */
  158. static dom_attr_list * _dom_element_attr_list_next(const dom_attr_list *n)
  159. {
  160.         return (dom_attr_list *)(n->list.next);
  161. }
  162.  
  163. /**
  164.  * Unlink an attribute list node from its linked list
  165.  *
  166.  * \param n  The attribute list node
  167.  */
  168. static void _dom_element_attr_list_node_unlink(dom_attr_list *n)
  169. {
  170.         if (n == NULL)
  171.                 return;
  172.  
  173.         list_del(&n->list);
  174. }
  175.  
  176. /**
  177.  * Insert attribute list node into attribute list
  178.  *
  179.  * \param list      The list header
  180.  * \param new_attr  The attribute node to insert
  181.  */
  182. static void _dom_element_attr_list_insert(dom_attr_list *list,
  183.                 dom_attr_list *new_attr)
  184. {
  185.         assert(list != NULL);
  186.         assert(new_attr != NULL);
  187.         list_append(&list->list, &new_attr->list);
  188. }
  189.  
  190. /**
  191.  * Get attribute from attribute list, which matches given name
  192.  *
  193.  * \param list  The attribute list to search
  194.  * \param name  The name of the attribute to search for
  195.  * \param name  The namespace of the attribute to search for (may be NULL)
  196.  * \return the matching attribute, or NULL if none found
  197.  */
  198. static dom_attr_list * _dom_element_attr_list_find_by_name(
  199.                 dom_attr_list *list, dom_string *name, dom_string *namespace)
  200. {
  201.         dom_attr_list *attr = list;
  202.  
  203.         if (list == NULL || name == NULL)
  204.                 return NULL;
  205.  
  206.         do {
  207.                 if (((namespace == NULL && attr->namespace == NULL) ||
  208.                                 (namespace != NULL && attr->namespace != NULL &&
  209.                                                 dom_string_isequal(namespace,
  210.                                                 attr->namespace))) &&
  211.                                 dom_string_isequal(name, attr->name)) {
  212.                         /* Both have NULL namespace or matching namespace,
  213.                          * and both have same name */
  214.                         return attr;
  215.                 }
  216.  
  217.                 attr = _dom_element_attr_list_next(attr);
  218.                 assert(attr != NULL);
  219.         } while (attr != list);
  220.  
  221.         return NULL;
  222. }
  223.  
  224. /**
  225.  * Get the number of elements in this attribute list
  226.  *
  227.  * \param list  The attribute list
  228.  * \return the number attribute list node elements
  229.  */
  230. static unsigned int _dom_element_attr_list_length(dom_attr_list *list)
  231. {
  232.         dom_attr_list *attr = list;
  233.         unsigned int count = 0;
  234.  
  235.         if (list == NULL)
  236.                 return count;
  237.  
  238.         do {
  239.                 count++;
  240.  
  241.                 attr = _dom_element_attr_list_next(attr);
  242.         } while (attr != list);
  243.  
  244.         return count;
  245. }
  246.  
  247. /**
  248.  * Get the attribute list node at the given index
  249.  *
  250.  * \param list   The attribute list
  251.  * \param index  The index number
  252.  * \return the attribute list node at given index
  253.  */
  254. static dom_attr_list * _dom_element_attr_list_get_by_index(dom_attr_list *list,
  255.                 unsigned int index)
  256. {
  257.         dom_attr_list *attr = list;
  258.  
  259.         if (list == NULL)
  260.                 return NULL;
  261.  
  262.         do {
  263.                 if (--index == 0)
  264.                         return attr;
  265.  
  266.                 attr = _dom_element_attr_list_next(attr);
  267.         } while (attr != list);
  268.  
  269.         return NULL;
  270. }
  271.  
  272. /**
  273.  * Destroy an attribute list node, and its attribute
  274.  *
  275.  * \param n  The attribute list node to destroy
  276.  */
  277. static void _dom_element_attr_list_node_destroy(dom_attr_list *n)
  278. {
  279.         dom_node_internal *a;
  280.         dom_document *doc;
  281.  
  282.         assert(n != NULL);
  283.         assert(n->attr != NULL);
  284.         assert(n->name != NULL);
  285.  
  286.         a = (dom_node_internal *) n->attr;
  287.  
  288.         /* Need to destroy classes cache, when removing class attribute */
  289.         doc = a->owner;
  290.         if (n->namespace == NULL &&
  291.                         dom_string_isequal(n->name, doc->class_string)) {
  292.                 _dom_element_destroy_classes((dom_element *)(a->parent));
  293.         }
  294.  
  295.         /* Destroy rest of list node */
  296.         dom_string_unref(n->name);
  297.  
  298.         if (n->namespace != NULL)
  299.                 dom_string_unref(n->namespace);
  300.  
  301.         a->parent = NULL;
  302.         dom_node_try_destroy(a);
  303.  
  304.         free(n);
  305. }
  306.  
  307. /**
  308.  * Create an attribute list node
  309.  *
  310.  * \param attr       The attribute to create a list node for
  311.  * \param name       The attribute name
  312.  * \param namespace  The attribute namespace (may be NULL)
  313.  * \return the new attribute list node, or NULL on failure
  314.  */
  315. static dom_attr_list * _dom_element_attr_list_node_create(dom_attr *attr,
  316.                 dom_element *ele, dom_string *name, dom_string *namespace)
  317. {
  318.         dom_attr_list *new_list_node;
  319.         dom_node_internal *a;
  320.         dom_document *doc;
  321.  
  322.         if (attr == NULL || name == NULL)
  323.                 return NULL;
  324.  
  325.         new_list_node = malloc(sizeof(*new_list_node));
  326.         if (new_list_node == NULL)
  327.                 return NULL;
  328.  
  329.         list_init(&new_list_node->list);
  330.  
  331.         new_list_node->attr = attr;
  332.         new_list_node->name = name;
  333.         new_list_node->namespace = namespace;
  334.  
  335.         a = (dom_node_internal *) attr;
  336.         doc = a->owner;
  337.         if (namespace == NULL &&
  338.                         dom_string_isequal(name, doc->class_string)) {
  339.                 dom_string *value;
  340.  
  341.                 if (DOM_NO_ERR != _dom_attr_get_value(attr, &value)) {
  342.                         _dom_element_attr_list_node_destroy(new_list_node);
  343.                         return NULL;
  344.                 }
  345.  
  346.                 if (DOM_NO_ERR != _dom_element_create_classes(ele,
  347.                                 dom_string_data(value))) {
  348.                         _dom_element_attr_list_node_destroy(new_list_node);
  349.                         dom_string_unref(value);
  350.                         return NULL;
  351.                 }
  352.  
  353.                 dom_string_unref(value);
  354.         }
  355.  
  356.         return new_list_node;
  357. }
  358.  
  359. /**
  360.  * Destroy an entire attribute list, and its attributes
  361.  *
  362.  * \param list  The attribute list to destroy
  363.  */
  364. static void _dom_element_attr_list_destroy(dom_attr_list *list)
  365. {
  366.         dom_attr_list *attr = list;
  367.         dom_attr_list *next = list;
  368.  
  369.         if (list == NULL)
  370.                 return;
  371.  
  372.         do {
  373.                 attr = next;
  374.                 next = _dom_element_attr_list_next(attr);
  375.  
  376.                 _dom_element_attr_list_node_unlink(attr);
  377.                 _dom_element_attr_list_node_destroy(attr);
  378.         } while (next != attr);
  379.  
  380.         return;
  381. }
  382.  
  383. /**
  384.  * Clone an attribute list node, and its attribute
  385.  *
  386.  * \param n     The attribute list node to clone
  387.  * \param newe  Element to clone attribute for
  388.  * \return the new attribute list node, or NULL on failure
  389.  */
  390. static dom_attr_list *_dom_element_attr_list_node_clone(dom_attr_list *n,
  391.                 dom_element *newe)
  392. {
  393.         dom_attr *clone = NULL;
  394.         dom_attr_list *new_list_node;
  395.         dom_exception err;
  396.  
  397.         assert(n != NULL);
  398.         assert(n->attr != NULL);
  399.         assert(n->name != NULL);
  400.  
  401.         new_list_node = malloc(sizeof(*new_list_node));
  402.         if (new_list_node == NULL)
  403.                 return NULL;
  404.  
  405.         list_init(&new_list_node->list);
  406.  
  407.         new_list_node->name = NULL;
  408.         new_list_node->namespace = NULL;
  409.  
  410.         err = dom_node_clone_node(n->attr, true, (void *) &clone);
  411.         if (err != DOM_NO_ERR) {
  412.                 free(new_list_node);
  413.                 return NULL;
  414.         }
  415.  
  416.         dom_node_set_parent(clone, newe);
  417.         dom_node_remove_pending(clone);
  418.         dom_node_unref(clone);
  419.         new_list_node->attr = clone;
  420.  
  421.         if (n->name != NULL)
  422.                 new_list_node->name = dom_string_ref(n->name);
  423.  
  424.         if (n->namespace != NULL)
  425.                 new_list_node->namespace = dom_string_ref(n->namespace);
  426.  
  427.         return new_list_node;
  428. }
  429.  
  430. /**
  431.  * Clone an entire attribute list, and its attributes
  432.  *
  433.  * \param list  The attribute list to clone
  434.  * \param newe  Element to clone list for
  435.  * \return the new attribute list, or NULL on failure
  436.  */
  437. static dom_attr_list *_dom_element_attr_list_clone(dom_attr_list *list,
  438.                 dom_element *newe)
  439. {
  440.         dom_attr_list *attr = list;
  441.  
  442.         dom_attr_list *new_list = NULL;
  443.         dom_attr_list *new_list_node = NULL;
  444.  
  445.         if (list == NULL)
  446.                 return NULL;
  447.  
  448.         do {
  449.                 new_list_node = _dom_element_attr_list_node_clone(attr, newe);
  450.                 if (new_list_node == NULL) {
  451.                         if (new_list != NULL)
  452.                                 _dom_element_attr_list_destroy(new_list);
  453.                         return NULL;
  454.                 }
  455.  
  456.                 if (new_list == NULL) {
  457.                         new_list = new_list_node;
  458.                 } else {
  459.                         _dom_element_attr_list_insert(new_list, new_list_node);
  460.                 }
  461.  
  462.                 attr = _dom_element_attr_list_next(attr);
  463.         } while (attr != list);
  464.  
  465.         return new_list;
  466. }
  467.  
  468. static dom_exception _dom_element_get_attr(struct dom_element *element,
  469.                 dom_string *namespace, dom_string *name, dom_string **value);
  470. static dom_exception _dom_element_set_attr(struct dom_element *element,
  471.                 dom_string *namespace, dom_string *name, dom_string *value);
  472. static dom_exception _dom_element_remove_attr(struct dom_element *element,
  473.                 dom_string *namespace, dom_string *name);
  474.  
  475. static dom_exception _dom_element_get_attr_node(struct dom_element *element,
  476.                 dom_string *namespace, dom_string *name,
  477.                 struct dom_attr **result);
  478. static dom_exception _dom_element_set_attr_node(struct dom_element *element,
  479.                 dom_string *namespace, struct dom_attr *attr,
  480.                 struct dom_attr **result);
  481. static dom_exception _dom_element_remove_attr_node(struct dom_element *element,
  482.                 dom_string *namespace, struct dom_attr *attr,
  483.                 struct dom_attr **result);
  484.  
  485. static dom_exception _dom_element_has_attr(struct dom_element *element,
  486.                 dom_string *namespace, dom_string *name, bool *result);
  487. static dom_exception _dom_element_set_id_attr(struct dom_element *element,
  488.                 dom_string *namespace, dom_string *name, bool is_id);
  489.  
  490.  
  491. /* The operation set for namednodemap */
  492. static dom_exception attributes_get_length(void *priv,
  493.                 uint32_t *length);
  494. static dom_exception attributes_get_named_item(void *priv,
  495.                 dom_string *name, struct dom_node **node);
  496. static dom_exception attributes_set_named_item(void *priv,
  497.                 struct dom_node *arg, struct dom_node **node);
  498. static dom_exception attributes_remove_named_item(
  499.                 void *priv, dom_string *name,
  500.                 struct dom_node **node);
  501. static dom_exception attributes_item(void *priv,
  502.                 uint32_t index, struct dom_node **node);
  503. static dom_exception attributes_get_named_item_ns(
  504.                 void *priv, dom_string *namespace,
  505.                 dom_string *localname, struct dom_node **node);
  506. static dom_exception attributes_set_named_item_ns(
  507.                 void *priv, struct dom_node *arg,
  508.                 struct dom_node **node);
  509. static dom_exception attributes_remove_named_item_ns(
  510.                 void *priv, dom_string *namespace,
  511.                 dom_string *localname, struct dom_node **node);
  512. static void attributes_destroy(void *priv);
  513. static bool attributes_equal(void *p1, void *p2);
  514.  
  515. static struct nnm_operation attributes_opt = {
  516.         attributes_get_length,
  517.         attributes_get_named_item,
  518.         attributes_set_named_item,
  519.         attributes_remove_named_item,
  520.         attributes_item,
  521.         attributes_get_named_item_ns,
  522.         attributes_set_named_item_ns,
  523.         attributes_remove_named_item_ns,
  524.         attributes_destroy,
  525.         attributes_equal
  526. };
  527.  
  528. /*----------------------------------------------------------------------*/
  529. /* Constructors and Destructors */
  530.  
  531. /**
  532.  * Create an element node
  533.  *
  534.  * \param doc        The owning document
  535.  * \param name       The (local) name of the node to create
  536.  * \param namespace  The namespace URI of the element, or NULL
  537.  * \param prefix     The namespace prefix of the element, or NULL
  538.  * \param result     Pointer to location to receive created element
  539.  * \return DOM_NO_ERR                on success,
  540.  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
  541.  *         DOM_NO_MEM_ERR            on memory exhaustion.
  542.  *
  543.  * ::doc, ::name, ::namespace and ::prefix will have their
  544.  * reference counts increased.
  545.  *
  546.  * The returned element will already be referenced.
  547.  */
  548. dom_exception _dom_element_create(struct dom_document *doc,
  549.                 dom_string *name, dom_string *namespace,
  550.                 dom_string *prefix, struct dom_element **result)
  551. {
  552.         /* Allocate the element */
  553.         *result = malloc(sizeof(struct dom_element));
  554.         if (*result == NULL)
  555.                 return DOM_NO_MEM_ERR;
  556.  
  557.         /* Initialise the vtables */
  558.         (*result)->base.base.vtable = &_dom_element_vtable;
  559.         (*result)->base.vtable = &element_protect_vtable;
  560.  
  561.         return _dom_element_initialise(doc, *result, name, namespace, prefix);
  562. }
  563.  
  564. /**
  565.  * Initialise an element node
  566.  *
  567.  * \param doc        The owning document
  568.  * \param el         The element
  569.  * \param name       The (local) name of the node to create
  570.  * \param namespace  The namespace URI of the element, or NULL
  571.  * \param prefix     The namespace prefix of the element, or NULL
  572.  * \return DOM_NO_ERR                on success,
  573.  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
  574.  *         DOM_NO_MEM_ERR            on memory exhaustion.
  575.  *
  576.  * The caller should make sure that ::name is a valid NCName.
  577.  *
  578.  * ::doc, ::name, ::namespace and ::prefix will have their
  579.  * reference counts increased.
  580.  *
  581.  * The returned element will already be referenced.
  582.  */
  583. dom_exception _dom_element_initialise(struct dom_document *doc,
  584.                 struct dom_element *el, dom_string *name,
  585.                 dom_string *namespace, dom_string *prefix)
  586. {
  587.         dom_exception err;
  588.  
  589.         assert(doc != NULL);
  590.  
  591.         el->attributes = NULL;
  592.  
  593.         /* Initialise the base class */
  594.         err = _dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
  595.                         name, NULL, namespace, prefix);
  596.         if (err != DOM_NO_ERR) {
  597.                 free(el);
  598.                 return err;
  599.         }
  600.  
  601.         /* Perform our type-specific initialisation */
  602.         el->id_ns = NULL;
  603.         el->id_name = NULL;
  604.         el->schema_type_info = NULL;
  605.  
  606.         el->n_classes = 0;
  607.         el->classes = NULL;
  608.  
  609.         return DOM_NO_ERR;
  610. }
  611.  
  612. /**
  613.  * Finalise a dom_element
  614.  *
  615.  * \param ele  The element
  616.  */
  617. void _dom_element_finalise(struct dom_element *ele)
  618. {
  619.         /* Destroy attributes attached to this node */
  620.         if (ele->attributes != NULL) {
  621.                 _dom_element_attr_list_destroy(ele->attributes);
  622.                 ele->attributes = NULL;
  623.         }
  624.  
  625.         if (ele->schema_type_info != NULL) {
  626.                 /** \todo destroy schema type info */
  627.         }
  628.  
  629.         /* Destroy the pre-separated class names */
  630.         _dom_element_destroy_classes(ele);
  631.  
  632.         /* Finalise base class */
  633.         _dom_node_finalise(&ele->base);
  634. }
  635.  
  636. /**
  637.  * Destroy an element
  638.  *
  639.  * \param element  The element to destroy
  640.  *
  641.  * The contents of ::element will be destroyed and ::element will be freed.
  642.  */
  643. void _dom_element_destroy(struct dom_element *element)
  644. {
  645.         _dom_element_finalise(element);
  646.  
  647.         /* Free the element */
  648.         free(element);
  649. }
  650.  
  651. /*----------------------------------------------------------------------*/
  652.  
  653. /* The public virtual functions */
  654.  
  655. /**
  656.  * Retrieve an element's tag name
  657.  *
  658.  * \param element  The element to retrieve the name from
  659.  * \param name     Pointer to location to receive name
  660.  * \return DOM_NO_ERR      on success,
  661.  *         DOM_NO_MEM_ERR  on memory exhaustion.
  662.  *
  663.  * The returned string will have its reference count increased. It is
  664.  * the responsibility of the caller to unref the string once it has
  665.  * finished with it.
  666.  */
  667. dom_exception _dom_element_get_tag_name(struct dom_element *element,
  668.                 dom_string **name)
  669. {
  670.         /* This is the same as nodeName */
  671.         return dom_node_get_node_name((struct dom_node *) element, name);
  672. }
  673.  
  674. /**
  675.  * Retrieve an attribute from an element by name
  676.  *
  677.  * \param element  The element to retrieve attribute from
  678.  * \param name     The attribute's name
  679.  * \param value    Pointer to location to receive attribute's value
  680.  * \return DOM_NO_ERR.
  681.  *
  682.  * The returned string will have its reference count increased. It is
  683.  * the responsibility of the caller to unref the string once it has
  684.  * finished with it.
  685.  */
  686. dom_exception _dom_element_get_attribute(struct dom_element *element,
  687.                 dom_string *name, dom_string **value)
  688. {
  689.         return _dom_element_get_attr(element, NULL, name, value);
  690. }
  691.  
  692. /**
  693.  * Set an attribute on an element by name
  694.  *
  695.  * \param element  The element to set attribute on
  696.  * \param name     The attribute's name
  697.  * \param value    The attribute's value
  698.  * \return DOM_NO_ERR                      on success,
  699.  *         DOM_INVALID_CHARACTER_ERR       if ::name is invalid,
  700.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
  701.  */
  702. dom_exception _dom_element_set_attribute(struct dom_element *element,
  703.                 dom_string *name, dom_string *value)
  704. {
  705.         return _dom_element_set_attr(element, NULL, name, value);
  706. }
  707.  
  708. /**
  709.  * Remove an attribute from an element by name
  710.  *
  711.  * \param element  The element to remove attribute from
  712.  * \param name     The name of the attribute to remove
  713.  * \return DOM_NO_ERR                      on success,
  714.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
  715.  */
  716. dom_exception _dom_element_remove_attribute(struct dom_element *element,
  717.                 dom_string *name)
  718. {
  719.         return _dom_element_remove_attr(element, NULL, name);
  720. }
  721.  
  722. /**
  723.  * Retrieve an attribute node from an element by name
  724.  *
  725.  * \param element  The element to retrieve attribute node from
  726.  * \param name     The attribute's name
  727.  * \param result   Pointer to location to receive attribute node
  728.  * \return DOM_NO_ERR.
  729.  *
  730.  * The returned node will have its reference count increased. It is
  731.  * the responsibility of the caller to unref the node once it has
  732.  * finished with it.
  733.  */
  734. dom_exception _dom_element_get_attribute_node(struct dom_element *element,
  735.                 dom_string *name, struct dom_attr **result)
  736. {
  737.         return _dom_element_get_attr_node(element, NULL, name, result);
  738. }
  739.  
  740. /**
  741.  * Set an attribute node on an element, replacing existing node, if present
  742.  *
  743.  * \param element  The element to add a node to
  744.  * \param attr     The attribute node to add
  745.  * \param result   Pointer to location to receive previous node
  746.  * \return DOM_NO_ERR                      on success,
  747.  *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
  748.  *                                         same document as ::element,
  749.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  750.  *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
  751.  *                                         of another Element node.
  752.  *
  753.  * The returned node will have its reference count increased. It is
  754.  * the responsibility of the caller to unref the node once it has
  755.  * finished with it.
  756.  */
  757. dom_exception _dom_element_set_attribute_node(struct dom_element *element,
  758.                 struct dom_attr *attr, struct dom_attr **result)
  759. {
  760.         return _dom_element_set_attr_node(element, NULL, attr, result);
  761. }
  762.  
  763. /**
  764.  * Remove an attribute node from an element
  765.  *
  766.  * \param element  The element to remove attribute node from
  767.  * \param attr     The attribute node to remove
  768.  * \param result   Pointer to location to receive attribute node
  769.  * \return DOM_NO_ERR                      on success,
  770.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  771.  *         DOM_NOT_FOUND_ERR               if ::attr is not an attribute of
  772.  *                                         ::element.
  773.  *
  774.  * The returned node will have its reference count increased. It is
  775.  * the responsibility of the caller to unref the node once it has
  776.  * finished with it.
  777.  */
  778. dom_exception _dom_element_remove_attribute_node(struct dom_element *element,
  779.                 struct dom_attr *attr, struct dom_attr **result)
  780. {
  781.         return _dom_element_remove_attr_node(element, NULL, attr, result);
  782. }
  783.  
  784. /**
  785.  * Retrieve a list of descendant elements of an element which match a given
  786.  * tag name
  787.  *
  788.  * \param element  The root of the subtree to search
  789.  * \param name     The tag name to match (or "*" for all tags)
  790.  * \param result   Pointer to location to receive result
  791.  * \return DOM_NO_ERR.
  792.  *
  793.  * The returned nodelist will have its reference count increased. It is
  794.  * the responsibility of the caller to unref the nodelist once it has
  795.  * finished with it.
  796.  */
  797. dom_exception _dom_element_get_elements_by_tag_name(
  798.                 struct dom_element *element, dom_string *name,
  799.                 struct dom_nodelist **result)
  800. {
  801.         dom_exception err;
  802.         dom_node_internal *base = (dom_node_internal *) element;
  803.        
  804.         assert(base->owner != NULL);
  805.  
  806.         err = _dom_document_get_nodelist(base->owner, DOM_NODELIST_BY_NAME,
  807.                         (struct dom_node_internal *) element, name, NULL,
  808.                         NULL, result);
  809.  
  810.         return err;
  811. }
  812.  
  813. /**
  814.  * Retrieve an attribute from an element by namespace/localname
  815.  *
  816.  * \param element    The element to retrieve attribute from
  817.  * \param namespace  The attribute's namespace URI, or NULL
  818.  * \param localname  The attribute's local name
  819.  * \param value      Pointer to location to receive attribute's value
  820.  * \return DOM_NO_ERR            on success,
  821.  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
  822.  *                               the feature "XML" and the language exposed
  823.  *                               through the Document does not support
  824.  *                               Namespaces.
  825.  *
  826.  * The returned string will have its reference count increased. It is
  827.  * the responsibility of the caller to unref the string once it has
  828.  * finished with it.
  829.  */
  830. dom_exception _dom_element_get_attribute_ns(struct dom_element *element,
  831.                 dom_string *namespace, dom_string *localname,
  832.                 dom_string **value)
  833. {
  834.         return _dom_element_get_attr(element, namespace, localname, value);
  835. }
  836.  
  837. /**
  838.  * Set an attribute on an element by namespace/qualified name
  839.  *
  840.  * \param element    The element to set attribute on
  841.  * \param namespace  The attribute's namespace URI
  842.  * \param qname      The attribute's qualified name
  843.  * \param value      The attribute's value
  844.  * \return DOM_NO_ERR                      on success,
  845.  *         DOM_INVALID_CHARACTER_ERR       if ::qname is invalid,
  846.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  847.  *         DOM_NAMESPACE_ERR               if ::qname is malformed, or
  848.  *                                         ::qname has a prefix and
  849.  *                                         ::namespace is null, or ::qname
  850.  *                                         has a prefix "xml" and
  851.  *                                         ::namespace is not
  852.  *                                         "http://www.w3.org/XML/1998/namespace",
  853.  *                                         or ::qname has a prefix "xmlns"
  854.  *                                         and ::namespace is not
  855.  *                                         "http://www.w3.org/2000/xmlns",
  856.  *                                         or ::namespace is
  857.  *                                         "http://www.w3.org/2000/xmlns"
  858.  *                                         and ::qname is not prefixed
  859.  *                                         "xmlns",
  860.  *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
  861.  *                                         support the feature "XML" and the
  862.  *                                         language exposed through the
  863.  *                                         Document does not support
  864.  *                                         Namespaces.
  865.  */
  866. dom_exception _dom_element_set_attribute_ns(struct dom_element *element,
  867.                 dom_string *namespace, dom_string *qname,
  868.                 dom_string *value)
  869. {
  870.         dom_exception err;
  871.         dom_string *localname;
  872.         dom_string *prefix;
  873.  
  874.         if (_dom_validate_name(qname) == false)
  875.                 return DOM_INVALID_CHARACTER_ERR;
  876.  
  877.         err = _dom_namespace_validate_qname(qname, namespace);
  878.         if (err != DOM_NO_ERR)
  879.                 return DOM_NAMESPACE_ERR;
  880.  
  881.         err = _dom_namespace_split_qname(qname, &prefix, &localname);
  882.         if (err != DOM_NO_ERR)
  883.                 return err;
  884.  
  885.         /* If there is no namespace, must have a prefix */
  886.         if (namespace == NULL && prefix != NULL) {
  887.                 dom_string_unref(prefix);
  888.                 dom_string_unref(localname);
  889.                 return DOM_NAMESPACE_ERR;
  890.         }
  891.  
  892.         err = _dom_element_set_attr(element, namespace, localname, value);
  893.  
  894.         dom_string_unref(prefix);
  895.         dom_string_unref(localname);
  896.  
  897.         return err;
  898. }
  899.  
  900. /**
  901.  * Remove an attribute from an element by namespace/localname
  902.  *
  903.  * \param element    The element to remove attribute from
  904.  * \param namespace  The attribute's namespace URI
  905.  * \param localname  The attribute's local name
  906.  * \return DOM_NO_ERR                      on success,
  907.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  908.  *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
  909.  *                                         support the feature "XML" and the
  910.  *                                         language exposed through the
  911.  *                                         Document does not support
  912.  *                                         Namespaces.
  913.  */
  914. dom_exception _dom_element_remove_attribute_ns(struct dom_element *element,
  915.                 dom_string *namespace, dom_string *localname)
  916. {
  917.         return _dom_element_remove_attr(element, namespace, localname);
  918. }
  919.  
  920. /**
  921.  * Retrieve an attribute node from an element by namespace/localname
  922.  *
  923.  * \param element    The element to retrieve attribute from
  924.  * \param namespace  The attribute's namespace URI
  925.  * \param localname  The attribute's local name
  926.  * \param result     Pointer to location to receive attribute node
  927.  * \return DOM_NO_ERR            on success,
  928.  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
  929.  *                               the feature "XML" and the language exposed
  930.  *                               through the Document does not support
  931.  *                               Namespaces.
  932.  *
  933.  * The returned node will have its reference count increased. It is
  934.  * the responsibility of the caller to unref the node once it has
  935.  * finished with it.
  936.  */
  937. dom_exception _dom_element_get_attribute_node_ns(struct dom_element *element,
  938.                 dom_string *namespace, dom_string *localname,
  939.                 struct dom_attr **result)
  940. {
  941.         return _dom_element_get_attr_node(element, namespace, localname,
  942.                         result);
  943. }
  944.  
  945. /**
  946.  * Set an attribute node on an element, replacing existing node, if present
  947.  *
  948.  * \param element  The element to add a node to
  949.  * \param attr     The attribute node to add
  950.  * \param result   Pointer to location to recieve previous node
  951.  * \return DOM_NO_ERR                      on success,
  952.  *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
  953.  *                                         same document as ::element,
  954.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  955.  *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
  956.  *                                         of another Element node.
  957.  *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
  958.  *                                         support the feature "XML" and the
  959.  *                                         language exposed through the
  960.  *                                         Document does not support
  961.  *                                         Namespaces.
  962.  *
  963.  * The returned node will have its reference count increased. It is
  964.  * the responsibility of the caller to unref the node once it has
  965.  * finished with it.
  966.  */
  967. dom_exception _dom_element_set_attribute_node_ns(struct dom_element *element,
  968.                 struct dom_attr *attr, struct dom_attr **result)
  969. {
  970.         dom_exception err;
  971.         dom_string *namespace;
  972.  
  973.         err = dom_node_get_namespace(attr, (void *) &namespace);
  974.         if (err != DOM_NO_ERR)
  975.                 return err;
  976.  
  977.         err = _dom_element_set_attr_node(element, namespace, attr, result);
  978.  
  979.         if (namespace != NULL)
  980.                 dom_string_unref(namespace);
  981.  
  982.         return err;
  983. }
  984.  
  985. /**
  986.  * Retrieve a list of descendant elements of an element which match a given
  987.  * namespace/localname pair.
  988.  *
  989.  * \param element  The root of the subtree to search
  990.  * \param namespace  The namespace URI to match (or "*" for all)
  991.  * \param localname  The local name to match (or "*" for all)
  992.  * \param result   Pointer to location to receive result
  993.  * \return DOM_NO_ERR            on success,
  994.  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
  995.  *                               the feature "XML" and the language exposed
  996.  *                               through the Document does not support
  997.  *                               Namespaces.
  998.  *
  999.  * The returned nodelist will have its reference count increased. It is
  1000.  * the responsibility of the caller to unref the nodelist once it has
  1001.  * finished with it.
  1002.  */
  1003. dom_exception _dom_element_get_elements_by_tag_name_ns(
  1004.                 struct dom_element *element, dom_string *namespace,
  1005.                 dom_string *localname, struct dom_nodelist **result)
  1006. {
  1007.         dom_exception err;
  1008.  
  1009.         /** \todo ensure XML feature is supported */
  1010.  
  1011.         err = _dom_document_get_nodelist(element->base.owner,
  1012.                         DOM_NODELIST_BY_NAMESPACE,
  1013.                         (struct dom_node_internal *) element, NULL,
  1014.                         namespace, localname,
  1015.                         result);
  1016.  
  1017.         return err;
  1018. }
  1019.  
  1020. /**
  1021.  * Determine if an element possesses and attribute with the given name
  1022.  *
  1023.  * \param element  The element to query
  1024.  * \param name     The attribute name to look for
  1025.  * \param result   Pointer to location to receive result
  1026.  * \return DOM_NO_ERR.
  1027.  */
  1028. dom_exception _dom_element_has_attribute(struct dom_element *element,
  1029.                 dom_string *name, bool *result)
  1030. {
  1031.         return _dom_element_has_attr(element, NULL, name, result);
  1032. }
  1033.  
  1034. /**
  1035.  * Determine if an element possesses and attribute with the given
  1036.  * namespace/localname pair.
  1037.  *
  1038.  * \param element    The element to query
  1039.  * \param namespace  The attribute namespace URI to look for
  1040.  * \param localname  The attribute local name to look for
  1041.  * \param result   Pointer to location to receive result
  1042.  * \return DOM_NO_ERR            on success,
  1043.  *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
  1044.  *                               the feature "XML" and the language exposed
  1045.  *                               through the Document does not support
  1046.  *                               Namespaces.
  1047.  */
  1048. dom_exception _dom_element_has_attribute_ns(struct dom_element *element,
  1049.                 dom_string *namespace, dom_string *localname,
  1050.                 bool *result)
  1051. {
  1052.         return _dom_element_has_attr(element, namespace, localname, result);
  1053. }
  1054.  
  1055. /**
  1056.  * Retrieve the type information associated with an element
  1057.  *
  1058.  * \param element  The element to retrieve type information from
  1059.  * \param result   Pointer to location to receive type information
  1060.  * \return DOM_NO_ERR.
  1061.  *
  1062.  * The returned typeinfo will have its reference count increased. It is
  1063.  * the responsibility of the caller to unref the typeinfo once it has
  1064.  * finished with it.
  1065.  */
  1066. dom_exception _dom_element_get_schema_type_info(struct dom_element *element,
  1067.                 struct dom_type_info **result)
  1068. {
  1069.         UNUSED(element);
  1070.         UNUSED(result);
  1071.  
  1072.         return DOM_NOT_SUPPORTED_ERR;
  1073. }
  1074.  
  1075. /**
  1076.  * (Un)declare an attribute as being an element's ID by name
  1077.  *
  1078.  * \param element  The element containing the attribute
  1079.  * \param name     The attribute's name
  1080.  * \param is_id    Whether the attribute is an ID
  1081.  * \return DOM_NO_ERR                      on success,
  1082.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  1083.  *         DOM_NOT_FOUND_ERR               if the specified node is not an
  1084.  *                                         attribute of ::element.
  1085.  *
  1086.  * @note: The DOM spec does not say: how to deal with when there are two or
  1087.  * more isId attribute nodes. Here, the implementation just maintain only
  1088.  * one such attribute node.
  1089.  */
  1090. dom_exception _dom_element_set_id_attribute(struct dom_element *element,
  1091.                 dom_string *name, bool is_id)
  1092. {
  1093.         return _dom_element_set_id_attr(element, NULL, name, is_id);
  1094. }
  1095.  
  1096. /**
  1097.  * (Un)declare an attribute as being an element's ID by namespace/localname
  1098.  *
  1099.  * \param element    The element containing the attribute
  1100.  * \param namespace  The attribute's namespace URI
  1101.  * \param localname  The attribute's local name
  1102.  * \param is_id      Whether the attribute is an ID
  1103.  * \return DOM_NO_ERR                      on success,
  1104.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  1105.  *         DOM_NOT_FOUND_ERR               if the specified node is not an
  1106.  *                                         attribute of ::element.
  1107.  */
  1108. dom_exception _dom_element_set_id_attribute_ns(struct dom_element *element,
  1109.                 dom_string *namespace, dom_string *localname,
  1110.                 bool is_id)
  1111. {
  1112.         dom_exception err;
  1113.  
  1114.         err = _dom_element_set_id_attr(element, namespace, localname, is_id);
  1115.        
  1116.         element->id_ns = dom_string_ref(namespace);
  1117.  
  1118.         return err;
  1119. }
  1120.  
  1121. /**
  1122.  * (Un)declare an attribute node as being an element's ID
  1123.  *
  1124.  * \param element  The element containing the attribute
  1125.  * \param id_attr  The attribute node
  1126.  * \param is_id    Whether the attribute is an ID
  1127.  * \return DOM_NO_ERR                      on success,
  1128.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  1129.  *         DOM_NOT_FOUND_ERR               if the specified node is not an
  1130.  *                                         attribute of ::element.
  1131.  */
  1132. dom_exception _dom_element_set_id_attribute_node(struct dom_element *element,
  1133.                 struct dom_attr *id_attr, bool is_id)
  1134. {
  1135.         dom_exception err;
  1136.         dom_string *namespace;
  1137.         dom_string *localname;
  1138.  
  1139.         err = dom_node_get_namespace(id_attr, &namespace);
  1140.         if (err != DOM_NO_ERR)
  1141.                 return err;
  1142.         err = dom_node_get_local_name(id_attr, &localname);
  1143.         if (err != DOM_NO_ERR)
  1144.                 return err;
  1145.  
  1146.         err = _dom_element_set_id_attr(element, namespace, localname, is_id);
  1147.         if (err != DOM_NO_ERR)
  1148.                 return err;
  1149.        
  1150.         element->id_ns = namespace;
  1151.  
  1152.         return DOM_NO_ERR;
  1153.  
  1154. }
  1155.  
  1156. /**
  1157.  * Obtain a pre-parsed array of class names for an element
  1158.  *
  1159.  * \param element    Element containing classes
  1160.  * \param classes    Pointer to location to receive client-owned allocated array
  1161.  * \param n_classes  Pointer to location to receive number of classes
  1162.  * \return DOM_NO_ERR on success,
  1163.  *         DOM_NO_MEM_ERR on memory exhaustion
  1164.  */
  1165. dom_exception _dom_element_get_classes(struct dom_element *element,
  1166.                 lwc_string ***classes, uint32_t *n_classes)
  1167. {      
  1168.         if (element->n_classes > 0) {
  1169.                 lwc_string **classes_copy = NULL;
  1170.                 uint32_t classnr;
  1171.  
  1172.                 classes_copy = malloc(sizeof(lwc_string *) *
  1173.                                 element->n_classes);
  1174.                 if (classes_copy == NULL)
  1175.                         return DOM_NO_MEM_ERR;
  1176.  
  1177.                 for (classnr = 0; classnr < element->n_classes; classnr++)
  1178.                         classes_copy[classnr] = lwc_string_ref(
  1179.                                         element->classes[classnr]);
  1180.  
  1181.                 *classes = classes_copy;
  1182.                 *n_classes = element->n_classes;
  1183.         } else {
  1184.                 *n_classes = 0;
  1185.                 *classes = NULL;
  1186.         }
  1187.  
  1188.         return DOM_NO_ERR;
  1189. }
  1190.  
  1191. /**
  1192.  * Determine if an element has an associated class
  1193.  *
  1194.  * \param element  Element to consider
  1195.  * \param name     Class name to look for
  1196.  * \param match    Pointer to location to receive result
  1197.  * \return DOM_NO_ERR.
  1198.  */
  1199. dom_exception _dom_element_has_class(struct dom_element *element,
  1200.                 lwc_string *name, bool *match)
  1201. {
  1202.         dom_exception err;
  1203.         unsigned int class;
  1204.         struct dom_node_internal *node = (struct dom_node_internal *)element;
  1205.         dom_document_quirks_mode quirks_mode;
  1206.        
  1207.         /* Short-circuit case where we have no classes */
  1208.         if (element->n_classes == 0) {
  1209.                 *match = false;
  1210.                 return DOM_NO_ERR;
  1211.         }
  1212.  
  1213.         err = dom_document_get_quirks_mode(node->owner, &quirks_mode);
  1214.         if (err != DOM_NO_ERR)
  1215.                 return err;
  1216.  
  1217.         if (quirks_mode != DOM_DOCUMENT_QUIRKS_MODE_NONE) {
  1218.                 /* Quirks mode: case insensitively match */
  1219.                 for (class = 0; class < element->n_classes; class++) {
  1220.                         if (lwc_error_ok == lwc_string_caseless_isequal(name,
  1221.                                         element->classes[class], match) &&
  1222.                                         *match == true)
  1223.                                 return DOM_NO_ERR;
  1224.                 }
  1225.         } else {
  1226.                 /* Standards mode: case sensitively match */
  1227.                 for (class = 0; class < element->n_classes; class++) {
  1228.                         if (lwc_error_ok == lwc_string_isequal(name,
  1229.                                         element->classes[class], match) &&
  1230.                                         *match == true)
  1231.                                 return DOM_NO_ERR;
  1232.                 }
  1233.         }
  1234.  
  1235.         return DOM_NO_ERR;
  1236. }
  1237.  
  1238. /**
  1239.  * Get a named ancestor node
  1240.  *
  1241.  * \param element   Element to consider
  1242.  * \param name      Node name to look for
  1243.  * \param ancestor  Pointer to location to receive node pointer
  1244.  * \return DOM_NO_ERR.
  1245.  */
  1246. dom_exception dom_element_named_ancestor_node(dom_element *element,
  1247.                 lwc_string *name, dom_element **ancestor)
  1248. {
  1249.         dom_node_internal *node = (dom_node_internal *)element;
  1250.  
  1251.         *ancestor = NULL;
  1252.  
  1253.         for (node = node->parent; node != NULL; node = node->parent) {
  1254.                 if (node->type != DOM_ELEMENT_NODE)
  1255.                         continue;
  1256.  
  1257.                 assert(node->name != NULL);
  1258.  
  1259.                 if (dom_string_caseless_lwc_isequal(node->name, name)) {
  1260.                         *ancestor = (dom_element *)node;
  1261.                         break;
  1262.                 }
  1263.         }
  1264.  
  1265.         return DOM_NO_ERR;
  1266. }
  1267.  
  1268. /**
  1269.  * Get a named parent node
  1270.  *
  1271.  * \param element  Element to consider
  1272.  * \param name     Node name to look for
  1273.  * \param parent   Pointer to location to receive node pointer
  1274.  * \return DOM_NO_ERR.
  1275.  */
  1276. dom_exception dom_element_named_parent_node(dom_element *element,
  1277.                 lwc_string *name, dom_element **parent)
  1278. {
  1279.         dom_node_internal *node = (dom_node_internal *)element;
  1280.  
  1281.         *parent = NULL;
  1282.  
  1283.         for (node = node->parent; node != NULL; node = node->parent) {
  1284.                 if (node->type != DOM_ELEMENT_NODE)
  1285.                         continue;
  1286.  
  1287.                 assert(node->name != NULL);
  1288.  
  1289.                 if (dom_string_caseless_lwc_isequal(node->name, name)) {
  1290.                         *parent = (dom_element *)node;
  1291.                 }
  1292.                 break;
  1293.         }
  1294.  
  1295.         return DOM_NO_ERR;
  1296. }
  1297.  
  1298. /**
  1299.  * Get a named parent node
  1300.  *
  1301.  * \param element  Element to consider
  1302.  * \param name     Node name to look for
  1303.  * \param parent   Pointer to location to receive node pointer
  1304.  * \return DOM_NO_ERR.
  1305.  */
  1306. dom_exception dom_element_parent_node(dom_element *element,
  1307.                 dom_element **parent)
  1308. {
  1309.         dom_node_internal *node = (dom_node_internal *)element;
  1310.  
  1311.         *parent = NULL;
  1312.  
  1313.         for (node = node->parent; node != NULL; node = node->parent) {
  1314.                 if (node->type != DOM_ELEMENT_NODE)
  1315.                         continue;
  1316.  
  1317.                 *parent = (dom_element *)node;
  1318.                 break;
  1319.         }
  1320.  
  1321.         return DOM_NO_ERR;
  1322. }
  1323.  
  1324. /*------------- The overload virtual functions ------------------------*/
  1325.  
  1326. /* Overload function of Node, please refer src/core/node.c for detail */
  1327. dom_exception _dom_element_get_attributes(dom_node_internal *node,
  1328.                 struct dom_namednodemap **result)
  1329. {
  1330.         dom_exception err;
  1331.         dom_document *doc;
  1332.  
  1333.         doc = dom_node_get_owner(node);
  1334.         assert(doc != NULL);
  1335.  
  1336.         err = _dom_namednodemap_create(doc, node, &attributes_opt, result);
  1337.         if (err != DOM_NO_ERR)
  1338.                 return err;
  1339.        
  1340.         dom_node_ref(node);
  1341.        
  1342.         return DOM_NO_ERR;
  1343. }
  1344.  
  1345. /* Overload function of Node, please refer src/core/node.c for detail */
  1346. dom_exception _dom_element_has_attributes(dom_node_internal *node, bool *result)
  1347. {
  1348.         UNUSED(node);
  1349.         *result = true;
  1350.  
  1351.         return DOM_NO_ERR;
  1352. }
  1353.  
  1354. /* For the following namespace related algorithm take a look at:
  1355.  * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html
  1356.  */
  1357.  
  1358. /**
  1359.  * Look up the prefix which matches the namespace.
  1360.  *
  1361.  * \param node       The current Node in which we search for
  1362.  * \param namespace  The namespace for which we search a prefix
  1363.  * \param result     The returned prefix
  1364.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1365.  */
  1366. dom_exception _dom_element_lookup_prefix(dom_node_internal *node,
  1367.                 dom_string *namespace, dom_string **result)
  1368. {
  1369.         struct dom_element *owner;
  1370.         dom_exception err;
  1371.  
  1372.         err = dom_attr_get_owner_element(node, &owner);
  1373.         if (err != DOM_NO_ERR)
  1374.                 return err;
  1375.        
  1376.         if (owner == NULL) {
  1377.                 *result = NULL;
  1378.                 return DOM_NO_ERR;
  1379.         }
  1380.  
  1381.         return dom_node_lookup_prefix(owner, namespace, result);
  1382. }
  1383.  
  1384. /**
  1385.  * Test whether certain namespace is the default namespace of some node.
  1386.  *
  1387.  * \param node       The Node to test
  1388.  * \param namespace  The namespace to test
  1389.  * \param result     true is the namespace is default namespace
  1390.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1391.  */
  1392. dom_exception _dom_element_is_default_namespace(dom_node_internal *node,
  1393.                 dom_string *namespace, bool *result)
  1394. {
  1395.         struct dom_element *ele = (struct dom_element *) node;
  1396.         dom_string *value;
  1397.         dom_exception err;
  1398.         bool has;
  1399.         dom_string *xmlns;
  1400.  
  1401.         if (node->prefix == NULL) {
  1402.                 *result = dom_string_isequal(node->namespace, namespace);
  1403.                 return DOM_NO_ERR;
  1404.         }
  1405.  
  1406.         xmlns = _dom_namespace_get_xmlns_prefix();
  1407.         err = dom_element_has_attribute(ele, xmlns, &has);
  1408.         if (err != DOM_NO_ERR)
  1409.                 return err;
  1410.        
  1411.         if (has == true) {
  1412.                 err = dom_element_get_attribute(ele, xmlns, &value);
  1413.                 if (err != DOM_NO_ERR)
  1414.                         return err;
  1415.  
  1416.                 *result = dom_string_isequal(value, namespace);
  1417.  
  1418.                 dom_string_unref(value);
  1419.  
  1420.                 return DOM_NO_ERR;
  1421.         }
  1422.  
  1423.         return dom_node_is_default_namespace(node->parent, namespace, result);
  1424. }
  1425.  
  1426. /**
  1427.  * Look up the namespace with certain prefix.
  1428.  *
  1429.  * \param node    The current node in which we search for the prefix
  1430.  * \param prefix  The prefix to search
  1431.  * \param result  The result namespace if found
  1432.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1433.  */
  1434. dom_exception _dom_element_lookup_namespace(dom_node_internal *node,
  1435.                 dom_string *prefix, dom_string **result)
  1436. {
  1437.         dom_exception err;
  1438.         bool has;
  1439.         dom_string *xmlns;
  1440.  
  1441.         if (node->namespace != NULL &&
  1442.                         dom_string_isequal(node->prefix, prefix)) {
  1443.                 *result = dom_string_ref(node->namespace);
  1444.                 return DOM_NO_ERR;
  1445.         }
  1446.        
  1447.         xmlns = _dom_namespace_get_xmlns_prefix();
  1448.         err = dom_element_has_attribute_ns(node, xmlns, prefix, &has);
  1449.         if (err != DOM_NO_ERR)
  1450.                 return err;
  1451.        
  1452.         if (has == true)
  1453.                 return dom_element_get_attribute_ns(node,
  1454.                                 dom_namespaces[DOM_NAMESPACE_XMLNS], prefix,
  1455.                                 result);
  1456.  
  1457.         err = dom_element_has_attribute(node, xmlns, &has);
  1458.         if (err != DOM_NO_ERR)
  1459.                 return err;
  1460.        
  1461.         if (has == true) {
  1462.                 return dom_element_get_attribute(node, xmlns, result);
  1463.         }
  1464.  
  1465.         return dom_node_lookup_namespace(node->parent, prefix, result);
  1466. }
  1467.  
  1468.  
  1469. /*----------------------------------------------------------------------*/
  1470. /* The protected virtual functions */
  1471.  
  1472. /**
  1473.  * The virtual function to parse some dom attribute
  1474.  *
  1475.  * \param ele     The element object
  1476.  * \param name    The name of the attribute
  1477.  * \param value   The new value of the attribute
  1478.  * \param parsed  The parsed value of the attribute
  1479.  * \return DOM_NO_ERR on success.
  1480.  *
  1481.  * @note: This virtual method is provided to serve as a template method.
  1482.  * When any attribute is set or added, the attribute's value should be
  1483.  * checked to make sure that it is a valid one. And the child class of
  1484.  * dom_element may to do some special stuff on the attribute is set. Take
  1485.  * some integer attribute as example:
  1486.  *
  1487.  * 1. The client call dom_element_set_attribute("size", "10.1"), but the
  1488.  *    size attribute may only accept an integer, and only the specific
  1489.  *    dom_element know this. And the dom_attr_set_value method, which is
  1490.  *    called by dom_element_set_attribute should call the this virtual
  1491.  *    template method.
  1492.  * 2. The overload virtual function of following one will truncate the
  1493.  *    "10.1" to "10" to make sure it is a integer. And of course, the
  1494.  *    overload method may also save the integer as a 'int' C type for
  1495.  *    later easy accessing by any client.
  1496.  */
  1497. dom_exception _dom_element_parse_attribute(dom_element *ele,
  1498.                 dom_string *name, dom_string *value,
  1499.                 dom_string **parsed)
  1500. {
  1501.         UNUSED(ele);
  1502.         UNUSED(name);
  1503.  
  1504.         dom_string_ref(value);
  1505.         *parsed = value;
  1506.  
  1507.         return DOM_NO_ERR;
  1508. }
  1509.  
  1510. /* The destroy virtual function of dom_element */
  1511. void __dom_element_destroy(struct dom_node_internal *node)
  1512. {
  1513.         _dom_element_destroy((struct dom_element *) node);
  1514. }
  1515.  
  1516. /* TODO: How to deal with default attribue:
  1517.  *
  1518.  *  Ask a language binding for default attributes.     
  1519.  *
  1520.  *      So, when we copy a element we copy all its attributes because they
  1521.  *      are all specified. For the methods like importNode and adoptNode,
  1522.  *      this will make _dom_element_copy can be used in them.
  1523.  */
  1524. dom_exception _dom_element_copy(dom_node_internal *old,
  1525.                 dom_node_internal **copy)
  1526. {
  1527.         dom_element *olde = (dom_element *) old;
  1528.         dom_element *e;
  1529.         dom_exception err;
  1530.         uint32_t classnr;
  1531.        
  1532.         e = malloc(sizeof(dom_element));
  1533.         if (e == NULL)
  1534.                 return DOM_NO_MEM_ERR;
  1535.  
  1536.         err = dom_node_copy_internal(old, e);
  1537.         if (err != DOM_NO_ERR) {
  1538.                 free(e);
  1539.                 return err;
  1540.         }
  1541.  
  1542.         if (olde->attributes != NULL) {
  1543.                 /* Copy the attribute list */
  1544.                 e->attributes = _dom_element_attr_list_clone(olde->attributes,
  1545.                                 e);
  1546.         } else {
  1547.                 e->attributes = NULL;
  1548.         }
  1549.        
  1550.         if (olde->n_classes > 0) {
  1551.                 e->n_classes = olde->n_classes;
  1552.                 e->classes = malloc(sizeof(lwc_string *) * e->n_classes);
  1553.                 for (classnr = 0; classnr < e->n_classes; ++classnr)
  1554.                         e->classes[classnr] =
  1555.                                 lwc_string_ref(olde->classes[classnr]);
  1556.         } else {
  1557.                 e->n_classes = 0;
  1558.                 e->classes = NULL;
  1559.         }
  1560.        
  1561.         e->id_ns = NULL;
  1562.         e->id_name = NULL;
  1563.  
  1564.         /* TODO: deal with dom_type_info, it get no definition ! */
  1565.  
  1566.         *copy = (dom_node_internal *) e;
  1567.  
  1568.         return DOM_NO_ERR;
  1569. }
  1570.  
  1571.  
  1572.  
  1573. /*--------------------------------------------------------------------------*/
  1574.  
  1575. /* Helper functions */
  1576.  
  1577. /**
  1578.  * The internal helper function for getAttribute/getAttributeNS.
  1579.  *
  1580.  * \param element    The element
  1581.  * \param namespace  The namespace to look for attribute in.  May be NULL.
  1582.  * \param name       The name of the attribute
  1583.  * \param value      The value of the attribute
  1584.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1585.  */
  1586. dom_exception _dom_element_get_attr(struct dom_element *element,
  1587.                 dom_string *namespace, dom_string *name, dom_string **value)
  1588. {
  1589.         dom_attr_list *match;
  1590.         dom_exception err = DOM_NO_ERR;
  1591.  
  1592.         match = _dom_element_attr_list_find_by_name(element->attributes,
  1593.                         name, namespace);
  1594.  
  1595.         /* Fill in value */
  1596.         if (match == NULL) {
  1597.                 *value = NULL;
  1598.         } else {
  1599.                 err = dom_attr_get_value(match->attr, value);
  1600.         }
  1601.  
  1602.         return err;
  1603. }
  1604.  
  1605. /**
  1606.  * The internal helper function for setAttribute and setAttributeNS.
  1607.  *
  1608.  * \param element    The element
  1609.  * \param namespace  The namespace to set attribute for.  May be NULL.
  1610.  * \param name       The name of the new attribute
  1611.  * \param value      The value of the new attribute
  1612.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  1613.  */
  1614. dom_exception _dom_element_set_attr(struct dom_element *element,
  1615.                 dom_string *namespace, dom_string *name, dom_string *value)
  1616. {
  1617.         dom_attr_list *match;
  1618.         dom_node_internal *e = (dom_node_internal *) element;
  1619.         dom_exception err;
  1620.  
  1621.         if (_dom_validate_name(name) == false)
  1622.                 return DOM_INVALID_CHARACTER_ERR;
  1623.  
  1624.         /* Ensure element can be written */
  1625.         if (_dom_node_readonly(e))
  1626.                 return DOM_NO_MODIFICATION_ALLOWED_ERR;
  1627.  
  1628.         match = _dom_element_attr_list_find_by_name(element->attributes,
  1629.                         name, namespace);
  1630.  
  1631.         if (match != NULL) {
  1632.                 /* Found an existing attribute, so replace its value */
  1633.  
  1634.                 /* Dispatch a DOMAttrModified event */
  1635.                 dom_string *old = NULL;
  1636.                 struct dom_document *doc = dom_node_get_owner(element);
  1637.                 bool success = true;
  1638.                 err = dom_attr_get_value(match->attr, &old);
  1639.                 /* TODO: We did not support some node type such as entity
  1640.                  * reference, in that case, we should ignore the error to
  1641.                  * make sure the event model work as excepted. */
  1642.                 if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR)
  1643.                         return err;
  1644.                 err = _dom_dispatch_attr_modified_event(doc, e, old, value,
  1645.                                 match->attr, name, DOM_MUTATION_MODIFICATION,
  1646.                                 &success);
  1647.                 dom_string_unref(old);
  1648.                 if (err != DOM_NO_ERR)
  1649.                         return err;
  1650.  
  1651.                 success = true;
  1652.                 err = _dom_dispatch_subtree_modified_event(doc,
  1653.                                 (dom_event_target *) e, &success);
  1654.                 if (err != DOM_NO_ERR)
  1655.                         return err;
  1656.  
  1657.                 err = dom_attr_set_value(match->attr, value);
  1658.                 if (err != DOM_NO_ERR)
  1659.                         return err;
  1660.         } else {
  1661.                 /* No existing attribute, so create one */
  1662.                 struct dom_attr *attr;
  1663.                 struct dom_attr_list *list_node;
  1664.                 struct dom_document *doc;
  1665.                 bool success = true;
  1666.  
  1667.                 err = _dom_attr_create(e->owner, name, namespace, NULL,
  1668.                                 true, &attr);
  1669.                 if (err != DOM_NO_ERR)
  1670.                         return err;
  1671.  
  1672.                 /* Set its parent, so that value parsing works */
  1673.                 dom_node_set_parent(attr, element);
  1674.  
  1675.                 /* Set its value */
  1676.                 err = dom_attr_set_value(attr, value);
  1677.                 if (err != DOM_NO_ERR) {
  1678.                         dom_node_set_parent(attr, NULL);
  1679.                         dom_node_unref(attr);
  1680.                         return err;
  1681.                 }
  1682.  
  1683.                 /* Dispatch a DOMAttrModified event */
  1684.                 doc = dom_node_get_owner(element);
  1685.                 err = _dom_dispatch_attr_modified_event(doc, e, NULL, value,
  1686.                                 (dom_event_target *) attr, name,
  1687.                                 DOM_MUTATION_ADDITION, &success);
  1688.                 if (err != DOM_NO_ERR) {
  1689.                         dom_node_set_parent(attr, NULL);
  1690.                         dom_node_unref(attr);
  1691.                         return err;
  1692.                 }
  1693.  
  1694.                 err = dom_node_dispatch_node_change_event(doc,
  1695.                                 attr, element, DOM_MUTATION_ADDITION, &success);
  1696.                 if (err != DOM_NO_ERR) {
  1697.                         dom_node_set_parent(attr, NULL);
  1698.                         dom_node_unref(attr);
  1699.                         return err;
  1700.                 }
  1701.  
  1702.                 /* Create attribute list node */
  1703.                 list_node = _dom_element_attr_list_node_create(attr, element,
  1704.                                 name, namespace);
  1705.                 if (list_node == NULL) {
  1706.                         /* If we failed at this step, there must be no memory */
  1707.                         dom_node_set_parent(attr, NULL);
  1708.                         dom_node_unref(attr);
  1709.                         return DOM_NO_MEM_ERR;
  1710.                 }
  1711.                 dom_string_ref(name);
  1712.                 dom_string_ref(namespace);
  1713.  
  1714.                 /* Link into element's attribute list */
  1715.                 if (element->attributes == NULL)
  1716.                         element->attributes = list_node;
  1717.                 else
  1718.                         _dom_element_attr_list_insert(element->attributes,
  1719.                                         list_node);
  1720.  
  1721.                 dom_node_unref(attr);
  1722.                 dom_node_remove_pending(attr);
  1723.  
  1724.                 success = true;
  1725.                 err = _dom_dispatch_subtree_modified_event(doc,
  1726.                                 (dom_event_target *) element, &success);
  1727.                 if (err != DOM_NO_ERR)
  1728.                         return err;
  1729.         }
  1730.  
  1731.         return DOM_NO_ERR;
  1732. }
  1733.  
  1734. /**
  1735.  * Remove an attribute from an element by name
  1736.  *
  1737.  * \param element  The element to remove attribute from
  1738.  * \param name     The name of the attribute to remove
  1739.  * \return DOM_NO_ERR                      on success,
  1740.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
  1741.  */
  1742. dom_exception _dom_element_remove_attr(struct dom_element *element,
  1743.                 dom_string *namespace, dom_string *name)
  1744. {
  1745.         dom_attr_list *match;
  1746.         dom_exception err;
  1747.         dom_node_internal *e = (dom_node_internal *) element;
  1748.  
  1749.         /* Ensure element can be written to */
  1750.         if (_dom_node_readonly(e))
  1751.                 return DOM_NO_MODIFICATION_ALLOWED_ERR;
  1752.  
  1753.         match = _dom_element_attr_list_find_by_name(element->attributes,
  1754.                         name, namespace);
  1755.  
  1756.         /* Detach attr node from list */
  1757.         if (match != NULL) {
  1758.                 /* Disptach DOMNodeRemoval event */
  1759.                 bool success = true;
  1760.                 dom_attr *a = match->attr;
  1761.                 struct dom_document *doc = dom_node_get_owner(element);
  1762.                 dom_string *old = NULL;
  1763.  
  1764.                 err = dom_node_dispatch_node_change_event(doc, match->attr,
  1765.                                 element, DOM_MUTATION_REMOVAL, &success);
  1766.                 if (err != DOM_NO_ERR)
  1767.                         return err;
  1768.  
  1769.                 /* Claim a reference for later event dispatch */
  1770.                 dom_node_ref(a);
  1771.  
  1772.  
  1773.                 /* Delete the attribute node */
  1774.                 if (element->attributes == match) {
  1775.                         element->attributes =
  1776.                                         _dom_element_attr_list_next(match);
  1777.                 }
  1778.                 if (element->attributes == match) {
  1779.                         /* match must be sole attribute */
  1780.                         element->attributes = NULL;
  1781.                 }
  1782.                 _dom_element_attr_list_node_unlink(match);
  1783.                 _dom_element_attr_list_node_destroy(match);
  1784.  
  1785.                 /* Dispatch a DOMAttrModified event */
  1786.                 success = true;
  1787.                 err = dom_attr_get_value(a, &old);
  1788.                 /* TODO: We did not support some node type such as entity
  1789.                  * reference, in that case, we should ignore the error to
  1790.                  * make sure the event model work as excepted. */
  1791.                 if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR)
  1792.                         return err;
  1793.                 err = _dom_dispatch_attr_modified_event(doc, e, old, NULL, a,
  1794.                                 name, DOM_MUTATION_REMOVAL, &success);
  1795.                 dom_string_unref(old);
  1796.                 /* Release the reference */
  1797.                 dom_node_unref(a);
  1798.                 if (err != DOM_NO_ERR)
  1799.                         return err;
  1800.  
  1801.                 success = true;
  1802.                 err = _dom_dispatch_subtree_modified_event(doc,
  1803.                                 (dom_event_target *) e, &success);
  1804.                 if (err != DOM_NO_ERR)
  1805.                         return err;
  1806.         }
  1807.  
  1808.         /** \todo defaulted attribute handling */
  1809.  
  1810.         return DOM_NO_ERR;
  1811. }
  1812.  
  1813. /**
  1814.  * Retrieve an attribute node from an element by name
  1815.  *
  1816.  * \param element  The element to retrieve attribute node from
  1817.  * \param name     The attribute's name
  1818.  * \param result   Pointer to location to receive attribute node
  1819.  * \return DOM_NO_ERR.
  1820.  *
  1821.  * The returned node will have its reference count increased. It is
  1822.  * the responsibility of the caller to unref the node once it has
  1823.  * finished with it.
  1824.  */
  1825. dom_exception _dom_element_get_attr_node(struct dom_element *element,
  1826.                 dom_string *namespace, dom_string *name,
  1827.                 struct dom_attr **result)
  1828. {
  1829.         dom_attr_list *match;
  1830.  
  1831.         match = _dom_element_attr_list_find_by_name(element->attributes,
  1832.                         name, namespace);
  1833.  
  1834.         /* Fill in value */
  1835.         if (match == NULL) {
  1836.                 *result = NULL;
  1837.         } else {
  1838.                 *result = match->attr;
  1839.                 dom_node_ref(*result);
  1840.         }
  1841.  
  1842.         return DOM_NO_ERR;
  1843. }
  1844.  
  1845. /**
  1846.  * Set an attribute node on an element, replacing existing node, if present
  1847.  *
  1848.  * \param element  The element to add a node to
  1849.  * \param attr     The attribute node to add
  1850.  * \param result   Pointer to location to receive previous node
  1851.  * \return DOM_NO_ERR                      on success,
  1852.  *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
  1853.  *                                         same document as ::element,
  1854.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  1855.  *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
  1856.  *                                         of another Element node.
  1857.  *
  1858.  * The returned node will have its reference count increased. It is
  1859.  * the responsibility of the caller to unref the node once it has
  1860.  * finished with it.
  1861.  */
  1862. dom_exception _dom_element_set_attr_node(struct dom_element *element,
  1863.                 dom_string *namespace, struct dom_attr *attr,
  1864.                 struct dom_attr **result)
  1865. {
  1866.         dom_attr_list *match;
  1867.         dom_exception err;
  1868.         dom_string *name = NULL;
  1869.         dom_node_internal *e = (dom_node_internal *) element;
  1870.         dom_node_internal *attr_node = (dom_node_internal *) attr;
  1871.         dom_attr *old_attr;
  1872.         dom_string *new = NULL;
  1873.         struct dom_document *doc;
  1874.         bool success = true;
  1875.  
  1876.         /** \todo validate name */
  1877.  
  1878.         /* Ensure element and attribute belong to the same document */
  1879.         if (e->owner != attr_node->owner)
  1880.                 return DOM_WRONG_DOCUMENT_ERR;
  1881.  
  1882.         /* Ensure element can be written to */
  1883.         if (_dom_node_readonly(e))
  1884.                 return DOM_NO_MODIFICATION_ALLOWED_ERR;
  1885.  
  1886.         /* Ensure attribute isn't attached to another element */
  1887.         if (attr_node->parent != NULL && attr_node->parent != e)
  1888.                 return DOM_INUSE_ATTRIBUTE_ERR;
  1889.  
  1890.         err = dom_node_get_local_name(attr, &name);
  1891.         if (err != DOM_NO_ERR)
  1892.                 return err;
  1893.  
  1894.         match = _dom_element_attr_list_find_by_name(element->attributes,
  1895.                         name, namespace);
  1896.  
  1897.         *result = NULL;
  1898.         if (match != NULL) {
  1899.                 /* Disptach DOMNodeRemoval event */
  1900.                 dom_string *old = NULL;
  1901.                 doc = dom_node_get_owner(element);
  1902.                 old_attr = match->attr;
  1903.  
  1904.                 err = dom_node_dispatch_node_change_event(doc, old_attr,
  1905.                                 element, DOM_MUTATION_REMOVAL, &success);
  1906.                 if (err != DOM_NO_ERR) {
  1907.                         dom_string_unref(name);
  1908.                         return err;
  1909.                 }
  1910.  
  1911.                 dom_node_ref(old_attr);
  1912.  
  1913.                 _dom_element_attr_list_node_unlink(match);
  1914.                 _dom_element_attr_list_node_destroy(match);
  1915.  
  1916.                 /* Dispatch a DOMAttrModified event */
  1917.                 success = true;
  1918.                 err = dom_attr_get_value(old_attr, &old);
  1919.                 /* TODO: We did not support some node type such as entity
  1920.                  * reference, in that case, we should ignore the error to
  1921.                  * make sure the event model work as excepted. */
  1922.                 if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) {
  1923.                         dom_node_unref(old_attr);
  1924.                         dom_string_unref(name);
  1925.                         return err;
  1926.                 }
  1927.                 err = _dom_dispatch_attr_modified_event(doc, e, old, NULL,
  1928.                                 (dom_event_target *) old_attr, name,
  1929.                                 DOM_MUTATION_REMOVAL, &success);
  1930.                 dom_string_unref(old);
  1931.                 *result = old_attr;
  1932.                 if (err != DOM_NO_ERR) {
  1933.                         dom_string_unref(name);
  1934.                         return err;
  1935.                 }
  1936.  
  1937.                 success = true;
  1938.                 err = _dom_dispatch_subtree_modified_event(doc,
  1939.                                 (dom_event_target *) e, &success);
  1940.                 if (err != DOM_NO_ERR) {
  1941.                         dom_string_unref(name);
  1942.                         return err;
  1943.                 }
  1944.         }
  1945.  
  1946.  
  1947.         match = _dom_element_attr_list_node_create(attr, element,
  1948.                         name, namespace);
  1949.         if (match == NULL) {
  1950.                 dom_string_unref(name);
  1951.                 /* If we failed at this step, there must be no memory */
  1952.                 return DOM_NO_MEM_ERR;
  1953.         }
  1954.  
  1955.         dom_string_ref(name);
  1956.         dom_string_ref(namespace);
  1957.         dom_node_set_parent(attr, element);
  1958.         dom_node_remove_pending(attr);
  1959.  
  1960.         /* Dispatch a DOMAttrModified event */
  1961.         doc = dom_node_get_owner(element);
  1962.         success = true;
  1963.         err = dom_attr_get_value(attr, &new);
  1964.         /* TODO: We did not support some node type such as entity reference, in
  1965.          * that case, we should ignore the error to make sure the event model
  1966.          * work as excepted. */
  1967.         if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR)
  1968.                 return err;
  1969.         err = _dom_dispatch_attr_modified_event(doc, e, NULL, new,
  1970.                         (dom_event_target *) attr, name,
  1971.                         DOM_MUTATION_ADDITION, &success);
  1972.         /* Cleanup */
  1973.         dom_string_unref(new);
  1974.         dom_string_unref(name);
  1975.         if (err != DOM_NO_ERR) {
  1976.                 return err;
  1977.         }
  1978.  
  1979.         err = dom_node_dispatch_node_change_event(doc, attr, element,
  1980.                         DOM_MUTATION_ADDITION, &success);
  1981.         if (err != DOM_NO_ERR)
  1982.                 return err;
  1983.  
  1984.         success = true;
  1985.         err = _dom_dispatch_subtree_modified_event(doc,
  1986.                         (dom_event_target *) element, &success);
  1987.         if (err != DOM_NO_ERR)
  1988.                 return err;
  1989.  
  1990.         /* Link into element's attribute list */
  1991.         if (element->attributes == NULL)
  1992.                 element->attributes = match;
  1993.         else
  1994.                 _dom_element_attr_list_insert(element->attributes, match);
  1995.  
  1996.         return DOM_NO_ERR;
  1997. }
  1998.  
  1999. /**
  2000.  * Remove an attribute node from an element
  2001.  *
  2002.  * \param element  The element to remove attribute node from
  2003.  * \param attr     The attribute node to remove
  2004.  * \param result   Pointer to location to receive attribute node
  2005.  * \return DOM_NO_ERR                      on success,
  2006.  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  2007.  *         DOM_NOT_FOUND_ERR               if ::attr is not an attribute of
  2008.  *                                         ::element.
  2009.  *
  2010.  * The returned node will have its reference count increased. It is
  2011.  * the responsibility of the caller to unref the node once it has
  2012.  * finished with it.
  2013.  */
  2014. dom_exception _dom_element_remove_attr_node(struct dom_element *element,
  2015.                 dom_string *namespace, struct dom_attr *attr,
  2016.                 struct dom_attr **result)
  2017. {
  2018.         dom_attr_list *match;
  2019.         dom_exception err;
  2020.         dom_string *name;
  2021.         dom_node_internal *e = (dom_node_internal *) element;
  2022.         dom_attr *a;
  2023.         bool success = true;
  2024.         struct dom_document *doc;
  2025.         dom_string *old = NULL;
  2026.        
  2027.         /* Ensure element can be written to */
  2028.         if (_dom_node_readonly(e))
  2029.                 return DOM_NO_MODIFICATION_ALLOWED_ERR;
  2030.        
  2031.         err = dom_node_get_node_name(attr, &name);
  2032.         if (err != DOM_NO_ERR)
  2033.                 return err;
  2034.  
  2035.         match = _dom_element_attr_list_find_by_name(element->attributes,
  2036.                         name, namespace);
  2037.  
  2038.         /** \todo defaulted attribute handling */
  2039.  
  2040.         if (match == NULL || match->attr != attr) {
  2041.                 dom_string_unref(name);
  2042.                 return DOM_NOT_FOUND_ERR;
  2043.         }
  2044.  
  2045.         a = match->attr;
  2046.  
  2047.         /* Dispatch a DOMNodeRemoved event */
  2048.         doc = dom_node_get_owner(element);
  2049.         err = dom_node_dispatch_node_change_event(doc, a, element,
  2050.                         DOM_MUTATION_REMOVAL, &success);
  2051.         if (err != DOM_NO_ERR) {
  2052.                 dom_string_unref(name);
  2053.                 return err;
  2054.         }
  2055.  
  2056.         dom_node_ref(a);
  2057.  
  2058.         /* Delete the attribute node */
  2059.         if (element->attributes == match) {
  2060.                 element->attributes = _dom_element_attr_list_next(match);
  2061.         }
  2062.         if (element->attributes == match) {
  2063.                 /* match must be sole attribute */
  2064.                 element->attributes = NULL;
  2065.         }
  2066.         _dom_element_attr_list_node_unlink(match);
  2067.         _dom_element_attr_list_node_destroy(match);
  2068.  
  2069.         /* Now, cleaup the dom_string */
  2070.         dom_string_unref(name);
  2071.  
  2072.         /* Dispatch a DOMAttrModified event */
  2073.         success = true;
  2074.         err = dom_attr_get_value(a, &old);
  2075.         /* TODO: We did not support some node type such as entity reference, in
  2076.          * that case, we should ignore the error to make sure the event model
  2077.          * work as excepted. */
  2078.         if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) {
  2079.                 dom_node_unref(a);
  2080.                 return err;
  2081.         }
  2082.         err = _dom_dispatch_attr_modified_event(doc, e, old, NULL,
  2083.                         (dom_event_target *) a, name,
  2084.                         DOM_MUTATION_REMOVAL, &success);
  2085.         dom_string_unref(old);
  2086.         if (err != DOM_NO_ERR)
  2087.                 return err;
  2088.  
  2089.         /* When a Node is removed, it should be destroy. When its refcnt is not
  2090.          * zero, it will be added to the document's deletion pending list.
  2091.          * When a Node is removed, its parent should be NULL, but its owner
  2092.          * should remain to be the document.
  2093.          */
  2094.         *result = (dom_attr *) a;
  2095.  
  2096.         success = true;
  2097.         err = _dom_dispatch_subtree_modified_event(doc,
  2098.                         (dom_event_target *) e, &success);
  2099.         if (err != DOM_NO_ERR)
  2100.                 return err;
  2101.  
  2102.         return DOM_NO_ERR;
  2103. }
  2104.  
  2105. /**
  2106.  * Test whether certain attribute exists on the element
  2107.  *
  2108.  * \param element    The element
  2109.  * \param namespace  The namespace to look for attribute in.  May be NULL.
  2110.  * \param name       The attribute's name
  2111.  * \param result     The return value
  2112.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  2113.  */
  2114. dom_exception _dom_element_has_attr(struct dom_element *element,
  2115.                 dom_string *namespace, dom_string *name, bool *result)
  2116. {
  2117.         dom_attr_list *match;
  2118.  
  2119.         match = _dom_element_attr_list_find_by_name(element->attributes,
  2120.                         name, namespace);
  2121.  
  2122.         /* Fill in result */
  2123.         if (match == NULL) {
  2124.                 *result = false;
  2125.         } else {
  2126.                 *result = true;
  2127.         }
  2128.  
  2129.         return DOM_NO_ERR;
  2130. }
  2131.  
  2132. /**
  2133.  * (Un)set an attribute Node as a ID.
  2134.  *
  2135.  * \param element    The element contains the attribute
  2136.  * \param namespace  The namespace of the attribute node
  2137.  * \param name       The name of the attribute
  2138.  * \param is_id      true for set the node as a ID attribute, false unset it
  2139.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  2140.  */
  2141. dom_exception _dom_element_set_id_attr(struct dom_element *element,
  2142.                 dom_string *namespace, dom_string *name, bool is_id)
  2143. {
  2144.        
  2145.         dom_attr_list *match;
  2146.  
  2147.         match = _dom_element_attr_list_find_by_name(element->attributes,
  2148.                         name, namespace);
  2149.         if (match == NULL)
  2150.                 return DOM_NOT_FOUND_ERR;
  2151.        
  2152.         if (is_id == true) {
  2153.                 /* Clear the previous id attribute if there is one */
  2154.                 dom_attr_list *old = _dom_element_attr_list_find_by_name(
  2155.                                 element->attributes, element->id_name,
  2156.                                 element->id_ns);
  2157.  
  2158.                 if (old != NULL) {
  2159.                         _dom_attr_set_isid(old->attr, false);
  2160.                 }
  2161.  
  2162.                 /* Set up the new id attr stuff */
  2163.                 element->id_name = dom_string_ref(name);
  2164.                 element->id_ns = dom_string_ref(namespace);
  2165.         }
  2166.  
  2167.         _dom_attr_set_isid(match->attr, is_id);
  2168.  
  2169.         return DOM_NO_ERR;
  2170. }
  2171.  
  2172. /**
  2173.  * Get the ID string of the element
  2174.  *
  2175.  * \param ele  The element
  2176.  * \param id   The ID of this element
  2177.  * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
  2178.  */
  2179. dom_exception _dom_element_get_id(struct dom_element *ele, dom_string **id)
  2180. {
  2181.         dom_exception err;
  2182.         dom_string *ret = NULL;
  2183.         dom_document *doc;
  2184.         dom_string *name;
  2185.  
  2186.         *id = NULL;
  2187.  
  2188.         if (ele->id_ns != NULL && ele->id_name != NULL) {
  2189.                 /* There is user specific ID attribute */
  2190.                 err = _dom_element_get_attribute_ns(ele, ele->id_ns,
  2191.                                 ele->id_name, &ret);
  2192.                 if (err != DOM_NO_ERR) {
  2193.                         return err;
  2194.                 }
  2195.  
  2196.                 *id = ret;
  2197.                 return err;
  2198.         }
  2199.  
  2200.         doc = dom_node_get_owner(ele);
  2201.         assert(doc != NULL);
  2202.  
  2203.         if (ele->id_name != NULL) {
  2204.                 name = ele->id_name;
  2205.         } else {
  2206.                 name = _dom_document_get_id_name(doc);
  2207.  
  2208.                 if (name == NULL) {
  2209.                         /* No ID attribute at all, just return NULL */
  2210.                         *id = NULL;
  2211.                         return DOM_NO_ERR;
  2212.                 }
  2213.         }
  2214.  
  2215.         err = _dom_element_get_attribute(ele, name, &ret);
  2216.         if (err != DOM_NO_ERR) {
  2217.                 return err;
  2218.         }
  2219.  
  2220.         if (ret != NULL) {
  2221.                 *id = ret;
  2222.         } else {
  2223.                 *id = NULL;
  2224.         }
  2225.  
  2226.         return err;
  2227. }
  2228.  
  2229.  
  2230.  
  2231. /*-------------- The dom_namednodemap functions -------------------------*/
  2232.  
  2233. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2234.  * details */
  2235. dom_exception attributes_get_length(void *priv, uint32_t *length)
  2236. {
  2237.         dom_element *e = (dom_element *) priv;
  2238.  
  2239.         *length = _dom_element_attr_list_length(e->attributes);
  2240.  
  2241.         return DOM_NO_ERR;
  2242. }
  2243.  
  2244. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2245.  * details */
  2246. dom_exception attributes_get_named_item(void *priv,
  2247.                 dom_string *name, struct dom_node **node)
  2248. {
  2249.         dom_element *e = (dom_element *) priv;
  2250.  
  2251.         return _dom_element_get_attribute_node(e, name, (dom_attr **) node);
  2252. }
  2253.  
  2254. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2255.  * details */
  2256. dom_exception attributes_set_named_item(void *priv,
  2257.                 struct dom_node *arg, struct dom_node **node)
  2258. {
  2259.         dom_element *e = (dom_element *) priv;
  2260.         dom_node_internal *n = (dom_node_internal *) arg;
  2261.  
  2262.         if (n->type != DOM_ATTRIBUTE_NODE)
  2263.                 return DOM_HIERARCHY_REQUEST_ERR;
  2264.  
  2265.         return _dom_element_set_attribute_node(e, (dom_attr *) arg,
  2266.                         (dom_attr **) node);
  2267. }
  2268.  
  2269. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2270.  * details */
  2271. dom_exception attributes_remove_named_item(
  2272.                 void *priv, dom_string *name,
  2273.                 struct dom_node **node)
  2274. {
  2275.         dom_element *e = (dom_element *) priv;
  2276.         dom_exception err;
  2277.  
  2278.         err = _dom_element_get_attribute_node(e, name, (dom_attr **) node);
  2279.         if (err != DOM_NO_ERR)
  2280.                 return err;
  2281.  
  2282.         if (*node == NULL) {
  2283.                 return DOM_NOT_FOUND_ERR;
  2284.         }
  2285.        
  2286.         return _dom_element_remove_attribute(e, name);
  2287. }
  2288.  
  2289. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2290.  * details */
  2291. dom_exception attributes_item(void *priv,
  2292.                 uint32_t index, struct dom_node **node)
  2293. {
  2294.         dom_attr_list * match = NULL;
  2295.         unsigned int num = index + 1;
  2296.         dom_element *e = (dom_element *) priv;
  2297.  
  2298.         match = _dom_element_attr_list_get_by_index(e->attributes, num);
  2299.  
  2300.         if (match != NULL) {
  2301.                 *node = (dom_node *) match->attr;
  2302.                 dom_node_ref(*node);
  2303.         } else {
  2304.                 *node = NULL;
  2305.         }
  2306.  
  2307.         return DOM_NO_ERR;
  2308. }
  2309.  
  2310. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2311.  * details */
  2312. dom_exception attributes_get_named_item_ns(
  2313.                 void *priv, dom_string *namespace,
  2314.                 dom_string *localname, struct dom_node **node)
  2315. {
  2316.         dom_element *e = (dom_element *) priv;
  2317.  
  2318.         return _dom_element_get_attribute_node_ns(e, namespace, localname,
  2319.                         (dom_attr **) node);
  2320. }
  2321.  
  2322. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2323.  * details */
  2324. dom_exception attributes_set_named_item_ns(
  2325.                 void *priv, struct dom_node *arg,
  2326.                 struct dom_node **node)
  2327. {
  2328.         dom_element *e = (dom_element *) priv;
  2329.         dom_node_internal *n = (dom_node_internal *) arg;
  2330.  
  2331.         if (n->type != DOM_ATTRIBUTE_NODE)
  2332.                 return DOM_HIERARCHY_REQUEST_ERR;
  2333.  
  2334.         return _dom_element_set_attribute_node_ns(e, (dom_attr *) arg,
  2335.                         (dom_attr **) node);
  2336. }
  2337.  
  2338. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2339.  * details */
  2340. dom_exception attributes_remove_named_item_ns(
  2341.                 void *priv, dom_string *namespace,
  2342.                 dom_string *localname, struct dom_node **node)
  2343. {
  2344.         dom_element *e = (dom_element *) priv;
  2345.         dom_exception err;
  2346.        
  2347.         err = _dom_element_get_attribute_node_ns(e, namespace, localname,
  2348.                         (dom_attr **) node);
  2349.         if (err != DOM_NO_ERR)
  2350.                 return err;
  2351.  
  2352.         if (*node == NULL) {
  2353.                 return DOM_NOT_FOUND_ERR;
  2354.         }
  2355.  
  2356.         return _dom_element_remove_attribute_ns(e, namespace, localname);
  2357. }
  2358.  
  2359. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2360.  * details */
  2361. void attributes_destroy(void *priv)
  2362. {
  2363.         dom_element *e = (dom_element *) priv;
  2364.  
  2365.         dom_node_unref(e);
  2366. }
  2367.  
  2368. /* Implementation function for NamedNodeMap, see core/namednodemap.h for
  2369.  * details */
  2370. bool attributes_equal(void *p1, void *p2)
  2371. {
  2372.         /* We have passed the pointer to this element as the private data,
  2373.          * and here we just need to compare whether the two elements are
  2374.          * equal
  2375.          */
  2376.         return p1 == p2;
  2377. }
  2378. /*------------------ End of namednodemap functions -----------------------*/
  2379.  
  2380.