Review: Bo Yang -- libDOM core (round 3)

John-Mark Bell jmb at netsurf-browser.org
Wed Aug 5 12:30:19 BST 2009


Precis:

This is round 3 of Bo Yang's libdom core changes.


Added files


Index: include/dom/core/typeinfo.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ include/dom/core/typeinfo.h	2009-08-05 12:14:54.000000000 +0100
@@ -0,0 +1,47 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#ifndef dom_core_typeinfo_h_
+#define dom_core_typeinfo_h_
+
+#include <stdbool.h>
+
+#include <dom/core/exceptions.h>
+
+struct dom_string;
+
+typedef struct dom_type_info dom_type_info;
+
+typedef enum {
+	DOM_TYPE_INFO_DERIVATION_RESTRICTION	= 0x00000001,
+	DOM_TYPE_INFO_DERIVATION_EXTENSION		= 0x00000002,
+	DOM_TYPE_INFO_DERIVATION_UNION			= 0x00000004,
+	DOM_TYPE_INFO_DERIVATION_LIST			= 0x00000008
+} dom_type_info_derivation_method;
+
+dom_exception _dom_type_info_get_type_name(dom_type_info *ti, 
+		struct dom_string **ret);
+#define dom_type_info_get_type_name(t, r) _dom_type_info_get_type_name( \
+		(dom_type_info *) (t), (struct dom_string **) (r))
+
+
+dom_exception _dom_type_info_get_type_namespace(dom_type_info *ti,
+		struct dom_string **ret);
+#define dom_type_info_get_type_namespace(t, r) _dom_type_info_get_type_namespace(\
+		(dom_type_info *) (t), (struct dom_string **) (r))
+
+
+dom_exception _dom_type_info_is_derived(dom_type_info *ti,
+		struct dom_string *namespace, struct dom_string *name, 
+		dom_type_info_derivation_method method, bool *ret);
+#define dom_type_info_is_derived(t, s, n, m, r)  _dom_type_info_is_derived(\
+		(dom_type_info *) (t), (struct dom_string *) (s), \
+		(struct dom_string *) (n), (dom_type_info_derivation_method) (m)\
+		(bool *) (r))
+
+
+#endif
Index: include/dom/core/comment.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ include/dom/core/comment.h	2009-08-05 12:14:54.000000000 +0100
@@ -0,0 +1,18 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#ifndef dom_core_comment_h_
+#define dom_core_comment_h_
+
+#include <stdbool.h>
+
+#include <dom/core/exceptions.h>
+#include <dom/core/characterdata.h>
+
+typedef struct dom_comment dom_comment;
+
+#endif
Index: src/utils/validate.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/validate.h	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,26 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ *
+ * This file contains the API used to validate whether certain element's 
+ * name/namespace are legal according the XML 1.0 standard. See 
+ *
+ * http://www.w3.org/TR/2004/REC-xml-20040204/
+ * 
+ * for detail.
+ */
+
+#ifndef  dom_utils_valid_h_
+#define  dom_utils_valid_h_
+
+#include <stdbool.h>
+
+struct dom_string;
+
+bool _dom_validate_name(struct dom_string *name);
+bool _dom_validate_ncname(struct dom_string *name);
+
+#endif
+
Index: src/utils/character_valid.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/character_valid.h	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,52 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *				http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ *
+ * This file contains the API used to validate whether certain character in
+ * name/value is legal according the XML 1.0 standard. See 
+ *
+ * http://www.w3.org/TR/2004/REC-xml-20040204/
+ * http://www.w3.org/TR/REC-xml/
+ * 
+ * for detail.
+ */
+
+#ifndef dom_utils_character_valid_h_
+#define dom_utils_character_valid_h_
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct xml_char_range {
+	unsigned int start;
+	unsigned int end;
+};
+
+struct xml_char_group {
+	size_t len;
+	const struct xml_char_range *range;
+};
+
+/* The groups */
+extern const struct xml_char_group base_char_group;
+extern const struct xml_char_group char_group;
+extern const struct xml_char_group combining_char_group;
+extern const struct xml_char_group digit_char_group;
+extern const struct xml_char_group extender_group;
+extern const struct xml_char_group ideographic_group;
+
+bool _dom_is_character_in_group(unsigned int ch, const struct xml_char_group *group);
+
+#define is_base_char(ch) _dom_is_character_in_group((ch), &base_char_group)
+#define is_char(ch) _dom_is_character_in_group((ch), &char_group)
+#define is_combining_char(ch) _dom_is_character_in_group((ch), &combining_char_group)
+#define is_digit(ch) _dom_is_character_in_group((ch), &digit_char_group)
+#define is_extender(ch) _dom_is_character_in_group((ch), &extender_group)
+#define is_ideographic(ch) _dom_is_character_in_group((ch), &ideographic_group)
+
+#define is_letter(ch)  (is_base_char(ch) || is_ideographic(ch))
+
+#endif
+
Index: src/utils/hashtable.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/hashtable.h	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,41 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2006 Rob Kendrick <rjek at rjek.com>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#ifndef dom_utils_hashtable_h_
+#define dom_utils_hashtable_h_
+
+#include <stdbool.h>
+#include <dom/functypes.h>
+
+typedef struct dom_hash_table dom_hash_table;
+/* The hash function */
+typedef unsigned int (*dom_hash_func)(void *key);
+/* Function to clone/delete key */
+typedef void *(*dom_key_func)(void *key, void *pw, dom_alloc alloc, void *alloc_pw, 
+		bool clone);
+/* Function to clone/delete value */
+typedef void *(*dom_value_func)(void *value, void *pw, dom_alloc alloc,
+		void *alloc_pw, bool clone);
+
+struct dom_hash_table *_dom_hash_create(unsigned int chains, dom_hash_func hash,
+		dom_alloc alloc, void *ptr);
+struct dom_hash_table *_dom_hash_clone(struct dom_hash_table *ht, 
+		dom_alloc alloc, void *pw, dom_key_func kf, void *key_pw, 
+		dom_value_func vf, void *value_pw);
+void _dom_hash_destroy(struct dom_hash_table *ht, dom_key_func kf, void *key_pw,
+		dom_value_func vf, void *value_pw);
+bool _dom_hash_add(struct dom_hash_table *ht, void *key, void *value, bool replace);
+void *_dom_hash_get(struct dom_hash_table *ht, void *key);
+void *_dom_hash_del(struct dom_hash_table *ht, void *key);
+void *_dom_hash_iterate(struct dom_hash_table *ht, unsigned int *c1,
+		unsigned int **c2);
+unsigned int _dom_hash_get_length(struct dom_hash_table *ht);
+unsigned int _dom_hash_get_chains(struct dom_hash_table *ht);
+dom_hash_func _dom_hash_get_func(struct dom_hash_table *ht);
+
+#endif
Index: src/utils/list.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/list.h	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,61 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ *
+ * This file contains the list structure used to compose lists. 
+ * 
+ * Note: This is a implementation of a doubld-linked cyclar list.
+ */
+
+#ifndef dom_utils_list_h_
+#define dom_utils_list_h_
+
+#include <stddef.h>
+
+struct list_entry {
+    struct list_entry *prev;
+    struct list_entry *next;
+};
+
+/**
+ * Initilise a list_entry structure
+ */
+static inline void list_init(struct list_entry *ent)
+{
+    ent->prev = ent;
+    ent->next = ent;
+}
+
+/**
+ * Append a new list_entry after the list
+ *
+ * \param head   The list header
+ * \param new    The new entry
+ *
+ * Note: Append a new entry to list started with head.
+ */
+static inline void list_append(struct list_entry *head, struct list_entry *new)
+{
+	new->next = head;
+	new->prev = head->prev;
+	head->prev->next = new;
+	head->prev = new;
+}
+
+/**
+ * Delete a list_entry from the list
+ *
+ * \param entry The entry need to be deleted from the list
+ */
+static inline void list_del(struct list_entry *ent)
+{
+    ent->prev->next = ent->next;
+    ent->next->prev = ent->prev;
+
+    ent->prev = ent;
+    ent->next = ent;
+}
+
+#endif
Index: src/utils/resource_mgr.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/resource_mgr.h	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,42 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *				http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#ifndef dom_utils_resource_mgr_h_
+#define dom_utils_resource_mgr_h_
+
+#include <dom/functypes.h>
+#include <dom/core/exceptions.h>
+
+#include "hashtable.h"
+
+struct lwc_context_s;
+struct lwc_string_s;
+struct dom_string;
+
+typedef struct dom_resource_mgr {
+	dom_alloc alloc;
+	void *pw;
+	struct lwc_context_s *ctx;
+} dom_resource_mgr;
+
+void *_dom_resource_mgr_alloc(struct dom_resource_mgr *res, void *ptr, 
+		size_t size);
+
+dom_exception _dom_resource_mgr_create_string(struct dom_resource_mgr *res,
+		const uint8_t *data, size_t len, struct dom_string **result);
+
+dom_exception _dom_resource_mgr_create_lwcstring(struct dom_resource_mgr *res,
+		const uint8_t *data, size_t len, struct lwc_string_s **result);
+
+dom_exception _dom_resource_mgr_create_string_from_lwcstring(
+		struct dom_resource_mgr *res, struct lwc_string_s *str, 
+		struct dom_string **result);
+
+dom_exception _dom_resource_mgr_create_hashtable(struct dom_resource_mgr *res,
+		size_t chains, dom_hash_func f, struct dom_hash_table **ht);
+
+#endif
Index: src/utils/validate.c
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/validate.c	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,174 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *				http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#include "utils/validate.h"
+
+#include <dom/core/string.h>
+
+#include "utils/character_valid.h"
+#include "utils/namespace.h"
+#include "utils/utils.h"
+
+/* An combination of various tests */
+static bool is_first_char(uint32_t ch);
+static bool is_name_char(uint32_t ch);
+
+/* Test whether the character can be the first character of
+ * a NCName. 
+ */
+static bool is_first_char(uint32_t ch)
+{
+	/* Refer http://www.w3.org/TR/REC-xml/ for detail */
+	if (((ch >= 'a') && (ch <= 'z')) ||
+		((ch >= 'A') && (ch <= 'Z')) ||
+		(ch == '_') || (ch == ':') ||
+		((ch >= 0xC0) && (ch <= 0xD6)) ||
+		((ch >= 0xD8) && (ch <= 0xF6)) ||
+		((ch >= 0xF8) && (ch <= 0x2FF)) ||
+		((ch >= 0x370) && (ch <= 0x37D)) ||
+		((ch >= 0x37F) && (ch <= 0x1FFF)) ||
+		((ch >= 0x200C) && (ch <= 0x200D)) ||
+		((ch >= 0x2070) && (ch <= 0x218F)) ||
+		((ch >= 0x2C00) && (ch <= 0x2FEF)) ||
+		((ch >= 0x3001) && (ch <= 0xD7FF)) ||
+		((ch >= 0xF900) && (ch <= 0xFDCF)) ||
+		((ch >= 0xFDF0) && (ch <= 0xFFFD)) ||
+		((ch >= 0x10000) && (ch <= 0xEFFFF)))
+		return true;
+
+	if (is_letter(ch) || ch == (uint32_t) '_' || ch == (uint32_t) ':') {
+		return true;
+	} 
+
+	return false;
+}
+
+/* Test whether the character can be a part of a NCName */
+static bool is_name_char(uint32_t ch)
+{
+	/* Refer http://www.w3.org/TR/REC-xml/ for detail */
+	if (((ch >= 'a') && (ch <= 'z')) ||
+		((ch >= 'A') && (ch <= 'Z')) ||
+		((ch >= '0') && (ch <= '9')) || /* !start */
+		(ch == '_') || (ch == ':') ||
+		(ch == '-') || (ch == '.') || (ch == 0xB7) || /* !start */
+		((ch >= 0xC0) && (ch <= 0xD6)) ||
+		((ch >= 0xD8) && (ch <= 0xF6)) ||
+		((ch >= 0xF8) && (ch <= 0x2FF)) ||
+		((ch >= 0x300) && (ch <= 0x36F)) || /* !start */
+		((ch >= 0x370) && (ch <= 0x37D)) ||
+		((ch >= 0x37F) && (ch <= 0x1FFF)) ||
+		((ch >= 0x200C) && (ch <= 0x200D)) ||
+		((ch >= 0x203F) && (ch <= 0x2040)) || /* !start */
+		((ch >= 0x2070) && (ch <= 0x218F)) ||
+		((ch >= 0x2C00) && (ch <= 0x2FEF)) ||
+		((ch >= 0x3001) && (ch <= 0xD7FF)) ||
+		((ch >= 0xF900) && (ch <= 0xFDCF)) ||
+		((ch >= 0xFDF0) && (ch <= 0xFFFD)) ||
+		((ch >= 0x10000) && (ch <= 0xEFFFF)))
+		return true;
+
+	if (is_letter(ch) == true)
+		return true;
+	if (is_digit(ch) == true)
+		return true;
+	if (is_combining_char(ch) == true)
+		return true;
+	if (is_extender(ch) == true)
+		return true;
+	
+	if (ch == (uint32_t) '.' || ch == (uint32_t) '-' || 
+			ch == (uint32_t) '_' || ch == (uint32_t) ':')
+		return true;
+
+	return false;
+}
+
+/* Test whether the name is a valid one according XML 1.0 standard.
+ * For the standard please refer:
+ *
+ * http://www.w3.org/TR/2004/REC-xml-20040204/
+ *
+ * \param   name	The name need to be tested
+ */
+bool _dom_validate_name(struct dom_string *name)
+{
+	uint32_t ch, len, i;
+	dom_exception err;
+
+	if (name == NULL)
+		return false;
+
+	len = dom_string_length(name);
+	if (len == 0)
+		return false;
+
+	/* Test the first character of this string */
+	err = dom_string_at(name, 0, &ch);
+	if (err != DOM_NO_ERR)
+		return false;
+
+	if (is_first_char(ch) == false)
+		return false;
+
+	/* Test all remain characters in this string */
+	for(i = 1; i < len; i++) {
+		err = dom_string_at(name, i, &ch);
+		if (err != DOM_NO_ERR)
+			return false;
+
+		if (is_name_char(ch) != true)
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * Validate whether the string is a legal NCName.
+ * Refer http://www.w3.org/TR/REC-xml-names/ for detail.
+ *
+ * \param   str	 The name to validate
+ */
+bool _dom_validate_ncname(struct dom_string *name)
+{
+	uint32_t ch, len, i;
+	dom_exception err;
+
+	if (name == NULL)
+		return false;
+
+	len = dom_string_length(name);
+	if (len == 0)
+		return false;
+
+	/* Test the first character of this string */
+	err = dom_string_at(name, 0, &ch);
+	if (err != DOM_NO_ERR)
+		return false;
+
+	if (is_letter(ch) == false && ch != (uint32_t) '_')
+		return false;
+	
+	/* Test all remain characters in this string */
+	for(i = 1; i < len; i++) {
+		err = dom_string_at(name, i, &ch);
+		if (err != DOM_NO_ERR)
+			return false;
+
+		if (is_name_char(ch) == false)
+			return false;
+
+		if (ch == (uint32_t) ':')
+			return false;
+	}
+
+	return true;
+}
Index: src/utils/character_valid.c
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/character_valid.c	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,213 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *				http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#include "utils/character_valid.h"
+
+#include <assert.h>
+
+static const struct xml_char_range base_char_range[] = { {0x41, 0x5a}, 
+	{0x61, 0x7a}, {0xc0, 0xd6}, {0xd8, 0xf6}, {0x00f8, 0x00ff}, {0x100, 0x131},
+	{0x134, 0x13e}, {0x141, 0x148}, {0x14a, 0x17e}, {0x180, 0x1c3},
+	{0x1cd, 0x1f0}, {0x1f4, 0x1f5}, {0x1fa, 0x217}, {0x250, 0x2a8},
+	{0x2bb, 0x2c1}, {0x386, 0x386}, {0x388, 0x38a}, {0x38c, 0x38c},
+	{0x38e, 0x3a1}, {0x3a3, 0x3ce}, {0x3d0, 0x3d6}, {0x3da, 0x3da},
+	{0x3dc, 0x3dc}, {0x3de, 0x3de}, {0x3e0, 0x3e0}, {0x3e2, 0x3f3},
+	{0x401, 0x40c}, {0x40e, 0x44f}, {0x451, 0x45c}, {0x45e, 0x481},
+	{0x490, 0x4c4}, {0x4c7, 0x4c8}, {0x4cb, 0x4cc}, {0x4d0, 0x4eb},
+	{0x4ee, 0x4f5}, {0x4f8, 0x4f9}, {0x531, 0x556}, {0x559, 0x559},
+	{0x561, 0x586}, {0x5d0, 0x5ea}, {0x5f0, 0x5f2}, {0x621, 0x63a},
+	{0x641, 0x64a}, {0x671, 0x6b7}, {0x6ba, 0x6be}, {0x6c0, 0x6ce},
+	{0x6d0, 0x6d3}, {0x6d5, 0x6d5}, {0x6e5, 0x6e6}, {0x905, 0x939},
+	{0x93d, 0x93d}, {0x958, 0x961}, {0x985, 0x98c}, {0x98f, 0x990},
+	{0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b2, 0x9b2}, {0x9b6, 0x9b9},
+	{0x9dc, 0x9dd}, {0x9df, 0x9e1}, {0x9f0, 0x9f1}, {0xa05, 0xa0a},
+	{0xa0f, 0xa10}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa32, 0xa33},
+	{0xa35, 0xa36}, {0xa38, 0xa39}, {0xa59, 0xa5c}, {0xa5e, 0xa5e},
+	{0xa72, 0xa74}, {0xa85, 0xa8b}, {0xa8d, 0xa8d}, {0xa8f, 0xa91},
+	{0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab2, 0xab3}, {0xab5, 0xab9},
+	{0xabd, 0xabd}, {0xae0, 0xae0}, {0xb05, 0xb0c}, {0xb0f, 0xb10},
+	{0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb32, 0xb33}, {0xb36, 0xb39},
+	{0xb3d, 0xb3d}, {0xb5c, 0xb5d}, {0xb5f, 0xb61}, {0xb85, 0xb8a},
+	{0xb8e, 0xb90}, {0xb92, 0xb95}, {0xb99, 0xb9a}, {0xb9c, 0xb9c},
+	{0xb9e, 0xb9f}, {0xba3, 0xba4}, {0xba8, 0xbaa}, {0xbae, 0xbb5},
+	{0xbb7, 0xbb9}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28},
+	{0xc2a, 0xc33}, {0xc35, 0xc39}, {0xc60, 0xc61}, {0xc85, 0xc8c},
+	{0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9},
+	{0xcde, 0xcde}, {0xce0, 0xce1}, {0xd05, 0xd0c}, {0xd0e, 0xd10},
+	{0xd12, 0xd28}, {0xd2a, 0xd39}, {0xd60, 0xd61}, {0xe01, 0xe2e},
+	{0xe30, 0xe30}, {0xe32, 0xe33}, {0xe40, 0xe45}, {0xe81, 0xe82},
+	{0xe84, 0xe84}, {0xe87, 0xe88}, {0xe8a, 0xe8a}, {0xe8d, 0xe8d},
+	{0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3}, {0xea5, 0xea5},
+	{0xea7, 0xea7}, {0xeaa, 0xeab}, {0xead, 0xeae}, {0xeb0, 0xeb0},
+	{0xeb2, 0xeb3}, {0xebd, 0xebd}, {0xec0, 0xec4}, {0xf40, 0xf47},
+	{0xf49, 0xf69}, {0x10a0, 0x10c5}, {0x10d0, 0x10f6}, {0x1100, 0x1100},
+	{0x1102, 0x1103}, {0x1105, 0x1107}, {0x1109, 0x1109}, {0x110b, 0x110c},
+	{0x110e, 0x1112}, {0x113c, 0x113c}, {0x113e, 0x113e}, {0x1140, 0x1140},
+	{0x114c, 0x114c}, {0x114e, 0x114e}, {0x1150, 0x1150}, {0x1154, 0x1155},
+	{0x1159, 0x1159}, {0x115f, 0x1161}, {0x1163, 0x1163}, {0x1165, 0x1165},
+	{0x1167, 0x1167}, {0x1169, 0x1169}, {0x116d, 0x116e}, {0x1172, 0x1173},
+	{0x1175, 0x1175}, {0x119e, 0x119e}, {0x11a8, 0x11a8}, {0x11ab, 0x11ab},
+	{0x11ae, 0x11af}, {0x11b7, 0x11b8}, {0x11ba, 0x11ba}, {0x11bc, 0x11c2},
+	{0x11eb, 0x11eb}, {0x11f0, 0x11f0}, {0x11f9, 0x11f9}, {0x1e00, 0x1e9b},
+	{0x1ea0, 0x1ef9}, {0x1f00, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45},
+	{0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f59, 0x1f59}, {0x1f5b, 0x1f5b},
+	{0x1f5d, 0x1f5d}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fbc},
+	{0x1fbe, 0x1fbe}, {0x1fc2, 0x1fc4}, {0x1fc6, 0x1fcc}, {0x1fd0, 0x1fd3},
+	{0x1fd6, 0x1fdb}, {0x1fe0, 0x1fec}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffc},
+	{0x2126, 0x2126}, {0x212a, 0x212b}, {0x212e, 0x212e}, {0x2180, 0x2182},
+	{0x3041, 0x3094}, {0x30a1, 0x30fa}, {0x3105, 0x312c}, {0xac00, 0xd7a3}
+};
+
+const struct xml_char_group base_char_group = {
+		sizeof(base_char_range) / sizeof(base_char_range[0]), base_char_range};
+
+static const struct xml_char_range char_range[] = { {0x100, 0xd7ff},
+	{0xe000, 0xfffd}, {0x10000, 0x10ffff} 
+};
+
+const struct xml_char_group char_group = { 
+		sizeof(char_range) / sizeof(char_range[0]), char_range};
+
+static const struct xml_char_range combining_char_range[] = { {0x300, 0x345},
+	{0x360, 0x361}, {0x483, 0x486}, {0x591, 0x5a1}, {0x5a3, 0x5b9},
+	{0x5bb, 0x5bd}, {0x5bf, 0x5bf}, {0x5c1, 0x5c2}, {0x5c4, 0x5c4},
+	{0x64b, 0x652}, {0x670, 0x670}, {0x6d6, 0x6dc}, {0x6dd, 0x6df},
+	{0x6e0, 0x6e4}, {0x6e7, 0x6e8}, {0x6ea, 0x6ed}, {0x901, 0x903},
+	{0x93c, 0x93c}, {0x93e, 0x94c}, {0x94d, 0x94d}, {0x951, 0x954},
+	{0x962, 0x963}, {0x981, 0x983}, {0x9bc, 0x9bc}, {0x9be, 0x9be},
+	{0x9bf, 0x9bf}, {0x9c0, 0x9c4}, {0x9c7, 0x9c8}, {0x9cb, 0x9cd},
+	{0x9d7, 0x9d7}, {0x9e2, 0x9e3}, {0xa02, 0xa02}, {0xa3c, 0xa3c},
+	{0xa3e, 0xa3e}, {0xa3f, 0xa3f}, {0xa40, 0xa42}, {0xa47, 0xa48},
+	{0xa4b, 0xa4d}, {0xa70, 0xa71}, {0xa81, 0xa83}, {0xabc, 0xabc},
+	{0xabe, 0xac5}, {0xac7, 0xac9}, {0xacb, 0xacd}, {0xb01, 0xb03},
+	{0xb3c, 0xb3c}, {0xb3e, 0xb43}, {0xb47, 0xb48}, {0xb4b, 0xb4d},
+	{0xb56, 0xb57}, {0xb82, 0xb83}, {0xbbe, 0xbc2}, {0xbc6, 0xbc8},
+	{0xbca, 0xbcd}, {0xbd7, 0xbd7}, {0xc01, 0xc03}, {0xc3e, 0xc44},
+	{0xc46, 0xc48}, {0xc4a, 0xc4d}, {0xc55, 0xc56}, {0xc82, 0xc83},
+	{0xcbe, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd}, {0xcd5, 0xcd6},
+	{0xd02, 0xd03}, {0xd3e, 0xd43}, {0xd46, 0xd48}, {0xd4a, 0xd4d},
+	{0xd57, 0xd57}, {0xe31, 0xe31}, {0xe34, 0xe3a}, {0xe47, 0xe4e},
+	{0xeb1, 0xeb1}, {0xeb4, 0xeb9}, {0xebb, 0xebc}, {0xec8, 0xecd},
+	{0xf18, 0xf19}, {0xf35, 0xf35}, {0xf37, 0xf37}, {0xf39, 0xf39},
+	{0xf3e, 0xf3e}, {0xf3f, 0xf3f}, {0xf71, 0xf84}, {0xf86, 0xf8b},
+	{0xf90, 0xf95}, {0xf97, 0xf97}, {0xf99, 0xfad}, {0xfb1, 0xfb7},
+	{0xfb9, 0xfb9}, {0x20d0, 0x20dc}, {0x20e1, 0x20e1}, {0x302a, 0x302f},
+	{0x3099, 0x3099}, {0x309a, 0x309a}
+};
+
+const struct xml_char_group combining_char_group = {
+		sizeof(combining_char_range) / sizeof(combining_char_range[0]), 
+		combining_char_range };
+
+static const struct xml_char_range digit_char_range[] = { {0x30, 0x39}, 
+	{0x660, 0x669}, {0x6f0, 0x6f9}, {0x966, 0x96f}, {0x9e6, 0x9ef}, 
+	{0xa66, 0xa6f}, {0xae6, 0xaef}, {0xb66, 0xb6f}, {0xbe7, 0xbef}, 
+	{0xc66, 0xc6f}, {0xce6, 0xcef}, {0xd66, 0xd6f}, {0xe50, 0xe59}, 
+	{0xed0, 0xed9}, {0xf20, 0xf29}
+};
+
+const struct xml_char_group digit_char_group = {
+		sizeof(digit_char_range) / sizeof(digit_char_range[0]), 
+		digit_char_range };
+
+static const struct xml_char_range extender_range[] = { {0xb7, 0xb7}, 
+	{0x2d0, 0x2d0}, {0x2d1, 0x2d1}, {0x387, 0x387}, {0x640, 0x640}, 
+	{0xe46, 0xe46}, {0xec6, 0xec6}, {0x3005, 0x3005}, {0x3031, 0x3035}, 
+	{0x309d, 0x309e}, {0x30fc, 0x30fe}
+};
+
+const struct xml_char_group extender_group = {
+		sizeof(extender_range) / sizeof(extender_range[0]), extender_range };
+
+static const struct xml_char_range ideographic_range[] = { {0x3007, 0x3007},
+	{0x3021, 0x3029}, {0x4e00, 0x9fa5}
+};
+
+const struct xml_char_group ideographic_group = {
+		sizeof(ideographic_range) / sizeof(ideographic_range[0]), 
+		ideographic_range };
+
+/* The binary search helper function */
+static bool binary_search(unsigned int ch, int left, int right, 
+		const struct xml_char_range *range);
+
+/* Search for ch in range[left, right]
+ */
+bool binary_search(unsigned int ch, int left, int right, 
+		const struct xml_char_range *range)
+{
+	if (left > right)
+		return false;
+
+	int mid = (left + right) / 2;
+	if (ch >= range[mid].start && ch <= range[mid].end)
+		return true;
+
+	if (ch < range[mid].start)
+		return binary_search(ch, left, mid - 1, range);
+
+	if (ch > range[mid].end)
+		return binary_search(ch, mid + 1, right, range);
+
+	return false;
+}
+
+/* Test whether certain character belongs to some XML character group
+ *
+ * \param ch		The being tested character.
+ * \param group	 The character group.
+ * \return		  True if the character belongs to the group, false otherwise.
+ *
+ * Generally, we use an algorithm like binary search to find the desired 
+ * character in the group. The time complexity is about lg(n) and here n is
+ * at most 180, so, I think the algorithm is fast enough for name validation.
+ */
+bool _dom_is_character_in_group(unsigned int ch, const struct xml_char_group *group)
+{
+	int len = group->len;
+	const struct xml_char_range *range = group->range;
+
+	if (ch < range[0].start || ch > range[len-1].end)
+		return false;
+
+	return binary_search(ch, 0, len - 1, range);
+}
+
+#ifdef CHVALID_DEBUG
+/* The following is the testcases for this file. 
+ * Compile this file :
+ *
+ * gcc -o test -DCHVALID_DEBUG character_valid.c
+ *
+ */
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	unsigned int ch = 0x666;
+
+	assert(is_digit(ch) == true);
+	assert(is_base_char(ch) == false);
+	assert(is_char(ch) == true);
+	assert(is_extender(ch) == false);
+	assert(is_combining_char(ch) == false);
+	assert(is_ideographic(ch) == false);
+
+	ch = 0xf40;
+
+	assert(is_digit(ch) == false);
+	assert(is_base_char(ch) == true);
+	assert(is_char(ch) == true);
+	assert(is_extender(ch) == false);
+	assert(is_combining_char(ch) == false);
+	assert(is_ideographic(ch) == false);
+
+	printf("The test pass.\n");
+	return 0;
+}
+
+#endif
Index: src/utils/hashtable.c
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/hashtable.c	2009-08-05 12:14:56.000000000 +0100
@@ -0,0 +1,488 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *				http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2006 Rob Kendrick <rjek at rjek.com>
+ * Copyright 2006 Richard Wilson <info at tinct.net>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+#ifdef TEST_RIG
+#include <stdio.h>
+#endif
+#include "utils/hashtable.h"
+
+
+struct _dom_hash_entry {
+	void *key;			/**< The key pointer */
+	void *value;			/**< The value pointer */
+	struct _dom_hash_entry *next;	/**< next entry */
+};
+
+struct dom_hash_table {
+	unsigned int nchains;
+	dom_hash_func hash;
+	struct _dom_hash_entry **chain;
+	unsigned int number;		/**< The enries in this table */
+
+	dom_alloc alloc;
+	void *ptr;
+};
+
+
+/**
+ * Create a new hash table, and return a context for it.  The memory consumption
+ * of a hash table is approximately 8 + (nchains * 12) bytes if it is empty.
+ *
+ * \param  chains Number of chains/buckets this hash table will have.  This
+ *		  should be a prime number, and ideally a prime number just
+ *		  over a power of two, for best performance and distribution.
+ * \param hash	  The hash function
+ * \param alloc	  The memory allocator
+ * \param ptr	  The private pointer for the allocator
+ * \return struct dom_hash_table containing the context of this hash table or NULL
+ *	   if there is insufficent memory to create it and its chains.
+ */
+
+struct dom_hash_table *_dom_hash_create(unsigned int chains, dom_hash_func hash, 
+		dom_alloc alloc, void *ptr)
+{
+	struct dom_hash_table *r = alloc(NULL, sizeof(struct dom_hash_table), ptr);
+
+	if (r == NULL) {
+		return NULL;
+	}
+
+	r->nchains = chains;
+	r->hash = hash;
+	r->alloc = alloc;
+	r->ptr = ptr;
+	r->chain = (struct _dom_hash_entry **)alloc(NULL, 
+			chains*sizeof(struct _dom_hash_entry *), ptr);
+	r->number = 0;
+
+	unsigned int i;
+	for (i = 0; i < chains; i++)
+		r->chain[i] = NULL;
+
+	if (r->chain == NULL) {
+		alloc(r, 0, ptr);
+		return NULL;
+	}
+
+	return r;
+}
+
+/**
+ * Clone a hash table.
+ *
+ * \param ht		Hash table to clone.
+ * \param alloc		The allocator.
+ * \param pw		The private data for the allocator.
+ * \param kf		The function pointer used to copy the key.
+ * \param key_pw	The private data for the key cloner.
+ * \param vf		The function pointer used to copy the value.
+ * \param value_pw	The private data for the value cloner.
+ *
+ * \return 			The cloned hash table.
+ */
+struct dom_hash_table *_dom_hash_clone(struct dom_hash_table *ht, 
+		dom_alloc alloc, void *pw, dom_key_func kf, void *key_pw, 
+		dom_value_func vf, void *value_pw)
+{
+	struct dom_hash_table *ret;
+	
+	ret = _dom_hash_create(ht->nchains, ht->hash, alloc, pw);
+	if (ret == NULL)
+		return NULL;
+
+	void *key = NULL, *nkey = NULL;
+	void *value = NULL, *nvalue = NULL;
+	unsigned int c1, *c2 = NULL;
+	while ( (key = _dom_hash_iterate(ht, &c1, &c2)) != NULL) {
+		nkey = kf(key, key_pw, alloc, pw, true);
+		if (nkey == NULL) {
+			_dom_hash_destroy(ret, kf, key_pw, vf, value_pw);
+			return NULL;
+		}
+
+		value = _dom_hash_get(ht, key);
+		nvalue = vf(value, value_pw, alloc, pw, true);
+		if (nvalue == NULL) {
+			kf(nkey, key_pw, alloc, pw, false);
+			_dom_hash_destroy(ret, kf, key_pw, vf, value_pw);
+			return NULL;
+		}
+
+		if (_dom_hash_add(ret, nkey, nvalue, false) == false) {
+			_dom_hash_destroy(ret, kf, key_pw, vf, value_pw);
+			return NULL;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Destroys a hash table, freeing all memory associated with it.
+ *
+ * \param  ht	 Hash table to destroy.  After the function returns, this
+ *		 will nolonger be valid.
+ * \param func	 The client provided destroy function
+ * \param pw	 The private data pointer for this destroy function
+ */
+
+void _dom_hash_destroy(struct dom_hash_table *ht, dom_key_func kf, 
+		void *key_pw, dom_value_func vf, void *value_pw)
+{
+	unsigned int i;
+
+	if (ht == NULL)
+		return;
+
+	assert(ht->alloc != NULL);
+
+	for (i = 0; i < ht->nchains; i++) {
+		if (ht->chain[i] != NULL) {
+			struct _dom_hash_entry *e = ht->chain[i];
+			while (e) {
+				struct _dom_hash_entry *n = e->next;
+				if (kf != NULL) {
+					kf(e->key, key_pw, ht->alloc, ht->ptr, false);
+				}
+				if (vf != NULL) {
+					vf(e->value, value_pw, ht->alloc, ht->ptr, false);
+				}
+				ht->alloc(e, 0, ht->ptr);
+				e = n;
+			}
+		}
+	}
+
+	ht->alloc(ht->chain, 0, ht->ptr);
+	ht->alloc(ht, 0, ht->ptr);
+}
+
+/**
+ * Adds a key/value pair to a hash table.  If the key you're adding is already
+ * in the hash table, it does not replace it, but it does take precedent over
+ * it.  The old key/value pair will be inaccessable but still in memory until
+ * _dom_hash_destroy() is called on the hash table.
+ *
+ * \param  ht	  The hash table context to add the key/value pair to.
+ * \param  key	  The key to associate the value with.
+ * \param  value  The value to associate the key with.
+ * \return true if the add succeeded, false otherwise.  (Failure most likely
+ *	   indicates insufficent memory to make copies of the key and value.
+ */
+
+bool _dom_hash_add(struct dom_hash_table *ht, void *key, void *value, 
+		bool replace)
+{
+	unsigned int h, c;
+	struct _dom_hash_entry *e;
+
+	if (ht == NULL || key == NULL || value == NULL)
+		return false;
+
+	h = ht->hash(key);
+	c = h % ht->nchains;
+
+	for (e = ht->chain[c]; e; e = e->next)
+		if (key == e->key) {
+			if (replace == true) {
+				e->value = value;
+				return true;
+			} else {
+				return false;
+			}
+		}
+
+	assert(ht->alloc != NULL);
+
+	e = ht->alloc(NULL, sizeof(struct _dom_hash_entry), ht->ptr);
+	if (e == NULL) {
+		return false;
+	}
+
+	e->key = key;
+	e->value = value;
+
+	e->next = ht->chain[c];
+	ht->chain[c] = e;
+	ht->number ++;
+
+	return true;
+}
+
+/**
+ * Looks up a the value associated with with a key from a specific hash table.
+ *
+ * \param  ht	  The hash table context to look up the key in.
+ * \param  key	  The key to search for.
+ * \return The value associated with the key, or NULL if it was not found.
+ */
+
+void *_dom_hash_get(struct dom_hash_table *ht, void *key)
+{
+	unsigned int h, c;
+	struct _dom_hash_entry *e;
+
+	if (ht == NULL || key == NULL)
+		return NULL;
+
+	h = ht->hash(key);
+	c = h % ht->nchains;
+
+	for (e = ht->chain[c]; e; e = e->next)
+		if (key == e->key) 
+			return e->value;
+
+	return NULL;
+}
+
+/**
+ * Delete the key from the hashtable.
+ *
+ * \param ht		The hashtable object
+ * \param key 		The key to delete
+ * \return 		The deleted value
+ */
+void *_dom_hash_del(struct dom_hash_table *ht, void *key)
+{
+	unsigned int h, c;
+	struct _dom_hash_entry *e, *p;
+	void *ret;
+
+	if (ht == NULL || key == NULL)
+		return NULL;
+
+	h = ht->hash(key);
+	c = h % ht->nchains;
+
+	assert(ht->alloc != NULL);
+
+	p = ht->chain[c];
+	for (e = p; e; p = e, e = e->next)
+		if (key == e->key) {
+			if (p != e) {
+				p->next = e->next;
+			} else {
+				/* The first item in this chain is target*/
+				ht->chain[c] = e->next;
+			}
+
+			ret = e->value;
+			ht->alloc(e, 0, ht->ptr);
+			ht->number --;
+			return ret;
+		}
+	
+	return NULL;
+}
+
+/**
+ * Iterate through all available hash keys.
+ *
+ * \param  ht	The hash table context to iterate.
+ * \param  c1	Pointer to first context
+ * \param  c2	Pointer to second context (set to 0 on first call)
+ * \return The next hash key, or NULL for no more keys
+ */
+
+void *_dom_hash_iterate(struct dom_hash_table *ht, unsigned int *c1, unsigned int **c2) {
+	struct _dom_hash_entry **he = (struct _dom_hash_entry **)c2;
+
+	if (ht == NULL)
+		return NULL;
+
+	if (!*he)
+		*c1 = -1;
+	else
+		*he = (*he)->next;
+
+	if (*he)
+		return (*he)->key;
+
+	while (!*he) {
+		(*c1)++;
+		if (*c1 >= ht->nchains)
+			return NULL;
+		*he = ht->chain[*c1];
+	}
+	return (*he)->key;
+}
+
+/* Get the number of elements in this hash table 
+ *
+ * \param ht	The hash table
+ * 
+ * \return 	The number of elements
+ */
+unsigned int _dom_hash_get_length(struct dom_hash_table *ht)
+{
+	return ht->number;
+}
+
+/* Get the chain number of this hash table 
+ *
+ * \param ht	The hash table
+ * 
+ * \return 	The number of chains
+ */
+unsigned int _dom_hash_get_chains(struct dom_hash_table *ht)
+{
+	return ht->nchains;
+}
+
+/* Get the hash function of this hash table 
+ *
+ * \param ht	The hash table
+ * 
+ * \return 	The hash function
+ */
+dom_hash_func _dom_hash_get_func(struct dom_hash_table *ht)
+{
+	return ht->hash;
+}
+
+/* A simple test rig.  To compile, use:
+ * gcc -g  -o hashtest -I../ -I../../include  -DTEST_RIG  hashtable.c
+ *
+ * If you make changes to this hash table implementation, please rerun this
+ * test, and if possible, through valgrind to make sure there are no memory
+ * leaks or invalid memory accesses.  If you add new functionality, please
+ * include a test for it that has good coverage along side the other tests.
+ */
+
+#ifdef TEST_RIG
+
+
+/**
+ * Hash a pointer, returning a 32bit value.  
+ *
+ * \param  ptr   The pointer to hash.
+ * \return The calculated hash value for the pointer.
+ */
+
+static inline unsigned int _dom_hash_pointer_fnv(void *ptr)
+{
+	return (unsigned int) ptr;
+}
+
+static void *test_alloc(void *p, size_t size, void *ptr)
+{
+	if (p != NULL) {
+		free(p);
+		return NULL;
+	}
+
+	if (p == NULL) {
+		return malloc(size);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct dom_hash_table *a, *b;
+	FILE *dict;
+	char keybuf[BUFSIZ], valbuf[BUFSIZ];
+	int i;
+	char *cow="cow", *moo="moo", *pig="pig", *oink="oink",
+			*chicken="chikcken", *cluck="cluck",
+			*dog="dog", *woof="woof", *cat="cat", 
+			*meow="meow";
+	void *ret;
+
+	a = _dom_hash_create(79, _dom_hash_pointer_fnv, test_alloc, NULL);
+	assert(a != NULL);
+
+	b = _dom_hash_create(103, _dom_hash_pointer_fnv, test_alloc, NULL);
+	assert(b != NULL);
+
+	_dom_hash_add(a, cow, moo ,true);
+	_dom_hash_add(b, moo, cow ,true);
+
+	_dom_hash_add(a, pig, oink ,true);
+	_dom_hash_add(b, oink, pig ,true);
+
+	_dom_hash_add(a, chicken, cluck ,true);
+	_dom_hash_add(b, cluck, chicken ,true);
+
+	_dom_hash_add(a, dog, woof ,true);
+	_dom_hash_add(b, woof, dog ,true);
+
+	_dom_hash_add(a, cat, meow ,true);
+	_dom_hash_add(b, meow, cat ,true);
+
+#define MATCH(x,y) assert(!strcmp((char *)hash_get(a, x), (char *)y)); \
+		assert(!strcmp((char *)hash_get(b, y), (char *)x))
+	MATCH(cow, moo);
+	MATCH(pig, oink);
+	MATCH(chicken, cluck);
+	MATCH(dog, woof);
+	MATCH(cat, meow);
+
+	assert(hash_get_length(a) == 5);
+	assert(hash_get_length(b) == 5);
+
+	_dom_hash_del(a, cat);
+	_dom_hash_del(b, meow);
+	assert(hash_get(a, cat) == NULL);
+	assert(hash_get(b, meow) == NULL);
+
+	assert(hash_get_length(a) == 4);
+	assert(hash_get_length(b) == 4);
+
+	_dom_hash_destroy(a, NULL, NULL);
+	_dom_hash_destroy(b, NULL, NULL);
+
+	/* this test requires /usr/share/dict/words - a large list of English
+	 * words.  We load the entire file - odd lines are used as keys, and
+	 * even lines are used as the values for the previous line.  we then
+	 * work through it again making sure everything matches.
+	 *
+	 * We do this twice - once in a hash table with many chains, and once
+	 * with a hash table with fewer chains.
+	 */
+
+	a = _dom_hash_create(1031, _dom_hash_pointer_fnv, test_alloc, NULL);
+	b = _dom_hash_create(7919, _dom_hash_pointer_fnv, test_alloc, NULL);
+
+	dict = fopen("/usr/share/dict/words", "r");
+	if (dict == NULL) {
+		fprintf(stderr, "Unable to open /usr/share/dict/words - extensive testing skipped.\n");
+		exit(0);
+	}
+
+	while (!feof(dict)) {
+		fscanf(dict, "%s", keybuf);
+		fscanf(dict, "%s", valbuf);
+		_dom_hash_add(a, keybuf, valbuf, true);
+		_dom_hash_add(b, keybuf, valbuf, true);
+	}
+
+	for (i = 0; i < 5; i++) {
+		fseek(dict, 0, SEEK_SET);
+
+		while (!feof(dict)) {
+			fscanf(dict, "%s", keybuf);
+			fscanf(dict, "%s", valbuf);
+			assert(strcmp(hash_get(a, keybuf), valbuf) == 0);
+			assert(strcmp(hash_get(b, keybuf), valbuf) == 0);
+		}
+	}
+
+	_dom_hash_destroy(a, NULL, NULL);
+	_dom_hash_destroy(b, NULL, NULL);
+
+	fclose(dict);
+
+	return 0;
+}
+
+#endif
Index: src/utils/resource_mgr.c
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/utils/resource_mgr.c	2009-08-05 12:14:57.000000000 +0100
@@ -0,0 +1,99 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *				http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#include "resource_mgr.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+#include "core/string.h"
+
+/**
+ * Allocate some memory with this allocator
+ *
+ * \param res	The resource manager
+ * \param size	The size of memory to allocate
+ */
+void *_dom_resource_mgr_alloc(struct dom_resource_mgr *res, void *ptr, 
+		size_t size)
+{
+	return res->alloc(ptr, size, res->pw);
+}
+
+/**
+ * Create a dom_string using this resource manager
+ *
+ * \param res 	The resource manager
+ * \param data	The data pointer
+ * \param len	The length of data
+ * \param result 	The returned dom_string
+ */
+dom_exception _dom_resource_mgr_create_string(struct dom_resource_mgr *res,
+		const uint8_t *data, size_t len, struct dom_string **result)
+{
+	return dom_string_create(res->alloc, res->pw, data, len, result);
+}
+
+/**
+ * Create a lwc_string using this resource manager
+ *
+ * \param res 	The resource manager
+ * \param data	The data pointer
+ * \param len	The length of the data
+ * \param result	The returned lwc_string
+ */
+dom_exception _dom_resource_mgr_create_lwcstring(struct dom_resource_mgr *res,
+		const uint8_t *data, size_t len, struct lwc_string_s **result)
+{
+	lwc_error lerr;
+
+	assert(res->ctx != NULL);
+
+	lerr = lwc_context_intern(res->ctx, (const char *) data, len, 
+			result);
+	
+	return _dom_exception_from_lwc_error(lerr);
+}
+
+/**
+ * Create a lwc_string from a dom_string using this resource manager
+ *
+ * \param res 	The resource manager
+ * \param str	The dom_string to intern
+ * \param result	The returned lwc_string
+ */
+dom_exception _dom_resource_mgr_create_string_from_lwcstring(
+		struct dom_resource_mgr *res, struct lwc_string_s *str, 
+		struct dom_string **result)
+{
+	assert(res->ctx != NULL);
+
+	return _dom_string_create_from_lwcstring(res->alloc, res->pw, res->ctx, 
+				str, result);
+}
+
+/**
+ * Create a _dom_hash_table using this resource manager
+ * 
+ * \param res 	The resource manager
+ * \param chains	The number of buckets of the hash table
+ * \param f		The hash function 
+ * \param ht	The returned hash table
+ */
+dom_exception _dom_resource_mgr_create_hashtable(struct dom_resource_mgr *res,
+		size_t chains, dom_hash_func f, struct dom_hash_table **ht)
+{
+	struct dom_hash_table *ret;
+
+	ret = _dom_hash_create(chains, f, res->alloc, res->pw);
+	if (ret == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ht = ret;
+	return DOM_NO_ERR;
+}
Index: src/core/string.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/core/string.h	2009-08-05 12:14:57.000000000 +0100
@@ -0,0 +1,31 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#ifndef dom_internal_core_string_h_
+#define dom_internal_core_string_h_
+
+#include <dom/core/string.h>
+
+/* Create a DOM string from a lwc_string
+ * This function call mainly used for create a string from lwc_string */
+dom_exception _dom_string_create_from_lwcstring(dom_alloc alloc, void *pw,
+		struct lwc_context_s *ctx, struct lwc_string_s *str, 
+		struct dom_string **ret);
+
+/* Make the dom_string be interned in the lwc_context_s */
+dom_exception _dom_string_intern(struct dom_string *str, 
+		struct lwc_context_s *ctx, struct lwc_string_s **lwcstr);
+
+/* Compare the raw data of two lwc_strings for equality when the two string
+ * belong to different lwc_context */
+int _dom_lwc_string_compare_raw(struct lwc_string_s *s1, struct lwc_string_s *s2);
+
+/* Map the lwc_error to dom_exception */
+dom_exception _dom_exception_from_lwc_error(lwc_error err);
+
+#endif
+
Index: src/core/typeinfo.c
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/core/typeinfo.c	2009-08-05 12:14:59.000000000 +0100
@@ -0,0 +1,68 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#include <dom/core/typeinfo.h>
+#include <dom/core/string.h>
+
+#include "utils/utils.h"
+
+/* TypeInfo object */
+struct dom_type_info {
+	struct lwc_string_s *type;
+	struct lwc_string_s *namespace;
+};
+
+/**
+ * Get the type name of this dom_type_info
+ *
+ * \param ti	The dom_type_info
+ * \param ret	The name
+ */
+dom_exception _dom_type_info_get_type_name(dom_type_info *ti, 
+		struct dom_string **ret)
+{
+	UNUSED(ti);
+	UNUSED(ret);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Get the namespace of this type info
+ *
+ * \param ti 	The dom_type_info
+ * \param ret	The namespace
+ */
+dom_exception _dom_type_info_get_type_namespace(dom_type_info *ti,
+		struct dom_string **ret)
+{
+	UNUSED(ti);
+	UNUSED(ret);
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Whether this type info is derived from another one
+ *
+ * \param ti	The dom_type_info
+ * \param namespace	The namespace of name
+ * \param name	The name of the base typeinfo
+ * \param method	The derive method
+ * \param ret	The return value
+ */
+dom_exception _dom_type_info_is_derived(dom_type_info *ti,
+		struct dom_string *namespace, struct dom_string *name, 
+		dom_type_info_derivation_method method, bool *ret)
+{
+	UNUSED(ti);
+	UNUSED(namespace);
+	UNUSED(name);
+	UNUSED(method);
+	UNUSED(ret);
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
Index: src/bootstrap/implementation.c
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/bootstrap/implementation.c	2009-08-05 12:15:05.000000000 +0100
@@ -0,0 +1,422 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+/**
+ * Note: The DOMImplementation Object here is a singleton object. It is 
+ * initialised when the libDOM is initialised, it registers itself into
+ * the implreg and clients of it can get it by calling:
+ *
+ * dom_implregistry_get_dom_implementation or 
+ * dom_implregistry_get_dom_implementation_list
+ * 
+ */
+
+#include <dom/bootstrap/implpriv.h>
+#include <dom/bootstrap/implregistry.h>
+#include <dom/dom.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "core/node.h"
+#include "core/document_type.h"
+
+#include "utils/utils.h"
+#include "utils/validate.h"
+#include "utils/namespace.h"
+
+#include "bootstrap/implementation.h"
+
+static dom_alloc _alloc;
+static void *_pw;
+
+static dom_exception impl_get_dom_implementation(
+		struct dom_string *features,
+		struct dom_implementation **impl);
+static dom_exception impl_get_dom_implementation_list(
+		struct dom_string *features,
+		struct dom_implementation_list **list);
+
+static dom_exception impl_implementation_has_feature(
+		struct dom_implementation *impl,
+		struct dom_string *feature,
+		struct dom_string *version,
+		bool *result);
+static dom_exception impl_implementation_create_document_type(
+		struct dom_implementation *impl,
+		struct dom_string *qname,
+		struct dom_string *public_id,
+		struct dom_string *system_id,
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document_type **doctype);
+static dom_exception impl_implementation_create_document(
+		struct dom_implementation *impl,
+		struct dom_string *namespace,
+		struct dom_string *qname,
+		struct dom_document_type *doctype,
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document **doc);
+static dom_exception impl_implementation_get_feature(
+		struct dom_implementation *impl,
+		struct dom_string *feature,
+		struct dom_string *version,
+		void **object);
+static void dom_implementation_destroy(struct dom_implementation *impl);
+
+
+static struct dom_implementation_source dom_impl_src = {
+	impl_get_dom_implementation,
+	impl_get_dom_implementation_list
+};
+
+static struct dom_implementation dom_impl = {
+	impl_implementation_has_feature,
+	impl_implementation_create_document_type,
+	impl_implementation_create_document,
+	impl_implementation_get_feature,
+	dom_implementation_destroy,
+	0
+};
+
+/**
+ * Get a DOM implementation that supports the requested features
+ *
+ * \param features  String containing required features
+ * \param impl      Pointer to location to receive implementation
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function. The implementation's
+ * destroy() method will be called once it is no longer used.
+ *
+ * The implementation will be referenced, so the client need not
+ * do this explicitly. The client must unref the implementation
+ * once it has finished with it.
+ */
+dom_exception impl_get_dom_implementation(
+		struct dom_string *features,
+		struct dom_implementation **impl)
+{
+	UNUSED(features);
+
+	dom_impl.refcnt++;
+
+	*impl = &dom_impl;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Get a list of DOM implementations that support the requested
+ * features
+ *
+ * \param features  String containing required features
+ * \param list      Pointer to location to receive list
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function. The ::alloc/::pw
+ * pair must be stored on the list object, such that the list
+ * and its contents may be freed once they are no longer needed.
+ *
+ * List nodes reference the implementation objects they point to.
+ *
+ * The list will be referenced, so the client need not do this
+ * explicitly. The client must unref the list once it has finished
+ * with it.
+ */
+dom_exception impl_get_dom_implementation_list(
+		struct dom_string *features,
+		struct dom_implementation_list **list)
+{
+	struct dom_implementation_list *l;
+	struct dom_implementation_list_item *i;
+
+	UNUSED(features);
+
+	l = _alloc(NULL, sizeof(struct dom_implementation_list), _pw);
+	if (l == NULL)
+		return DOM_NO_MEM_ERR;
+
+	i = _alloc(NULL, sizeof(struct dom_implementation_list_item), _pw);
+	if (i == NULL) {
+		_alloc(l, 0, _pw);
+		return DOM_NO_MEM_ERR;
+	}
+
+	i->impl = &dom_impl;
+	i->next = NULL;
+	i->prev = NULL;
+
+	l->head = i;
+
+	l->refcnt = 1;
+
+	*list = l;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Test whether a DOM implementation implements a specific feature
+ * and version
+ *
+ * \param impl     The DOM implementation to query
+ * \param feature  The feature to test for
+ * \param version  The version number of the feature to test for
+ * \param result   Pointer to location to receive result
+ * \return DOM_NO_ERR.
+ */
+dom_exception impl_implementation_has_feature(
+		struct dom_implementation *impl,
+		struct dom_string *feature,
+		struct dom_string *version,
+		bool *result)
+{
+	UNUSED(impl);
+	UNUSED(feature);
+	UNUSED(version);
+	UNUSED(result);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Create a document type node
+ *
+ * \param impl       The implementation to create the node
+ * \param qname      The qualified name of the document type
+ * \param public_id  The external subset public identifier
+ * \param system_id  The external subset system identifier
+ * \param doctype    Pointer to location to receive result
+ * \return DOM_NO_ERR on success,
+ *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
+ *         DOM_NAMESPACE_ERR         if ::qname is malformed.
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function.
+ *
+ * The doctype will be referenced, so the client need not do this
+ * explicitly. The client must unref the doctype once it has
+ * finished with it.
+ */
+dom_exception impl_implementation_create_document_type(
+		struct dom_implementation *impl,
+		struct dom_string *qname,
+		struct dom_string *public_id,
+		struct dom_string *system_id,
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document_type **doctype)
+{
+	struct dom_document_type *d;
+	struct dom_string *prefix = NULL, *lname = NULL;
+	dom_exception err;
+
+	UNUSED(impl);
+
+	if (qname != NULL && _dom_validate_name(qname) == false)
+		return DOM_INVALID_CHARACTER_ERR;
+
+	err = _dom_namespace_split_qname(qname, &prefix, &lname);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if ((prefix != NULL && _dom_validate_ncname(prefix) == false) ||
+			(lname != NULL && _dom_validate_ncname(lname) == false))
+		return DOM_NAMESPACE_ERR;
+
+	/* Create the doctype */
+	err = dom_document_type_create(qname, public_id, system_id,
+			alloc, pw, ctx, &d);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	*doctype = d;
+	if (prefix != NULL)
+		dom_string_unref(prefix);
+	if (lname != NULL)
+		dom_string_unref(lname);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Create a document node
+ *
+ * \param impl       The implementation to create the node
+ * \param namespace  The namespace URI of the document element
+ * \param qname      The qualified name of the document element
+ * \param doctype    The type of document to create
+ * \param doc        Pointer to location to receive result
+ * \return DOM_NO_ERR on success,
+ *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
+ *         DOM_NAMESPACE_ERR         if ::qname is malformed, or if
+ *                                   ::qname has a prefix and
+ *                                   ::namespace is NULL, or if
+ *                                   ::qname is NULL and ::namespace
+ *                                   is non-NULL, or if ::qname has
+ *                                   a prefix "xml" and ::namespace
+ *                                   is not
+ *                                   "http://www.w3.org/XML/1998/namespace",
+ *                                   or if ::impl does not support
+ *                                   the "XML" feature and
+ *                                   ::namespace is non-NULL,
+ *         DOM_WRONG_DOCUMENT_ERR    if ::doctype is already being
+ *                                   used by a document, or if it
+ *                                   was not created by ::impl,
+ *         DOM_NOT_SUPPORTED_ERR     if ::impl does not support the
+ *                                   feature "XML" and the language
+ *                                   exposed through Document does
+ *                                   not support XML namespaces.
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function.
+ *
+ * The document will be referenced, so the client need not do this
+ * explicitly. The client must unref the document once it has
+ * finished with it.
+ */
+dom_exception impl_implementation_create_document(
+		struct dom_implementation *impl,
+		struct dom_string *namespace,
+		struct dom_string *qname,
+		struct dom_document_type *doctype,
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document **doc)
+{
+	struct dom_document *d;
+	dom_exception err;
+
+	if (qname != NULL && _dom_validate_name(qname) == false)
+		return  DOM_INVALID_CHARACTER_ERR;
+  
+	err = _dom_namespace_validate_qname(qname, namespace);
+	if (err != DOM_NO_ERR)
+		return DOM_NAMESPACE_ERR;
+
+	if (doctype != NULL) {
+			if (dom_node_get_parent(doctype) != NULL || 
+					_dom_document_type_get_impl(doctype) != impl)
+				return DOM_WRONG_DOCUMENT_ERR;
+	}
+
+	/* Create document object */
+	err = dom_document_create(impl, alloc, pw, ctx, &d);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	/* Set its doctype, if necessary */
+	if (doctype != NULL) {
+		struct dom_node *ins_doctype = NULL;
+
+		err = dom_node_append_child((struct dom_node *) d, 
+				(struct dom_node *) doctype, &ins_doctype);
+		if (err != DOM_NO_ERR) {
+			dom_node_unref((struct dom_node *) d);
+			return err;
+		}
+
+		/* Not interested in inserted doctype */
+		if (ins_doctype != NULL)
+			dom_node_unref(ins_doctype);
+	}
+
+	/* Create root element and attach it to document */
+	if (qname != NULL) {
+		struct dom_element *e;
+		struct dom_node *inserted;
+
+		err = dom_document_create_element_ns(d, namespace, qname, &e);
+		if (err != DOM_NO_ERR) {
+			dom_node_unref((struct dom_node *) d);
+			return err;
+		}
+
+		err = dom_node_append_child((struct dom_node *) d,
+				(struct dom_node *) e, &inserted);
+		if (err != DOM_NO_ERR) {
+			dom_node_unref((struct dom_node *) e);
+			dom_node_unref((struct dom_node *) d);
+			return err;
+		}
+
+		/* No longer interested in inserted node */
+		dom_node_unref(inserted);
+
+		/* Done with element */
+		dom_node_unref((struct dom_node *) e);
+	}
+
+	*doc = d;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Retrieve a specialized object which implements the specified
+ * feature and version
+ *
+ * \param impl     The implementation to create the object
+ * \param feature  The requested feature
+ * \param version  The version number of the feature
+ * \param object   Pointer to location to receive object
+ * \return DOM_NO_ERR.
+ *
+ * Any memory allocated by this call should be allocated using
+ * the provided memory (de)allocation function.
+ */
+dom_exception impl_implementation_get_feature(
+		struct dom_implementation *impl,
+		struct dom_string *feature,
+		struct dom_string *version,
+		void **object)
+{
+	UNUSED(impl);
+	UNUSED(feature);
+	UNUSED(version);
+	UNUSED(object);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Destroy a DOM implementation instance
+ *
+ * \param impl  The instance to destroy
+ */
+void dom_implementation_destroy(struct dom_implementation *impl)
+{
+	UNUSED(impl);
+
+	/* Nothing to do -- we're statically allocated */
+}
+
+/**
+ * Initialise the DOM implementation
+ *
+ * \param alloc  Pointer to memory (de)allocation function
+ * \param pw     Pointer to client-specific private data
+ * \return DOM_NO_ERR on success
+ */
+dom_exception _dom_implementation_initialise(dom_alloc alloc, void *pw)
+{
+	_alloc = alloc;
+	_pw = pw;
+
+	return dom_register_source(&dom_impl_src);
+}
+
+/**
+ * Finalise the DOM implementation
+ */
+void _dom_implementation_finalise(void)
+{
+	_alloc = NULL;
+	_pw = NULL;
+}
+
+
Index: src/bootstrap/implementation.h
===================================================================
--- /dev/null	2009-04-16 19:17:07.000000000 +0100
+++ src/bootstrap/implementation.h	2009-08-05 12:15:05.000000000 +0100
@@ -0,0 +1,14 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
+ */
+
+#ifndef dom_bootstrap_implementation_h_
+#define dom_bootstrap_implementation_h_
+
+dom_exception _dom_implementation_initialise(dom_alloc alloc, void *pw);
+void _dom_implementation_finalise(void);
+
+#endif


Changed files


 Makefile                             |    3 
 bindings/hubbub/parser.c             |  115 +-
 bindings/hubbub/parser.h             |    4 
 bindings/xml/Makefile                |    2 
 bindings/xml/xmlparser.c             |  117 +-
 bindings/xml/xmlparser.h             |    4 
 include/dom/bootstrap/implpriv.h     |   42 
 include/dom/bootstrap/implregistry.h |   10 
 include/dom/core/attr.h              |    8 
 include/dom/core/document.h          |    6 
 include/dom/core/element.h           |    2 
 include/dom/core/implementation.h    |   11 
 include/dom/core/namednodemap.h      |    4 
 include/dom/core/node.h              |   18 
 include/dom/core/string.h            |   15 
 include/dom/dom.h                    |   18 
 src/bootstrap/Makefile               |    2 
 src/bootstrap/implregistry.c         |   60 -
 src/bootstrap/init_fini.c            |   20 
 src/core/Makefile                    |   13 
 src/core/attr.c                      |  341 ++++-
 src/core/attr.h                      |   98 +
 src/core/cdatasection.c              |   70 +
 src/core/cdatasection.h              |   25 
 src/core/characterdata.c             |   80 +
 src/core/characterdata.h             |   29 
 src/core/comment.c                   |   73 +
 src/core/comment.h                   |   23 
 src/core/doc_fragment.c              |   99 +
 src/core/doc_fragment.h              |   24 
 src/core/document.c                  |  950 ++++++++++++----
 src/core/document.h                  |  103 +
 src/core/document_type.c             |  208 +++
 src/core/document_type.h             |   28 
 src/core/element.c                   | 2008 ++++++++++++++++++++++++-----------
 src/core/element.h                   |  100 +
 src/core/entity_ref.c                |  104 +
 src/core/entity_ref.h                |   31 
 src/core/implementation.c            |   25 
 src/core/impllist.c                  |   18 
 src/core/namednodemap.c              |  356 ------
 src/core/namednodemap.h              |   50 
 src/core/node.c                      | 1108 +++++++++++++++----
 src/core/node.h                      |  134 ++
 src/core/nodelist.c                  |  199 ++-
 src/core/nodelist.h                  |   23 
 src/core/pi.c                        |   69 +
 src/core/pi.h                        |   22 
 src/core/string.c                    |  341 +++++
 src/core/text.c                      |  318 ++++-
 src/core/text.h                      |   44 
 src/utils/Makefile                   |    3 
 src/utils/namespace.c                |  101 +
 src/utils/namespace.h                |    7 
 test/Makefile                        |   13 
 55 files changed, 5647 insertions(+), 2052 deletions(-)


Index: test/Makefile
===================================================================
--- test/Makefile	(revision 9058)
+++ test/Makefile	(working copy)
@@ -1,18 +1,17 @@
-testlib_files := lib/comparators.c;lib/list.c;lib/testassert.c
-testlib_files := $(testlib_files);lib/testobject.c;lib/utils.c
+testutils_files := testutils/comparators.c;testutils/list.c;testutils/domasserts.c
+testutils_files := $(testutils_files);testutils/utils.c;testutils/foreach.c;testutils/load.c
 
-TESTCFLAGS := $(TESTCFLAGS) -I$(CURDIR) -I$(CURDIR)/$(DIR)
+TESTCFLAGS := $(TESTCFLAGS) -I$(CURDIR) -I$(CURDIR)/testutils
 
-DIR_TEST_ITEMS := binding:binding.c;$(testlib_files) \
-		test-list:test-list.c;$(testlib_files)
+DIR_TEST_ITEMS := $(testutils_files)
 
 define add_xml_test
   ifeq ($$(WANT_TEST),yes)
-    $(DIR)xml/c/$1.c: $(DIR)xml/tests/$1.xml
+	$(DIR)xml/c/$1.c: $(DIR)xml/tests/$1.xml
 	$$(Q)$$(XSLTPROC) $$(XSLTPROCFLAGS) -o $$@ \
 		$(DIR)transform/test-to-c.xsl $$<
 
-    DIR_TEST_ITEMS := $$(DIR_TEST_ITEMS) $1:xml/c/$1.c;$$(testlib_files)
+	DIR_TEST_ITEMS := $$(DIR_TEST_ITEMS) $1:xml/c/$1.c;$$(testlib_files)
   endif
 
   DISTCLEAN_ITEMS := $$(DISTCLEAN_ITEMS) $(DIR)xml/c/$1.c
Index: include/dom/dom.h
===================================================================
--- include/dom/dom.h	(revision 9058)
+++ include/dom/dom.h	(working copy)
@@ -38,17 +38,19 @@
 #include <dom/core/string.h>
 #include <dom/core/text.h>
 #include <dom/core/pi.h>
+#include <dom/core/typeinfo.h>
+#include <dom/core/comment.h>
 
 typedef enum dom_namespace {
-       DOM_NAMESPACE_NULL    = 0,
-       DOM_NAMESPACE_HTML    = 1,
-       DOM_NAMESPACE_MATHML  = 2,
-       DOM_NAMESPACE_SVG     = 3,
-       DOM_NAMESPACE_XLINK   = 4,
-       DOM_NAMESPACE_XML     = 5,
-       DOM_NAMESPACE_XMLNS   = 6,
+	DOM_NAMESPACE_NULL    = 0,
+	DOM_NAMESPACE_HTML    = 1,
+	DOM_NAMESPACE_MATHML  = 2,
+	DOM_NAMESPACE_SVG     = 3,
+	DOM_NAMESPACE_XLINK   = 4,
+	DOM_NAMESPACE_XML     = 5,
+	DOM_NAMESPACE_XMLNS   = 6,
 
-       DOM_NAMESPACE_COUNT   = 7
+	DOM_NAMESPACE_COUNT   = 7
 } dom_namespace;
 
 extern struct dom_string *dom_namespaces[DOM_NAMESPACE_COUNT];
Index: include/dom/core/element.h
===================================================================
--- include/dom/core/element.h	(revision 9058)
+++ include/dom/core/element.h	(working copy)
@@ -211,7 +211,7 @@
 			dom_element_remove_attribute_ns(element, namespace, 
 			localname);
 }
-#define dom_element_remove_attribute_ns(e, n, l, v) \
+#define dom_element_remove_attribute_ns(e, n, l) \
 		dom_element_remove_attribute_ns((dom_element *) (e), \
 		(struct dom_string *) (n), (struct dom_string *) (l))
 
Index: include/dom/core/string.h
===================================================================
--- include/dom/core/string.h	(revision 9058)
+++ include/dom/core/string.h	(working copy)
@@ -10,6 +10,7 @@
 
 #include <inttypes.h>
 #include <stddef.h>
+#include <libwapcaplet/libwapcaplet.h>
 
 #include <dom/functypes.h>
 #include <dom/core/exceptions.h>
@@ -25,6 +26,14 @@
 dom_exception dom_string_create(dom_alloc alloc, void *pw,
 		const uint8_t *ptr, size_t len, struct dom_string **str);
 
+/* Clone a dom_string */
+dom_exception dom_string_clone(dom_alloc alloc, void *pw, struct dom_string *str,
+		struct dom_string **ret);
+
+/* Get the internal lwc_string */
+dom_exception dom_string_get_intern(struct dom_string *str, 
+		struct lwc_context_s **ctx, struct lwc_string_s **lwcstr);
+
 /* Case sensitively compare two DOM strings */
 int dom_string_cmp(struct dom_string *s1, struct dom_string *s2);
 /* Case insensitively compare two DOM strings */
@@ -38,6 +47,12 @@
 /* Get the length, in characters, of a dom string */
 uint32_t dom_string_length(struct dom_string *str);
 
+/* Get the UCS-4 character at position index, the index should be in 
+ * [0, length), and length can be get by calling dom_string_length
+ */
+dom_exception dom_string_at(struct dom_string *str, uint32_t index, 
+		uint32_t *ch);
+
 /* Concatenate two dom strings */
 dom_exception dom_string_concat(struct dom_string *s1, struct dom_string *s2,
 		struct dom_string **result);
Index: include/dom/core/attr.h
===================================================================
--- include/dom/core/attr.h	(revision 9058)
+++ include/dom/core/attr.h	(working copy)
@@ -32,7 +32,7 @@
 			struct dom_string **result);
 	dom_exception (*dom_attr_set_value)(struct dom_attr *attr,
 			struct dom_string *value);
-	dom_exception (*dom_attr_get_owner)(struct dom_attr *attr,
+	dom_exception (*dom_attr_get_owner_element)(struct dom_attr *attr,
 			struct dom_element **result);
 	dom_exception (*dom_attr_get_schema_type_info)(struct dom_attr *attr,
 			struct dom_type_info **result);
@@ -74,13 +74,13 @@
 #define dom_attr_set_value(a, v) dom_attr_set_value((struct dom_attr *) (a), \
 		(struct dom_string *) (v))
 
-static inline dom_exception dom_attr_get_owner(struct dom_attr *attr,
+static inline dom_exception dom_attr_get_owner_element(struct dom_attr *attr,
 		struct dom_element **result)
 {
 	return ((dom_attr_vtable *) ((dom_node *) attr)->vtable)->
-			dom_attr_get_owner(attr, result);
+			dom_attr_get_owner_element(attr, result);
 }
-#define dom_attr_get_owner(a, r) dom_attr_get_owner((struct dom_attr *) (a), \
+#define dom_attr_get_owner_element(a, r) dom_attr_get_owner_element((struct dom_attr *) (a), \
 		(struct dom_element **) (r))
 
 static inline dom_exception dom_attr_get_schema_type_info(struct dom_attr *attr,
Index: include/dom/core/document.h
===================================================================
--- include/dom/core/document.h	(revision 9058)
+++ include/dom/core/document.h	(working copy)
@@ -9,6 +9,8 @@
 #define dom_core_document_h_
 
 #include <stdbool.h>
+#include <inttypes.h>
+#include <stddef.h>
 #include <stdint.h>
 
 #include <dom/core/exceptions.h>
@@ -29,6 +31,7 @@
 struct dom_processing_instruction;
 struct dom_string;
 struct dom_text;
+struct lwc_string_s;
 
 typedef struct dom_document dom_document;
 
@@ -114,9 +117,6 @@
 			struct dom_string *qname, struct dom_node **result);
 } dom_document_vtable;
 
-dom_exception dom_document_create_string(struct dom_document *doc,
-		const uint8_t *data, size_t len, struct dom_string **result);
-
 static inline dom_exception dom_document_get_doctype(struct dom_document *doc,
 		struct dom_document_type **result)
 {
Index: include/dom/core/implementation.h
===================================================================
--- include/dom/core/implementation.h	(revision 9058)
+++ include/dom/core/implementation.h	(working copy)
@@ -30,20 +30,19 @@
 dom_exception dom_implementation_create_document_type(
 		struct dom_implementation *impl, struct dom_string *qname,
 		struct dom_string *public_id, struct dom_string *system_id,
-		struct dom_document_type **doctype,
-		dom_alloc alloc, void *pw);
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document_type **doctype);
 
 dom_exception dom_implementation_create_document(
 		struct dom_implementation *impl,
 		struct dom_string *namespace, struct dom_string *qname,
 		struct dom_document_type *doctype,
-		struct dom_document **doc,
-		dom_alloc alloc, void *pw);
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document **doc);
 
 dom_exception dom_implementation_get_feature(
 		struct dom_implementation *impl,
 		struct dom_string *feature, struct dom_string *version,
-		void **object,
-		dom_alloc alloc, void *pw);
+		void **object);
 
 #endif
Index: include/dom/core/node.h
===================================================================
--- include/dom/core/node.h	(revision 9058)
+++ include/dom/core/node.h	(working copy)
@@ -127,7 +127,7 @@
 			dom_node_internal **result);
 	dom_exception (*dom_node_normalize)(dom_node_internal *node);
 	dom_exception (*dom_node_is_supported)(dom_node_internal *node,
-			struct dom_string *feature, dom_node_internal *version,
+			struct dom_string *feature, struct dom_string *version,
 			bool *result);
 	dom_exception (*dom_node_get_namespace)(dom_node_internal *node,
 			struct dom_string **result);
@@ -367,16 +367,16 @@
 #define dom_node_normalize(n) dom_node_normalize((dom_node *) (n))
 
 static inline dom_exception dom_node_is_supported(struct dom_node *node,
-		struct dom_string *feature, struct dom_node *version,
+		struct dom_string *feature, struct dom_string *version,
 		bool *result)
 {
 	return ((dom_node_vtable *) node->vtable)->dom_node_is_supported(
 			(dom_node_internal *) node, feature, 
-			(dom_node_internal *) version, result);
+			version, result);
 }
 #define dom_node_is_supported(n, f, v, r) dom_node_is_supported( \
-		(dom_node *) (n), (struct dom_string *) (f), (dom_node *) (v),\
-		(bool *) (r))
+		(dom_node *) (n), (struct dom_string *) (f), \
+		(struct dom_string *) (v), (bool *) (r))
 
 static inline dom_exception dom_node_get_namespace(struct dom_node *node,
 		struct dom_string **result)
@@ -385,7 +385,7 @@
 			(dom_node_internal *) node, result);
 }
 #define dom_node_get_namespace(n, r) dom_node_get_namespace((dom_node *) (n), \
-		(struct dom_string *) (r))
+		(struct dom_string **) (r))
 
 static inline dom_exception dom_node_get_prefix(struct dom_node *node,
 		struct dom_string **result)
@@ -394,7 +394,7 @@
 			(dom_node_internal *) node, result);
 }
 #define dom_node_get_prefix(n, r) dom_node_get_prefix((dom_node *) (n), \
-		(struct dom_string *) (r))
+		(struct dom_string **) (r))
 
 static inline dom_exception dom_node_set_prefix(struct dom_node *node,
 		struct dom_string *prefix)
@@ -412,7 +412,7 @@
 			(dom_node_internal *) node, result);
 }
 #define dom_node_get_local_name(n, r) dom_node_get_local_name((dom_node *) (n),\
-		(struct dom_string *) (r))
+		(struct dom_string **) (r))
 
 static inline dom_exception dom_node_has_attributes(struct dom_node *node, 
 		bool *result)
@@ -489,7 +489,7 @@
 	return ((dom_node_vtable *) node->vtable)->dom_node_is_default_namespace(
 			(dom_node_internal *) node, namespace, result);
 }
-#define dom_node_is_default_namesapce(n, ns, r) dom_node_is_default_namespace(\
+#define dom_node_is_default_namespace(n, ns, r) dom_node_is_default_namespace(\
 		(dom_node *) (n), (struct dom_string *) (ns), (bool *) (r))
 
 static inline dom_exception dom_node_lookup_namespace(struct dom_node *node,
Index: include/dom/core/namednodemap.h
===================================================================
--- include/dom/core/namednodemap.h	(revision 9058)
+++ include/dom/core/namednodemap.h	(working copy)
@@ -43,7 +43,7 @@
 
 #define dom_namednodemap_remove_named_item(m, n, r) \
 		_dom_namednodemap_remove_named_item((dom_namednodemap *) (m), \
-		(dom_string *) (n), (dom_node **) (n))
+		(dom_string *) (n), (dom_node **) (r))
 
 
 dom_exception _dom_namednodemap_item(struct dom_namednodemap *map,
@@ -60,7 +60,7 @@
 
 #define dom_namednodemap_get_named_item_ns(m, n, l, r) \
 		_dom_namednodemap_get_named_item_ns((dom_namednodemap *) (m), \
-		(dom_string *) (n), (dom_string *) (l), (dom_node **) (n))
+		(dom_string *) (n), (dom_string *) (l), (dom_node **) (r))
 
 
 dom_exception _dom_namednodemap_set_named_item_ns(
Index: include/dom/bootstrap/implregistry.h
===================================================================
--- include/dom/bootstrap/implregistry.h	(revision 9058)
+++ include/dom/bootstrap/implregistry.h	(working copy)
@@ -15,16 +15,18 @@
 struct dom_implementation_list;
 struct dom_string;
 
+/* Initialise the dom_implementation */
+dom_exception dom_implregistry_dom_implementation_initialise(
+		dom_alloc allocator, void *ptr);
+
 /* Retrieve a DOM implementation from the registry */
 dom_exception dom_implregistry_get_dom_implementation(
 		struct dom_string *features,
-		struct dom_implementation **impl,
-		dom_alloc alloc, void *pw);
+		struct dom_implementation **impl);
 
 /* Get a list of DOM implementations that support the requested features */
 dom_exception dom_implregistry_get_dom_implementation_list(
 		struct dom_string *features,
-		struct dom_implementation_list **list,
-		dom_alloc alloc, void *pw);
+		struct dom_implementation_list **list);
 
 #endif
Index: include/dom/bootstrap/implpriv.h
===================================================================
--- include/dom/bootstrap/implpriv.h	(revision 9058)
+++ include/dom/bootstrap/implpriv.h	(working copy)
@@ -33,6 +33,7 @@
 
 struct dom_document;
 struct dom_document_type;
+struct lwc_context_s;
 
 /**
  * DOM Implementation
@@ -61,8 +62,6 @@
 	 * \param public_id  The external subset public identifier
 	 * \param system_id  The external subset system identifier
 	 * \param doctype    Pointer to location to receive result
-	 * \param alloc      Memory (de)allocation function
-	 * \param pw         Pointer to client-specific private data
 	 * \return DOM_NO_ERR on success,
 	 *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
 	 *         DOM_NAMESPACE_ERR         if ::qname is malformed,
@@ -83,8 +82,8 @@
 			struct dom_string *qname,
 			struct dom_string *public_id,
 			struct dom_string *system_id,
-			struct dom_document_type **doctype,
-			dom_alloc alloc, void *pw);
+			dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+			struct dom_document_type **doctype);
 
 	/**
 	 * Create a document node
@@ -94,8 +93,6 @@
 	 * \param qname      The qualified name of the document element
 	 * \param doctype    The type of document to create
 	 * \param doc        Pointer to location to receive result
-	 * \param alloc      Memory (de)allocation function
-	 * \param pw         Pointer to client-specific private data
 	 * \return DOM_NO_ERR on success,
 	 *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
 	 *         DOM_NAMESPACE_ERR         if ::qname is malformed, or if
@@ -128,8 +125,8 @@
 			struct dom_string *namespace,
 			struct dom_string *qname,
 			struct dom_document_type *doctype,
-			struct dom_document **doc,
-			dom_alloc alloc, void *pw);
+			dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+			struct dom_document **doc);
 
 	/**
 	 * Retrieve a specialized object which implements the specified
@@ -139,8 +136,6 @@
 	 * \param feature  The requested feature
 	 * \param version  The version number of the feature
 	 * \param object   Pointer to location to receive object
-	 * \param alloc    Memory (de)allocation function
-	 * \param pw       Pointer to client-specific private data
 	 * \return DOM_NO_ERR.
 	 *
 	 * Any memory allocated by this call should be allocated using
@@ -149,8 +144,7 @@
 	dom_exception (*get_feature)(struct dom_implementation *impl,
 			struct dom_string *feature,
 			struct dom_string *version,
-			void **object,
-			dom_alloc alloc, void *pw);
+			void **object);
 
 	/**
 	 * Destroy a DOM implementation instance
@@ -179,10 +173,14 @@
 struct dom_implementation_list {
 	struct dom_implementation_list_item *head;	/**< Head of list */
 
-	dom_alloc alloc;		/**< Memory (de)allocation function */
-	void *pw;			/**< Pointer to client data */
-
 	uint32_t refcnt;		/**< Reference count */
+
+	/**
+	 * Destroy a DOM implementation instance
+	 *
+	 * \param impl  The instance to destroy
+	 */
+	void (*destroy)(struct dom_implementation_list *impllist);
 };
 
 
@@ -213,8 +211,7 @@
 	 */
 	dom_exception (*get_dom_implementation)(
 			struct dom_string *features,
-			struct dom_implementation **impl,
-			dom_alloc alloc, void *pw);
+			struct dom_implementation **impl);
 
 	/**
 	 * Get a list of DOM implementations that support the requested
@@ -239,17 +236,16 @@
 	 */
 	dom_exception (*get_dom_implementation_list)(
 			struct dom_string *features,
-			struct dom_implementation_list **list,
-			dom_alloc alloc, void *pw);
+			struct dom_implementation_list **list);
 };
 
 /* Register a source with the DOM library */
-dom_exception dom_register_source(struct dom_implementation_source *source,
-		dom_alloc alloc, void *pw);
+dom_exception dom_register_source(struct dom_implementation_source *source);
 
 /* Create a DOM document */
 dom_exception dom_document_create(struct dom_implementation *impl,
-		dom_alloc alloc, void *pw, struct dom_document **doc);
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document **doc);
 
 /* Set a document's buffer */
 void dom_document_set_buffer(struct dom_document *doc, uint8_t *buffer, 
@@ -259,7 +255,7 @@
 dom_exception dom_document_type_create(struct dom_string *qname,
 		struct dom_string *public_id, 
 		struct dom_string *system_id,
-		dom_alloc alloc, void *pw, 
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
 		struct dom_document_type **doctype);
 
 #endif
Index: src/utils/namespace.h
===================================================================
--- src/utils/namespace.h	(revision 9058)
+++ src/utils/namespace.h	(working copy)
@@ -14,6 +14,7 @@
 struct dom_document;
 struct dom_string;
 
+
 /* Initialise the namespace component */
 dom_exception _dom_namespace_initialise(dom_alloc alloc, void *pw);
 
@@ -28,5 +29,11 @@
 dom_exception _dom_namespace_split_qname(struct dom_string *qname,
 		struct dom_string **prefix, struct dom_string **localname);
 
+/* Get the XML prefix dom_string */
+struct dom_string *_dom_namespace_get_xml_prefix(void);
+
+/* Get the XMLNS prefix dom_string */
+struct dom_string *_dom_namespace_get_xmlns_prefix(void);
+
 #endif
 
Index: src/utils/Makefile
===================================================================
--- src/utils/Makefile	(revision 9058)
+++ src/utils/Makefile	(working copy)
@@ -1,4 +1,5 @@
 # Sources
-DIR_SOURCES := namespace.c
+DIR_SOURCES := namespace.c hashtable.c resource_mgr.c character_valid.c \
+	validate.c
 
 include build/makefiles/Makefile.subdir
Index: src/utils/namespace.c
===================================================================
--- src/utils/namespace.c	(revision 9058)
+++ src/utils/namespace.c	(working copy)
@@ -1,8 +1,9 @@
 /*
  * This file is part of libdom.
  * Licensed under the MIT License,
- *                http://www.opensource.org/licenses/mit-license.php
+ *				http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
 #include <string.h>
@@ -10,6 +11,7 @@
 #include <dom/dom.h>
 
 #include "utils/namespace.h"
+#include "utils/validate.h"
 #include "utils/utils.h"
 
 
@@ -37,7 +39,7 @@
  * Initialise the namespace component
  *
  * \param alloc  Pointer to memory (de)allocation function
- * \param pw     Pointer to client-specific private data
+ * \param pw	 Pointer to client-specific private data
  * \return DOM_NO_ERR on success.
  */
 dom_exception _dom_namespace_initialise(dom_alloc alloc, void *pw)
@@ -110,31 +112,40 @@
 /**
  * Ensure a QName is valid
  *
- * \param qname      The qname to validate
+ * \param qname	  The qname to validate
  * \param namespace  The namespace URI associated with the QName, or NULL
- * \return DOM_NO_ERR                if valid,
- *         DOM_INVALID_CHARACTER_ERR if ::qname contains an invalid character,
- *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
- *                                   prefix and ::namespace is NULL, or
- *                                   ::qname has a prefix "xml" and
- *                                   ::namespace is not
- *                                   "http://www.w3.org/XML/1998/namespace",
- *                                   or ::qname has a prefix "xmlns" and
- *                                   ::namespace is not
- *                                   "http://www.w3.org/2000/xmlns", or
- *                                   ::namespace is
- *                                   "http://www.w3.org/2000/xmlns" and
- *                                   ::qname is not (or is not prefixed by)
- *                                   "xmlns".
+ * \return DOM_NO_ERR				if valid,
+ *		 DOM_INVALID_CHARACTER_ERR 	if ::qname contains an invalid character,
+ *		 DOM_NAMESPACE_ERR		 	if ::qname is malformed, or it has a
+ *									prefix and ::namespace is NULL, or
+ *									::qname has a prefix "xml" and
+ *									::namespace is not
+ *									"http://www.w3.org/XML/1998/namespace",
+ *									or ::qname has a prefix "xmlns" and
+ *									::namespace is not
+ *									"http://www.w3.org/2000/xmlns", or
+ *									::namespace is
+ *									"http://www.w3.org/2000/xmlns" and
+ *									::qname is not (or is not prefixed by)
+ *									"xmlns".
  */
 dom_exception _dom_namespace_validate_qname(struct dom_string *qname,
 		struct dom_string *namespace)
 {
-	uint32_t colon;
+	uint32_t colon, len;
 
-	/** \todo search qname for invalid characters */
-	/** \todo ensure qname is not malformed */
+	if (qname == NULL){
+		if (namespace != NULL)
+			return DOM_NAMESPACE_ERR;
+		if (namespace == NULL)
+			return DOM_NO_ERR;
+	}
 
+	if (_dom_validate_name(qname) == false)
+		return DOM_NAMESPACE_ERR;
+
+	len = dom_string_length(qname);
+
 	/* Find colon */
 	colon = dom_string_index(qname, ':');
 
@@ -147,9 +158,14 @@
 				dom_string_cmp(qname, xmlns) != 0) {
 			return DOM_NAMESPACE_ERR;
 		}
+	} else if (colon == 0) {
+		/* Some name like ":name" */
+		if (namespace != NULL)
+			return DOM_NAMESPACE_ERR;
 	} else {
 		/* Prefix */
 		struct dom_string *prefix;
+		struct dom_string *lname;
 		dom_exception err;
 
 		/* Ensure there is a namespace URI */
@@ -157,11 +173,21 @@
 			return DOM_NAMESPACE_ERR;
 		}
 
-		err = dom_string_substr(qname, 0, colon - 1, &prefix);
+		err = dom_string_substr(qname, 0, colon, &prefix);
 		if (err != DOM_NO_ERR) {
 			return err;
 		}
 
+		err = dom_string_substr(qname, colon + 1, len, &lname);
+		if (err != DOM_NO_ERR) {
+			return err;
+		}
+
+		if (_dom_validate_ncname(prefix) == false || 
+				_dom_validate_ncname(lname) == false) {
+			return DOM_NAMESPACE_ERR;
+		}
+
 		/* Test for invalid XML namespace */
 		if (dom_string_cmp(prefix, xml) == 0 &&
 				dom_string_cmp(namespace,
@@ -195,9 +221,9 @@
 /**
  * Split a QName into a namespace prefix and localname string
  *
- * \param qname      The qname to split
- * \param prefix     Pointer to location to receive prefix
- * \param localname  Pointer to location to receive localname
+ * \param qname		The qname to split
+ * \param prefix	Pointer to location to receive prefix
+ * \param localname	Pointer to location to receive localname
  * \return DOM_NO_ERR on success.
  *
  * If there is no prefix present in ::qname, then ::prefix will be NULL.
@@ -223,7 +249,7 @@
 		}
 	} else {
 		/* Found one => prefix */
-		err = dom_string_substr(qname, 0, colon - 1, prefix);
+		err = dom_string_substr(qname, 0, colon, prefix);
 		if (err != DOM_NO_ERR) {
 			return err;
 		}
@@ -240,3 +266,28 @@
 	return DOM_NO_ERR;
 }
 
+/**
+ * Get the XML prefix dom_string 
+ * 
+ * Note: The client of this function may or may not call the dom_string_ref
+ * on the returned dom_string, because this string will only be destroyed when
+ * the dom_finalise is called. But if the client call dom_string_ref, it must
+ * call dom_string_unref to maintain a correct ref count of the dom_string.
+ */
+dom_string *_dom_namespace_get_xml_prefix(void)
+{
+	return xml;
+}
+
+/**
+ * Get the XMLNS prefix dom_string.
+ * 
+ * Note: The client of this function may or may not call the dom_string_ref
+ * on the returned dom_string, because this string will only be destroyed when
+ * the dom_finalise is called. But if the client call dom_string_ref, it must
+ * call dom_string_unref to maintain a correct ref count of the dom_string.
+ */
+dom_string *_dom_namespace_get_xmlns_prefix(void)
+{
+	return xmlns;
+}
Index: src/core/comment.c
===================================================================
--- src/core/comment.c	(revision 9058)
+++ src/core/comment.c	(working copy)
@@ -3,19 +3,26 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
 #include "core/characterdata.h"
 #include "core/comment.h"
 #include "core/document.h"
 
+#include "utils/utils.h"
+
 /**
- * A DOM comment node
+ * A DOM Comment node
  */
 struct dom_comment {
 	struct dom_characterdata base;	/**< Base node */
 };
 
+static struct dom_node_protect_vtable comment_protect_vtable = {
+	DOM_COMMENT_PROTECT_VTABLE
+};
+
 /**
  * Create a comment node
  *
@@ -30,23 +37,27 @@
  *
  * The returned node will already be referenced.
  */
-dom_exception dom_comment_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_comment_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_comment **result)
 {
 	struct dom_comment *c;
 	dom_exception err;
 
 	/* Allocate the comment node */
-	c = dom_document_alloc(doc, NULL, sizeof(struct dom_comment));
+	c = _dom_document_alloc(doc, NULL, sizeof(struct dom_comment));
 	if (c == NULL)
 		return DOM_NO_MEM_ERR;
 
+	/* Set the virtual table */
+	((dom_node_internal *) c)->base.vtable = &characterdata_vtable;
+	((dom_node_internal *) c)->vtable = &comment_protect_vtable;
+
 	/* And initialise the node */
-	err = dom_characterdata_initialise(&c->base, doc, DOM_COMMENT_NODE,
+	err = _dom_characterdata_initialise(&c->base, doc, DOM_COMMENT_NODE,
 			name, value);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, c, 0);
+		_dom_document_alloc(doc, c, 0);
 		return err;
 	}
 
@@ -63,12 +74,56 @@
  *
  * The contents of ::comment will be destroyed and ::comment will be freed
  */
-void dom_comment_destroy(struct dom_document *doc,
+void _dom_comment_destroy(struct dom_document *doc,
 		struct dom_comment *comment)
 {
 	/* Finalise base class contents */
-	dom_characterdata_finalise(doc, &comment->base);
+	_dom_characterdata_finalise(doc, &comment->base);
 
 	/* Free node */
-	dom_document_alloc(doc, comment, 0);
+	_dom_document_alloc(doc, comment, 0);
 }
+
+
+/*-----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/**
+ * The destory function 
+ */
+void __dom_comment_destroy(struct dom_node_internal *node)
+{
+	struct dom_document *doc;
+	doc = dom_node_get_owner(node);
+
+	_dom_comment_destroy(doc, (struct dom_comment *) node);
+}
+
+/**
+ * The memory allocation function of this class
+ */
+dom_exception _dom_comment_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	dom_comment *c;
+	
+	c = _dom_document_alloc(doc, NULL, sizeof(struct dom_comment));
+	if (c == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) c;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_comment_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	return _dom_characterdata_copy(new, old);
+}
+
Index: src/core/string.c
===================================================================
--- src/core/string.c	(revision 9058)
+++ src/core/string.c	(working copy)
@@ -3,16 +3,17 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
+#include <assert.h>
 #include <ctype.h>
 #include <inttypes.h>
 #include <string.h>
 
 #include <parserutils/charset/utf8.h>
 
-#include <dom/core/string.h>
-
+#include "core/string.h"
 #include "core/document.h"
 #include "utils/utils.h"
 
@@ -26,6 +27,10 @@
 
 	size_t len;			/**< Byte length of string */
 
+	lwc_string *intern;		/**< The lwc_string of this string */
+
+	lwc_context *context;		/**< The lwc_context for the lwc_string */
+
 	dom_alloc alloc;		/**< Memory (de)allocation function */
 	void *pw;			/**< Client-specific data */
 
@@ -40,6 +45,8 @@
 	.refcnt = 1
 };
 
+
+
 /**
  * Claim a reference on a DOM string
  *
@@ -60,8 +67,15 @@
  */
 void dom_string_unref(struct dom_string *str)
 {
+	if (str == NULL)
+		return;
+	
 	if (--str->refcnt == 0) {
-		if (str->alloc != NULL) {
+		if (str->intern != NULL) {
+			lwc_context_unref(str->context);
+			lwc_context_string_unref(str->context, str->intern);
+			str->alloc(str, 0, str->pw);
+		} else if (str->alloc != NULL) {
 			str->alloc(str->ptr, 0, str->pw);
 			str->alloc(str, 0, str->pw);
 		}
@@ -89,7 +103,7 @@
 {
 	struct dom_string *ret;
 
-	if (ptr == NULL && len == 0) {
+	if (ptr == NULL || len == 0) {
 		dom_string_ref(&empty_string);
 
 		*str = &empty_string;
@@ -114,6 +128,9 @@
 	ret->alloc = alloc;
 	ret->pw = pw;
 
+	ret->intern = NULL;
+	ret->context = NULL;
+
 	ret->refcnt = 1;
 
 	*str = ret;
@@ -122,6 +139,148 @@
 }
 
 /**
+ * Clone a dom_string if necessary. This method is used to create a new string
+ * with a new allocator, but if the allocator is the same with the param str, 
+ * just ref the string.
+ *
+ * \param alloc     The new allocator for this string
+ * \param pw        The new pw for this string
+ * \param str       The source dom_string
+ * \param ret       The cloned dom_string
+ *
+ * @note: When both the alloc and pw are the same as the str's, we need no
+ *	  real clone, just ref the source string is ok.
+ */
+dom_exception dom_string_clone(dom_alloc alloc, void *pw, struct dom_string *str,
+		struct dom_string **ret)
+{
+	if (alloc == str->alloc && pw == str->pw) {
+		*ret = str;
+		dom_string_ref(str);
+		return DOM_NO_ERR;
+	}
+
+	if (str->intern != NULL) {
+		return _dom_string_create_from_lwcstring(alloc, pw, str->context,
+				str->intern, ret);
+	} else {
+		return dom_string_create(alloc, pw, str->ptr, str->len, ret);
+	}
+}
+
+/**
+ * Create a dom_string from a lwc_string
+ * 
+ * \param ctx	The lwc_context
+ * \param str	The lwc_string
+ * \param ret   The new dom_string
+ */
+dom_exception _dom_string_create_from_lwcstring(dom_alloc alloc, void *pw,
+		lwc_context *ctx, lwc_string *str, struct dom_string **ret)
+{
+	dom_string *r;
+
+	if (str == NULL) {
+		*ret = NULL;
+		return DOM_NO_ERR;
+	}
+
+	r = alloc(NULL, sizeof(struct dom_string), pw);
+	if (r == NULL)
+		return DOM_NO_MEM_ERR;
+
+	if (str == NULL) {
+		*ret = &empty_string;
+		dom_string_ref(*ret);
+		return DOM_NO_ERR;
+	}
+
+	r->context = ctx;
+	r->intern = str;
+	r->ptr = (uint8_t *)lwc_string_data(str);
+	r->len = lwc_string_length(str);
+
+	r->alloc = alloc;
+	r->pw = pw;
+
+	r->refcnt = 1;
+
+	/* Ref the lwc_string */
+	lwc_context_ref(ctx);
+	lwc_context_string_ref(ctx, str);
+
+	*ret = r;
+	return DOM_NO_ERR;
+
+}
+
+/**
+ * Make the dom_string be interned in the lwc_context
+ *
+ * \param str		The dom_string to be interned
+ * \param ctx		The lwc_context to intern this dom_string
+ * \param lwcstr	The result lwc_string	
+ */
+dom_exception _dom_string_intern(struct dom_string *str, 
+		struct lwc_context_s *ctx, struct lwc_string_s **lwcstr)
+{
+	lwc_string *ret;
+	lwc_error lerr;
+
+	/* If this string is interned with the same context, do nothing */
+	if (str->context != NULL && str->context == ctx) {
+		*lwcstr = str->intern;
+		return DOM_NO_ERR;
+	}
+
+	lerr = lwc_context_intern(ctx, (const char *)str->ptr, str->len, &ret);
+	if (lerr != lwc_error_ok) {
+		return _dom_exception_from_lwc_error(lerr);
+	}
+
+	if (str->context != NULL) {
+		lwc_context_unref(str->context);
+		lwc_context_string_unref(str->context, str->intern);
+		str->ptr = NULL;
+	}
+
+	str->context = ctx;
+	str->intern = ret;
+	lwc_context_ref(ctx);
+	lwc_context_string_ref(ctx, ret);
+
+	if (str->ptr != NULL) {
+		str->alloc(str->ptr, 0, str->pw);
+	}
+
+	str->ptr = (uint8_t *) lwc_string_data(ret);
+
+	*lwcstr = ret;
+	return DOM_NO_ERR;
+}
+
+/**
+ * Get the internal lwc_string 
+ *
+ * \param str		The dom_string object
+ * \param ctx		The lwc_context which intern this dom_string
+ * \param lwcstr	The lwc_string of this dom-string
+ */
+dom_exception dom_string_get_intern(struct dom_string *str, 
+		struct lwc_context_s **ctx, struct lwc_string_s **lwcstr)
+{
+	*ctx = str->context;
+	*lwcstr = str->intern;
+
+	if (*ctx != NULL)
+		lwc_context_ref(*ctx);
+	if (*lwcstr != NULL)
+		lwc_context_string_ref(*ctx, *lwcstr);
+
+	return DOM_NO_ERR;
+}
+
+/**
  * Case sensitively compare two DOM strings
  *
  * \param s1  The first string to compare
@@ -132,12 +291,26 @@
  */
 int dom_string_cmp(struct dom_string *s1, struct dom_string *s2)
 {
+	bool ret;
+
 	if (s1 == NULL)
 		s1 = &empty_string;
 
 	if (s2 == NULL)
 		s2 = &empty_string;
 
+	if (s1->context == s2->context && s1->context != NULL) {
+		assert(s1->intern != NULL);
+		assert(s2->intern != NULL);
+		lwc_context_string_isequal(s1->context, s1->intern, 
+				s2->intern, &ret);
+		if (ret == true) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+
 	if (s1->len != s2->len)
 		return 1;
 
@@ -164,6 +337,19 @@
 	if (s2 == NULL)
 		s2 = &empty_string;
 
+	bool ret;
+	if (s1->context == s2->context && s1->context != NULL) {
+		assert(s1->intern != NULL);
+		assert(s2->intern != NULL);
+		lwc_context_string_caseless_isequal(s1->context, s1->intern, 
+				s2->intern, &ret);
+		if (ret == true) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+
 	d1 = s1->ptr;
 	d2 = s2->ptr;
 	l1 = s1->len;
@@ -304,6 +490,55 @@
 	return clen;
 }
 
+/**
+ * Get the UCS4 character at position index
+ *
+ * \param index     The position of the charater
+ * \param ch        The UCS4 character
+ */
+dom_exception dom_string_at(struct dom_string *str, uint32_t index, 
+		uint32_t *ch)
+{
+	const uint8_t *s;
+	size_t clen, slen;
+	uint32_t c, i;
+	parserutils_error err;
+
+	if (str == NULL)
+		str = &empty_string;
+
+	s = str->ptr;
+	slen = str->len;
+
+	i = 0;
+
+	while (slen > 0) {
+		err = parserutils_charset_utf8_char_byte_length(s, &clen);
+		if (err != PARSERUTILS_OK) {
+			return (uint32_t) -1;
+		}
+
+		i++;
+		if (i == index + 1)
+			break;
+
+		s += clen;
+		slen -= clen;
+	}
+
+	if (i == index + 1) {
+		err = parserutils_charset_utf8_to_ucs4(s, slen, &c, &clen);
+		if (err != PARSERUTILS_OK) {
+			return (uint32_t) -1;
+		}
+
+		*ch = c;
+		return DOM_NO_ERR;
+	} else {
+		return DOM_DOMSTRING_SIZE_ERR;
+	}
+}
+
 /** 
  * Concatenate two dom strings 
  * 
@@ -322,16 +557,33 @@
 		struct dom_string **result)
 {
 	struct dom_string *concat;
+	dom_alloc alloc;
+	void *pw;
 
-	concat = s1->alloc(NULL, sizeof(struct dom_string), s1->pw);
+	assert(s1 != NULL);
+	assert(s2 != NULL);
 
+	if (s1->alloc != NULL) {
+		alloc = s1->alloc;
+		pw = s1->pw;
+	} else if (s2->alloc != NULL) {
+		alloc = s2->alloc;
+		pw = s2->pw;
+	} else {
+		/* s1 == s2 == empty_string */
+		*result = &empty_string;
+		return DOM_NO_ERR;
+	}
+
+	concat = alloc(NULL, sizeof(struct dom_string), pw);
+
 	if (concat == NULL) {
 		return DOM_NO_MEM_ERR;
 	}
 
-	concat->ptr = s1->alloc(NULL, s1->len + s2->len, s1->pw);
+	concat->ptr = alloc(NULL, s1->len + s2->len, pw);
 	if (concat->ptr == NULL) {
-		s1->alloc(concat, 0, s1->pw);
+		alloc(concat, 0, pw);
 
 		return DOM_NO_MEM_ERR;
 	}
@@ -342,8 +594,10 @@
 
 	concat->len = s1->len + s2->len;
 
-	concat->alloc = s1->alloc;
-	concat->pw = s1->pw;
+	concat->alloc = alloc;
+	concat->pw = pw;
+	concat->context = NULL;
+	concat->intern = NULL;
 
 	concat->refcnt = 1;
 
@@ -382,7 +636,7 @@
 
 	/* Calculate the byte index of the start */
 	while (i1 > 0) {
-		err = parserutils_charset_utf8_next(s, slen - b1, b1, &b1);
+		err = parserutils_charset_utf8_next(s, slen, b1, &b1);
 		if (err != PARSERUTILS_OK) {
 			return DOM_NO_MEM_ERR;
 		}
@@ -395,7 +649,7 @@
 
 	/* Calculate the byte index of the end */
 	while (i2 > 0) {
-		err = parserutils_charset_utf8_next(s, slen - b2, b2, &b2);
+		err = parserutils_charset_utf8_next(s, slen, b2, &b2);
 		if (err != PARSERUTILS_OK) {
 			return DOM_NO_MEM_ERR;
 		}
@@ -451,7 +705,7 @@
 		ins = tlen;
 	} else {
 		while (offset > 0) {
-			err = parserutils_charset_utf8_next(t, tlen - ins, 
+			err = parserutils_charset_utf8_next(t, tlen, 
 					ins, &ins);
 
 			if (err != PARSERUTILS_OK) {
@@ -492,6 +746,8 @@
 
 	res->alloc = target->alloc;
 	res->pw = target->pw;
+	res->intern = NULL;
+	res->context = NULL;
 	
 	res->refcnt = 1;
 
@@ -526,6 +782,9 @@
 	uint32_t b1, b2;
 	parserutils_error err;
 
+	if (source == NULL)
+		source = &empty_string;
+
 	t = target->ptr;
 	tlen = target->len;
 	s = source->ptr;
@@ -538,7 +797,7 @@
 
 	/* Calculate the byte index of the start */
 	while (i1 > 0) {
-		err = parserutils_charset_utf8_next(s, slen - b1, b1, &b1);
+		err = parserutils_charset_utf8_next(s, slen, b1, &b1);
 
 		if (err != PARSERUTILS_OK) {
 			return DOM_NO_MEM_ERR;
@@ -552,7 +811,7 @@
 
 	/* Calculate the byte index of the end */
 	while (i2 > 0) {
-		err = parserutils_charset_utf8_next(s, slen - b2, b2, &b2);
+		err = parserutils_charset_utf8_next(s, slen, b2, &b2);
 
 		if (err != PARSERUTILS_OK) {
 			return DOM_NO_MEM_ERR;
@@ -594,6 +853,8 @@
 
 	res->alloc = target->alloc;
 	res->pw = target->pw;
+	res->intern = NULL;
+	res->context = NULL;
 
 	res->refcnt = 1;
 
@@ -618,8 +879,12 @@
 dom_exception dom_string_dup(struct dom_string *str, 
 		struct dom_string **result)
 {
-	return dom_string_create(str->alloc, str->pw, str->ptr, str->len, 
-			result);
+	if (str->intern != NULL) {
+		return _dom_string_create_from_lwcstring(str->alloc, str->pw, str->context,
+				str->intern, result);
+	} else {
+		return dom_string_create(str->alloc, str->pw, str->ptr, str->len, result);
+	}
 }
 
 /**
@@ -645,3 +910,47 @@
 	return hash;
 }
 
+/**
+ * Convert a lwc_error to a dom_exception
+ * 
+ * \param err	The input lwc_error
+ * \return		The dom_exception
+ */
+dom_exception _dom_exception_from_lwc_error(lwc_error err)
+{
+	switch (err) {
+		case lwc_error_ok:
+			return DOM_NO_ERR;
+		case lwc_error_oom:
+			return DOM_NO_MEM_ERR;
+		case lwc_error_range:
+			return DOM_INDEX_SIZE_ERR;
+	}
+	assert ("Unknow lwc_error, can't convert to dom_exception");
+	/* Suppress compile errors */
+	return DOM_NO_ERR;
+}
+
+/**
+ * Compare the raw data of two lwc_strings for equality when the two string
+ * belong to different lwc_context 
+ * 
+ * \param s1	The first lwc_string
+ * \param s2 	The second lwc_string
+ * \return		Return 0 for equal, non-zero otherwise
+ */
+int _dom_lwc_string_compare_raw(struct lwc_string_s *s1, struct lwc_string_s *s2)
+{
+	const char *rs1, *rs2;
+	size_t len;
+
+	if (lwc_string_length(s1) != lwc_string_length(s2))
+		return -1;
+	
+	len = lwc_string_length(s1);
+	rs1 = lwc_string_data(s1);
+	rs2 = lwc_string_data(s2);
+
+	return memcmp(rs1, rs2, len);
+}
+
Index: src/core/comment.h
===================================================================
--- src/core/comment.h	(revision 9058)
+++ src/core/comment.h	(working copy)
@@ -9,16 +9,33 @@
 #define dom_internal_core_comment_h_
 
 #include <dom/core/exceptions.h>
+#include <dom/core/comment.h>
 
 struct dom_comment;
 struct dom_document;
 struct dom_string;
+struct lwc_string_s;
 
-dom_exception dom_comment_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_comment_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_comment **result);
 
-void dom_comment_destroy(struct dom_document *doc,
+#define  _dom_comment_initialise _dom_characterdata_initialise
+#define  _dom_comment_finalise _dom_characterdata_finalise
+
+void _dom_comment_destroy(struct dom_document *doc,
 		struct dom_comment *comment);
 
+/* Following comes the protected vtable  */
+void __dom_comment_destroy(struct dom_node_internal *node);
+dom_exception _dom_comment_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_comment_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_COMMENT_PROTECT_VTABLE \
+	__dom_comment_destroy, \
+	_dom_comment_alloc, \
+	_dom_comment_copy
+
 #endif
Index: src/core/nodelist.c
===================================================================
--- src/core/nodelist.c	(revision 9058)
+++ src/core/nodelist.c	(working copy)
@@ -3,12 +3,17 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
+#include <assert.h>
 
 #include <dom/core/node.h>
+#include <dom/core/document.h>
 #include <dom/core/nodelist.h>
 #include <dom/core/string.h>
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include "core/document.h"
 #include "core/node.h"
 #include "core/nodelist.h"
@@ -23,16 +28,18 @@
 
 	struct dom_node_internal *root;		/**< Root of applicable subtree */
 
-	enum { DOM_NODELIST_CHILDREN,
-	       DOM_NODELIST_BY_NAME,
-	       DOM_NODELIST_BY_NAMESPACE
-	} type;				/**< List type */
+	nodelist_type type;
 
 	union {
-		struct dom_string *name;	/**< Tag name to match */
 		struct {
-			struct dom_string *namespace;	/**< Namespace */
-			struct dom_string *localname;	/**< Localname */
+			struct lwc_string_s *name;	/**< Tag name to match */
+			bool any_name;			/**< The name is '*' */
+		} n;
+		struct {
+			bool any_namespace;	/**< The namespace is '*' */
+			bool any_localname;	/**< The localname is '*' */
+			struct lwc_string_s *namespace;	/**< Namespace */
+			struct lwc_string_s *localname;	/**< Localname */
 		} ns;			/**< Data for namespace matching */
 	} data;
 
@@ -43,6 +50,7 @@
  * Create a nodelist
  *
  * \param doc        Owning document
+ * \param type	     The type of the NodeList
  * \param root       Root node of subtree that list applies to
  * \param tagname    Name of nodes in list (or NULL)
  * \param namespace  Namespace part of nodes in list (or NULL)
@@ -52,27 +60,21 @@
  *
  * ::root must be a node owned by ::doc
  *
- * If ::tagname is non-NULL, ::namespace and ::localname must be NULL and
- * the created list will match nodes by name
- *
- * If ::namespace is non-NULL, ::localname must be non-NULL and
- * ::tagname must be NULL and the created list will match nodes by namespace
- * and localname
- *
- * If ::tagname, ::namespace and ::localname are NULL, the created list
- * will match the children of ::root.
- *
  * The returned list will already be referenced, so the client need not
  * do so explicitly. The client must unref the list once finished with it.
  */
-dom_exception dom_nodelist_create(struct dom_document *doc,
-		struct dom_node_internal *root, struct dom_string *tagname,
-		struct dom_string *namespace, struct dom_string *localname,
+dom_exception _dom_nodelist_create(struct dom_document *doc, nodelist_type type,
+		struct dom_node_internal *root, struct lwc_string_s *tagname,
+		struct lwc_string_s *namespace, struct lwc_string_s *localname,
 		struct dom_nodelist **list)
 {
 	struct dom_nodelist *l;
+	lwc_context *ctx;
 
-	l = dom_document_alloc(doc, NULL, sizeof(struct dom_nodelist));
+	ctx = _dom_document_get_intern_context(doc);
+	assert(ctx != NULL);
+
+	l = _dom_document_alloc(doc, NULL, sizeof(struct dom_nodelist));
 	if (l == NULL)
 		return DOM_NO_MEM_ERR;
 
@@ -82,20 +84,45 @@
 	dom_node_ref(root);
 	l->root = root;
 
-	if (tagname != NULL && namespace == NULL && localname == NULL) {
-		dom_string_ref(tagname);
-		l->type = DOM_NODELIST_BY_NAME;
-		l->data.name = tagname;
-	} else if (namespace != NULL && localname != NULL &&
-			tagname == NULL) {
-		dom_string_ref(namespace);
-		dom_string_ref(localname);
-		l->type = DOM_NODELIST_BY_NAMESPACE;
+	l->type = type;
+
+	if (type == DOM_NODELIST_BY_NAME) {
+		assert(tagname != NULL);
+		l->data.n.any_name = false;
+		if (lwc_string_length(tagname) == 1) {
+			const char *ch = lwc_string_data(tagname);
+			if (*ch == '*') {
+				l->data.n.any_name = true;
+			}
+		}
+	
+		lwc_context_string_ref(ctx, tagname);
+		l->data.n.name = tagname;
+	} else if (type == DOM_NODELIST_BY_NAMESPACE) {
+		l->data.ns.any_localname = false;
+		l->data.ns.any_namespace = false;
+		if (localname != NULL) {
+			if (lwc_string_length(localname) == 1) {
+				const char *ch = lwc_string_data(localname);
+				if (*ch == '*') {
+				   l->data.ns.any_localname = true;
+				}
+			}
+			lwc_context_string_ref(ctx, localname);
+		}
+		if (namespace != NULL) {
+			if (lwc_string_length(namespace) == 1) {
+				const char *ch = lwc_string_data(namespace);
+				if (*ch == '*') {
+					l->data.ns.any_namespace = true;
+				}
+			}
+			lwc_context_string_ref(ctx, namespace);
+		}
+
 		l->data.ns.namespace = namespace;
 		l->data.ns.localname = localname;
-	} else {
-		l->type = DOM_NODELIST_CHILDREN;
-	}
+	} 
 
 	l->refcnt = 1;
 
@@ -111,6 +138,7 @@
  */
 void dom_nodelist_ref(struct dom_nodelist *list)
 {
+	assert(list != NULL);
 	list->refcnt++;
 }
 
@@ -124,30 +152,39 @@
  */
 void dom_nodelist_unref(struct dom_nodelist *list)
 {
+	if (list == NULL)
+		return;
+
 	if (--list->refcnt == 0) {
 		struct dom_node_internal *owner = 
 				(struct dom_node_internal *) list->owner;
+		lwc_context *ctx;
+		ctx = _dom_document_get_intern_context((dom_document *) owner);
+		assert(ctx != NULL);
 
 		switch (list->type) {
 		case DOM_NODELIST_CHILDREN:
 			/* Nothing to do */
 			break;
 		case DOM_NODELIST_BY_NAMESPACE:
-			dom_string_unref(list->data.ns.namespace);
-			dom_string_unref(list->data.ns.localname);
+			if (list->data.ns.namespace != NULL)
+				lwc_context_string_unref(ctx, list->data.ns.namespace);
+			if (list->data.ns.localname != NULL)
+				lwc_context_string_unref(ctx, list->data.ns.localname);
 			break;
 		case DOM_NODELIST_BY_NAME:
-			dom_string_unref(list->data.name);
+			assert(list->data.n.name != NULL);
+			lwc_context_string_unref(ctx, list->data.n.name);
 			break;
 		}
 
 		dom_node_unref(list->root);
 
 		/* Remove list from document */
-		dom_document_remove_nodelist(list->owner, list);
+		_dom_document_remove_nodelist(list->owner, list);
 
 		/* Destroy the list object */
-		dom_document_alloc(list->owner, list, 0);
+		_dom_document_alloc(list->owner, list, 0);
 
 		/* And release our reference on the owning document
 		 * This must be last as, otherwise, it's possible that
@@ -175,19 +212,22 @@
 		if (list->type == DOM_NODELIST_CHILDREN) {
 			len++;
 		} else if (list->type == DOM_NODELIST_BY_NAME) {
-			if (cur->name != NULL && 
-					dom_string_cmp(cur->name, 
-						list->data.name) == 0) {
-				len++;
+			/* Here, we compare two lwc_string pointer directly */
+			if (list->data.n.any_name == true || (
+					cur->name != NULL && 
+					cur->name == list->data.n.name)) {
+				if (cur->type == DOM_ELEMENT_NODE)
+					len++;
 			}
 		} else {
-			if (cur->namespace != NULL &&
-					dom_string_cmp(cur->namespace, 
-					list->data.ns.namespace) == 0 && 
-				cur->name != NULL &&
-				dom_string_cmp(cur->name, 
-					list->data.ns.localname) == 0) {
-				len++;
+			if (list->data.ns.any_namespace == true || 
+					cur->namespace == list->data.ns.namespace) {
+				if (list->data.ns.any_localname == true ||
+						(cur->name != NULL &&
+						cur->name == list->data.ns.localname)) {
+					if (cur->type == DOM_ELEMENT_NODE)
+						len++;
+				}
 			}
 		}
 
@@ -250,19 +290,22 @@
 		if (list->type == DOM_NODELIST_CHILDREN) {
 			count++;
 		} else if (list->type == DOM_NODELIST_BY_NAME) {
-			if (cur->name != NULL &&
-					dom_string_cmp(cur->name, 
-						list->data.name) == 0) {
-				count++;
+			if (list->data.n.any_name == true || (
+					cur->name != NULL && 
+					cur->name == list->data.n.name)) {
+				if (cur->type == DOM_ELEMENT_NODE)
+					count++;
 			}
 		} else {
-			if (cur->namespace != NULL &&
-					dom_string_cmp(cur->namespace, 
-					list->data.ns.namespace) == 0 && 
-				cur->name != NULL &&
-				dom_string_cmp(cur->name, 
-					list->data.ns.localname) == 0) {
-				count++;
+			if (list->data.ns.any_namespace == true || 
+					(cur->namespace != NULL &&
+					cur->namespace == list->data.ns.namespace)) {
+				if (list->data.ns.any_localname == true ||
+						(cur->name != NULL &&
+						cur->name == list->data.ns.localname)) {
+					if (cur->type == DOM_ELEMENT_NODE)
+						count++;
+				}
 			}
 		}
 
@@ -311,36 +354,44 @@
  * Match a nodelist instance against a set of nodelist creation parameters
  *
  * \param list       List to match
+ * \param type	     The type of the NodeList
  * \param root       Root node of subtree that list applies to
  * \param tagname    Name of nodes in list (or NULL)
  * \param namespace  Namespace part of nodes in list (or NULL)
  * \param localname  Local part of nodes in list (or NULL)
  * \return true if list matches, false otherwise
  */
-bool dom_nodelist_match(struct dom_nodelist *list, 
-		struct dom_node_internal *root, struct dom_string *tagname, 
-		struct dom_string *namespace, struct dom_string *localname)
+bool _dom_nodelist_match(struct dom_nodelist *list, nodelist_type type,
+		struct dom_node_internal *root, struct lwc_string_s *tagname, 
+		struct lwc_string_s *namespace, struct lwc_string_s *localname)
 {
 	if (list->root != root)
 		return false;
 
-	if (list->type == DOM_NODELIST_CHILDREN && tagname == NULL &&
-			namespace == NULL && localname == NULL) {
+	if (list->type != type)
+		return false;
+
+	if (list->type == DOM_NODELIST_CHILDREN) {
 		return true;
 	}
 
-	if (list->type == DOM_NODELIST_BY_NAME && tagname != NULL &&
-			namespace == NULL && localname == NULL) {
-		return (dom_string_cmp(list->data.name, tagname) == 0);
+	if (list->type == DOM_NODELIST_BY_NAME) {
+		return (list->data.n.name == tagname);
 	}
 
-	if (list->type == DOM_NODELIST_BY_NAMESPACE && tagname == NULL &&
-			namespace != NULL && localname != NULL) {
-		return (dom_string_cmp(list->data.ns.namespace,
-				namespace) == 0) &&
-			(dom_string_cmp(list->data.ns.localname,
-				localname) == 0);
+	if (list->type == DOM_NODELIST_BY_NAMESPACE) {
+		return (list->data.ns.namespace == namespace) &&
+			(list->data.ns.localname == localname);
 	}
 
 	return false;
 }
+
+/* 
+ * Test whether the two NodeList are equal 
+ */
+bool _dom_nodelist_equal(struct dom_nodelist *l1, struct dom_nodelist *l2)
+{
+	return _dom_nodelist_match(l1, l1->type, l2->root, l2->data.n.name, 
+			l2->data.ns.namespace, l2->data.ns.localname);
+}
Index: src/core/text.c
===================================================================
--- src/core/text.c	(revision 9058)
+++ src/core/text.c	(working copy)
@@ -3,18 +3,22 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
+#include <assert.h>
 
 #include <dom/core/string.h>
 #include <dom/core/text.h>
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include "core/characterdata.h"
 #include "core/document.h"
 #include "core/text.h"
 #include "utils/utils.h"
 
 /* The virtual table for dom_text */
-static struct dom_text_vtable text_vtable = {
+struct dom_text_vtable text_vtable = {
 	{
 		{
 			DOM_NODE_VTABLE
@@ -24,16 +28,31 @@
 	DOM_TEXT_VTABLE
 };
 
-/* The destroy virtual function */
-void _dom_text_destroy(struct dom_node_internal *node);
-void _dom_text_destroy(struct dom_node_internal *node)
-{
-	struct dom_document *doc;
-	dom_node_get_owner_document(node, &doc);
+static struct dom_node_protect_vtable text_protect_vtable = {
+	DOM_TEXT_PROTECT_VTABLE
+};
 
-	dom_text_destroy(doc, (struct dom_text *) node);
-}
+/* Following comes helper functions */
+typedef enum walk_operation {
+	COLLECT,
+	DELETE
+} walk_operation;
+typedef enum walk_order {
+	LEFT,
+	RIGHT
+} walk_order;
 
+/* Walk the logic-adjacent text in document order */
+static dom_exception walk_logic_adjacent_text_in_order(
+		dom_node_internal *node, walk_operation opt,
+		walk_order order, dom_string **ret, bool *cont);
+/* Walk the logic-adjacent text */
+static dom_exception walk_logic_adjacent_text(dom_text *text, 
+		walk_operation opt, dom_string **ret);
+	
+/*----------------------------------------------------------------------*/
+/* Constructor and Destructor */
+
 /**
  * Create a text node
  *
@@ -48,25 +67,29 @@
  *
  * The returned node will already be referenced.
  */
-dom_exception dom_text_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_text_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_text **result)
 {
 	struct dom_text *t;
 	dom_exception err;
 
 	/* Allocate the text node */
-	t = dom_document_alloc(doc, NULL, sizeof(struct dom_text));
+	t = _dom_document_alloc(doc, NULL, sizeof(struct dom_text));
 	if (t == NULL)
 		return DOM_NO_MEM_ERR;
 
 	/* And initialise the node */
-	err = dom_text_initialise(t, doc, DOM_TEXT_NODE, name, value);
+	err = _dom_text_initialise(t, doc, DOM_TEXT_NODE, name, value);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, t, 0);
+		_dom_document_alloc(doc, t, 0);
 		return err;
 	}
 
+	/* Compose the vtable */
+	((struct dom_node *) t)->vtable = &text_vtable;
+	((struct dom_node_internal *) t)->vtable = &text_protect_vtable;
+
 	*result = t;
 
 	return DOM_NO_ERR;
@@ -80,13 +103,13 @@
  *
  * The contents of ::text will be destroyed and ::text will be freed.
  */
-void dom_text_destroy(struct dom_document *doc, struct dom_text *text)
+void _dom_text_destroy(struct dom_document *doc, struct dom_text *text)
 {
 	/* Finalise node */
-	dom_text_finalise(doc, text);
+	_dom_text_finalise(doc, text);
 
 	/* Free node */
-	dom_document_alloc(doc, text, 0);
+	_dom_document_alloc(doc, text, 0);
 }
 
 /**
@@ -101,22 +124,18 @@
  *
  * ::doc, ::name and ::value will have their reference counts increased.
  */
-dom_exception dom_text_initialise(struct dom_text *text,
+dom_exception _dom_text_initialise(struct dom_text *text,
 		struct dom_document *doc, dom_node_type type,
-		struct dom_string *name, struct dom_string *value)
+		struct lwc_string_s *name, struct dom_string *value)
 {
 	dom_exception err;
 
 	/* Initialise the base class */
-	err = dom_characterdata_initialise(&text->base, doc, type,
+	err = _dom_characterdata_initialise(&text->base, doc, type,
 			name, value);
 	if (err != DOM_NO_ERR)
 		return err;
 
-	/* Compose the vtable */
-	((struct dom_node *) text)->vtable = &text_vtable;
-	text->base.base.destroy = &_dom_text_destroy;
-
 	/* Perform our type-specific initialisation */
 	text->element_content_whitespace = false;
 
@@ -131,11 +150,14 @@
  *
  * The contents of ::text will be cleaned up. ::text will not be freed.
  */
-void dom_text_finalise(struct dom_document *doc, struct dom_text *text)
+void _dom_text_finalise(struct dom_document *doc, struct dom_text *text)
 {
-	dom_characterdata_finalise(doc, &text->base);
+	_dom_characterdata_finalise(doc, &text->base);
 }
 
+/*----------------------------------------------------------------------*/
+/* The public virtual functions */
+
 /**
  * Split a text node at a given character offset
  *
@@ -181,7 +203,7 @@
 	}
 
 	/* Create new node */
-	err = dom_text_create(t->owner, t->name, value, &res);
+	err = _dom_text_create(t->owner, t->name, value, &res);
 	if (err != DOM_NO_ERR) {
 		dom_string_unref(value);
 		return err;
@@ -227,10 +249,7 @@
 dom_exception _dom_text_get_whole_text(struct dom_text *text,
 		struct dom_string **result)
 {
-	UNUSED(text);
-	UNUSED(result);
-
-	return DOM_NOT_SUPPORTED_ERR;
+	return walk_logic_adjacent_text(text, COLLECT, result);
 }
 
 /**
@@ -249,10 +268,239 @@
 dom_exception _dom_text_replace_whole_text(struct dom_text *text,
 		struct dom_string *content, struct dom_text **result)
 {
-	UNUSED(text);
-	UNUSED(content);
-	UNUSED(result);
+	dom_exception err;
+	dom_string *ret;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	err = walk_logic_adjacent_text(text, DELETE, &ret);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_characterdata_set_data(text, content);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	*result = text;
+	dom_node_ref(text);
+
+	return DOM_NO_ERR;
 }
 
+/*-----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/**
+ * The destory function of this class
+ */
+void __dom_text_destroy(struct dom_node_internal *node)
+{
+	struct dom_document *doc;
+	doc = dom_node_get_owner(node);
+
+	_dom_text_destroy(doc, (struct dom_text *) node);
+}
+
+/**
+ * The memory allocator for this class
+ */
+dom_exception _dom_text_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	dom_text *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_text));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_text_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	dom_text *ot = (dom_text *) old;
+	dom_text *nt = (dom_text *) new;
+
+	nt->element_content_whitespace = ot->element_content_whitespace;
+
+	return _dom_characterdata_copy(new, old);
+}
+
+/*----------------------------------------------------------------------*/
+/* Helper functions */
+
+/**
+ * Walk the logic adjacent text in certain order
+ *
+ * \param node	The start Text node
+ * \param opt	The operation on each Text Node
+ * \param order	The order
+ * \param ret	The string of the logic adjacent text 
+ * \param cont	Whether the logic adjacent text is interrupt here
+ */
+dom_exception walk_logic_adjacent_text_in_order(
+		dom_node_internal *node, walk_operation opt,
+		walk_order order, dom_string **ret, bool *cont)
+{
+	dom_exception err;
+	dom_string *data, *tmp;
+	dom_node_internal *parent = dom_node_get_parent(node);
+
+	/* If we reach the leaf of the DOM tree, just return to continue
+	 * to next sibling of our parent */
+	if (node == NULL) {
+		*cont = true;
+		return DOM_NO_ERR;
+	}
+
+	while (node != NULL) {
+		/* If we reach the boundary of logical-adjacent text, we stop */
+		if (node->type == DOM_ELEMENT_NODE || node->type == DOM_COMMENT_NODE 
+				|| node->type == DOM_PROCESSING_INSTRUCTION_NODE) {
+			*cont = false;
+			return DOM_NO_ERR;
+		}
+
+		if (node->type == DOM_TEXT_NODE) {
+			/* According the DOM spec, text node never have child */
+			assert(node->first_child == NULL);
+			assert(node->last_child == NULL);
+			if (opt == COLLECT) {
+				err = dom_characterdata_get_data(node, &data);
+				if (err == DOM_NO_ERR)
+					return err;
+
+				tmp = *ret;
+				if (order == LEFT) {
+					err = dom_string_concat(data, tmp, ret);
+					if (err == DOM_NO_ERR)
+						return err;
+				} else if (order == RIGHT) {
+					err = dom_string_concat(tmp, data, ret);
+					if (err == DOM_NO_ERR)
+						return err;
+				}
+
+				dom_string_unref(tmp);
+				dom_string_unref(data);
+
+				*cont = true;
+				return DOM_NO_ERR;
+			}
+
+			if (opt == DELETE) {
+				dom_node_internal *tn;
+				err = dom_node_remove_child(node->parent, node, (void *) &tn);
+				if (err != DOM_NO_ERR)
+					return err;
+
+				*cont = true;
+				dom_node_unref(tn);
+				return DOM_NO_ERR;
+			}
+		}
+
+		dom_node_internal *p = dom_node_get_parent(node);
+		if (order == LEFT) {
+			if (node->last_child != NULL) {
+				node = node->last_child;
+			} else if (node->previous != NULL) {
+				node = node->previous;
+			} else {
+				while (p != parent && node == p->last_child) {
+					node = p;
+					p = dom_node_get_parent(p);
+				}
+
+				node = node->previous;
+			}
+		} else {
+			if (node->first_child != NULL) {
+				node = node->first_child;
+			} else if (node->next != NULL) {
+				node = node->next;
+			} else {
+				while (p != parent && node == p->first_child) {
+					node = p;
+					p = dom_node_get_parent(p);
+				}
+
+				node = node->next;
+			}
+		}
+	}
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Traverse the logic adjacent text.
+ *
+ * \param text	The Text Node from which we start traversal
+ * \param opt	The operation code
+ * \param ret	The returned string if the opt is COLLECT
+ */
+dom_exception walk_logic_adjacent_text(dom_text *text, 
+		walk_operation opt, dom_string **ret)
+{
+	dom_node_internal *node = (dom_node_internal *) text;
+	dom_node_internal *parent = node->parent;
+	dom_node_internal *left = node->previous;
+	dom_node_internal *right = node->next;
+	dom_exception err;
+	bool cont;
+	
+	if (parent->type == DOM_ENTITY_NODE) {
+		return DOM_NOT_SUPPORTED_ERR;
+	}
+
+	/* Firstly, we look our left */
+	err = walk_logic_adjacent_text_in_order(left, opt, LEFT, ret, &cont);
+	if (err != DOM_NO_ERR) {
+		dom_string_unref(*ret);
+		*ret = NULL;
+		return err;
+	}
+
+	/* Ourself */
+	if (opt == COLLECT) {
+		dom_string *data = NULL, *tmp = NULL;
+		err = dom_characterdata_get_data(text, &data);
+		if (err == DOM_NO_ERR) {
+			dom_string_unref(*ret);
+			return err;
+		}
+
+		err = dom_string_concat(*ret, data, &tmp);
+		if (err == DOM_NO_ERR) {
+			dom_string_unref(*ret);
+			return err;
+		}
+
+		dom_string_unref(*ret);
+		dom_string_unref(data);
+		*ret = tmp;
+	} else {
+			dom_node_internal *tn;
+			err = dom_node_remove_child(node->parent, node, (void *) &tn);
+			if (err != DOM_NO_ERR)
+				return err;
+			dom_node_unref(tn);
+	}
+
+	/* Now, look right */
+	err = walk_logic_adjacent_text_in_order(right, opt, RIGHT, ret, &cont);
+	if (err != DOM_NO_ERR) {
+		dom_string_unref(*ret);
+		*ret = NULL;
+		return err;
+	}
+
+	return DOM_NO_ERR;
+}
Index: src/core/nodelist.h
===================================================================
--- src/core/nodelist.h	(revision 9058)
+++ src/core/nodelist.h	(working copy)
@@ -16,16 +16,27 @@
 struct dom_node;
 struct dom_nodelist;
 struct dom_string;
+struct lwc_string_s;
 
+typedef enum { 
+	DOM_NODELIST_CHILDREN,
+	DOM_NODELIST_BY_NAME,
+	DOM_NODELIST_BY_NAMESPACE
+} nodelist_type;
+
 /* Create a nodelist */
-dom_exception dom_nodelist_create(struct dom_document *doc,
-		struct dom_node_internal *root, struct dom_string *tagname,
-		struct dom_string *namespace, struct dom_string *localname,
+dom_exception _dom_nodelist_create(struct dom_document *doc, nodelist_type type,
+		struct dom_node_internal *root, struct lwc_string_s *tagname,
+		struct lwc_string_s *namespace, struct lwc_string_s *localname,
 		struct dom_nodelist **list);
 
 /* Match a nodelist instance against a set of nodelist creation parameters */
-bool dom_nodelist_match(struct dom_nodelist *list, 
-		struct dom_node_internal *root, struct dom_string *tagname, 
-		struct dom_string *namespace, struct dom_string *localname);
+bool _dom_nodelist_match(struct dom_nodelist *list, nodelist_type type,
+		struct dom_node_internal *root, struct lwc_string_s *tagname, 
+		struct lwc_string_s *namespace, struct lwc_string_s *localname);
 
+bool _dom_nodelist_equal(struct dom_nodelist *l1, struct dom_nodelist *l2);
+#define dom_nodelist_equal(l1, l2) _dom_nodelist_equal( \
+		(struct dom_nodelist *) (l1), (struct dom_nodelist *) (l2))
+
 #endif
Index: src/core/characterdata.c
===================================================================
--- src/core/characterdata.c	(revision 9058)
+++ src/core/characterdata.c	(working copy)
@@ -3,8 +3,11 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
+#include <assert.h>
+
 #include <dom/core/characterdata.h>
 #include <dom/core/string.h>
 
@@ -13,8 +16,9 @@
 #include "core/node.h"
 #include "utils/utils.h"
 
-/* The virtual functions for dom_characterdata */
-static struct dom_characterdata_vtable characterdata_vtable = {
+/* The virtual functions for dom_characterdata, we make this vtable
+ * public to each child class */
+struct dom_characterdata_vtable characterdata_vtable = {
 	{
 		DOM_NODE_VTABLE
 	},
@@ -26,15 +30,17 @@
  *
  * Return 	The new constructed DOM characterdata node of NULL if fail
  */
-dom_characterdata *dom_characterdata_create(struct dom_document *doc)
+dom_characterdata *_dom_characterdata_create(struct dom_document *doc)
 {
-	dom_characterdata *cdata = dom_document_alloc(doc, NULL,
+	dom_characterdata *cdata = _dom_document_alloc(doc, NULL,
 			sizeof(struct dom_characterdata));
 
 	if (cdata == NULL)
 		return NULL;
 
 	cdata->base.base.vtable = &characterdata_vtable;
+	cdata->base.vtable = NULL;
+
 	return cdata;
 }
 
@@ -50,11 +56,11 @@
  *
  * ::doc, ::name and ::value will have their reference counts increased.
  */
-dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata,
+dom_exception _dom_characterdata_initialise(struct dom_characterdata *cdata,
 		struct dom_document *doc, dom_node_type type,
-		struct dom_string *name, struct dom_string *value)
+		lwc_string *name, struct dom_string *value)
 {
-	return dom_node_initialise(&cdata->base, doc, type, 
+	return _dom_node_initialise(&cdata->base, doc, type, 
 			name, value, NULL, NULL);
 }
 
@@ -66,12 +72,17 @@
  *
  * The contents of ::cdata will be cleaned up. ::cdata will not be freed.
  */
-void dom_characterdata_finalise(struct dom_document *doc,
+void _dom_characterdata_finalise(struct dom_document *doc,
 		struct dom_characterdata *cdata)
 {
-	dom_node_finalise(doc, &cdata->base);
+	_dom_node_finalise(doc, &cdata->base);
 }
 
+
+/*----------------------------------------------------------------------*/
+
+/* The public virtual functions */
+
 /**
  * Retrieve data from a character data node
  *
@@ -182,7 +193,7 @@
 		len = 0;
 	}
 
-	if (offset >= len) {
+	if (offset > len) {
 		return DOM_INDEX_SIZE_ERR;
 	}
 
@@ -210,9 +221,7 @@
 		return DOM_NO_MODIFICATION_ALLOWED_ERR;
 	}
 
-	err = dom_string_insert(c->value, data, 
-			c->value != NULL ? dom_string_length(c->value) : 0,
-			&temp);
+	err = dom_string_concat(c->value, data, &temp);
 	if (err != DOM_NO_ERR) {
 		return err;
 	}
@@ -255,7 +264,7 @@
 		len = 0;
 	}
 
-	if (offset >= len) {
+	if (offset > len) {
 		return DOM_INDEX_SIZE_ERR;
 	}
 
@@ -302,7 +311,7 @@
 		len = 0;
 	}
 
-	if (offset >= len) {
+	if (offset > len) {
 		return DOM_INDEX_SIZE_ERR;
 	}
 
@@ -353,7 +362,7 @@
 		len = 0;
 	}
 
-	if (offset >= len) {
+	if (offset > len) {
 		return DOM_INDEX_SIZE_ERR;
 	}
 
@@ -373,3 +382,42 @@
 	return DOM_NO_ERR;
 }
 
+
+
+/*----------------------------------------------------------------------*/
+
+/* The protected virtual functions of Node, see core/node.h for details 
+ *
+ * @note: the three following API never be called directly from the virtual
+ *	  functions dispatch mechanism, they are here for the code consistent.
+ */
+void _dom_characterdata_destroy(struct dom_node_internal *node)
+{
+	assert("Should never be here" == NULL);
+	UNUSED(node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_characterdata_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	assert("Should never be here" == NULL);
+	UNUSED(doc);
+	UNUSED(n);
+	UNUSED(ret);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ * The sub-class of characterdata should call this API
+ */
+dom_exception _dom_characterdata_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	return _dom_node_copy(new, old);
+}
+
Index: src/core/doc_fragment.c
===================================================================
--- src/core/doc_fragment.c	(revision 9058)
+++ src/core/doc_fragment.c	(working copy)
@@ -3,13 +3,17 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include <dom/core/node.h>
 
 #include "core/document.h"
 #include "core/doc_fragment.h"
 #include "core/node.h"
+#include "utils/utils.h"
 
 /**
  * A DOM document fragment
@@ -18,8 +22,14 @@
 	struct dom_node_internal base;		/**< Base node */
 };
 
-void _dom_document_fragment_destroy(struct dom_node_internal *node);
+static struct dom_node_vtable df_vtable = {
+	DOM_NODE_VTABLE
+};
 
+static struct dom_node_protect_vtable df_protect_vtable = {
+	DOM_DF_PROTECT_VTABLE
+};
+
 /**
  * Create a document fragment
  *
@@ -34,30 +44,31 @@
  *
  * The returned node will already be referenced.
  */
-dom_exception dom_document_fragment_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_document_fragment_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_document_fragment **result)
 {
 	struct dom_document_fragment *f;
 	dom_exception err;
 
 	/* Allocate the comment node */
-	f = dom_document_alloc(doc, NULL,
+	f = _dom_document_alloc(doc, NULL,
 			sizeof(struct dom_document_fragment));
 	if (f == NULL)
 		return DOM_NO_MEM_ERR;
 
+
+	f->base.base.vtable = &df_vtable;
+	f->base.vtable = &df_protect_vtable;
+
 	/* And initialise the node */
-	err = dom_node_initialise(&f->base, doc, DOM_DOCUMENT_FRAGMENT_NODE,
-			name, value, NULL, NULL);
+	err = _dom_document_fragment_initialise(&f->base, doc, 
+			DOM_DOCUMENT_FRAGMENT_NODE, name, value, NULL, NULL);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, f, 0);
+		_dom_document_alloc(doc, f, 0);
 		return err;
 	}
 
-	/* Set the virtual function of destroy */
-	f->base.destroy = &_dom_document_fragment_destroy;
-
 	*result = f;
 
 	return DOM_NO_ERR;
@@ -71,45 +82,53 @@
  *
  * The contents of ::frag will be destroyed and ::frag will be freed.
  */
-void dom_document_fragment_destroy(struct dom_document *doc,
+void _dom_document_fragment_destroy(struct dom_document *doc,
 		struct dom_document_fragment *frag)
 {
-	struct dom_node_internal *c, *d;
+	/* Finalise base class */
+	_dom_document_fragment_finalise(doc, &frag->base);
 
-	/* Destroy children of this node */
-	for (c = frag->base.first_child; c != NULL; c = d) {
-		d = c->next;
+	/* Destroy fragment */
+	_dom_document_alloc(doc, frag, 0);
+}
 
-		/* Detach child */
-		c->parent = NULL;
+/*-----------------------------------------------------------------------*/
 
-		if (c->refcnt > 0) {
-			/* Something is using this child */
+/* Overload protected functions */
 
-			/** \todo add to list of nodes pending deletion */
+/**
+ * The virtual destroy function of this class
+ */
+void _dom_df_destroy(struct dom_node_internal *node)
+{
+	_dom_document_fragment_destroy(node->owner,
+			(struct dom_document_fragment *) node);
+}
 
-			continue;
-		}
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_df_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	struct dom_document_fragment *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_document_fragment));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
 
-		/* Detach from sibling list */
-		c->previous = NULL;
-		c->next = NULL;
-
-		dom_node_destroy(c);
-	}
-
-	/* Finalise base class */
-	dom_node_finalise(doc, &frag->base);
-
-	/* Destroy fragment */
-	dom_document_alloc(doc, frag, 0);
+	return DOM_NO_ERR;
 }
 
-void _dom_document_fragment_destroy(struct dom_node_internal *node)
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_df_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
 {
-	struct dom_document *doc;
-	dom_node_get_owner_document(node, &doc);
-
-	dom_document_fragment_destroy(doc, 
-			(struct dom_document_fragment *) node);
+	return _dom_node_copy(new, old);
 }
Index: src/core/text.h
===================================================================
--- src/core/text.h	(revision 9058)
+++ src/core/text.h	(working copy)
@@ -16,6 +16,8 @@
 
 struct dom_document;
 struct dom_string;
+struct lwc_context_s;
+struct lwc_string_s;
 
 /**
  * A DOM text node
@@ -27,6 +29,20 @@
 						 * content whitespace */
 };
 
+/* Constructor and Destructor */
+dom_exception _dom_text_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
+		struct dom_text **result);
+
+void _dom_text_destroy(struct dom_document *doc, struct dom_text *text);
+
+dom_exception _dom_text_initialise(struct dom_text *text,
+		struct dom_document *doc, dom_node_type type,
+		struct lwc_string_s *name, struct dom_string *value);
+
+void _dom_text_finalise(struct dom_document *doc, struct dom_text *text);
+
+
 /* Vitual functions for dom_text */
 dom_exception _dom_text_split_text(struct dom_text *text,
 		unsigned long offset, struct dom_text **result);
@@ -37,22 +53,26 @@
 dom_exception _dom_text_replace_whole_text(struct dom_text *text,
 		struct dom_string *content, struct dom_text **result);
 
-dom_exception dom_text_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
-		struct dom_text **result);
-
-void dom_text_destroy(struct dom_document *doc, struct dom_text *text);
-
-dom_exception dom_text_initialise(struct dom_text *text,
-		struct dom_document *doc, dom_node_type type,
-		struct dom_string *name, struct dom_string *value);
-
-void dom_text_finalise(struct dom_document *doc, struct dom_text *text);
-
 #define DOM_TEXT_VTABLE \
 	_dom_text_split_text, \
 	_dom_text_get_is_element_content_whitespace, \
 	_dom_text_get_whole_text, \
 	_dom_text_replace_whole_text
 
+
+/* Following comes the protected vtable  */
+void __dom_text_destroy(struct dom_node_internal *node);
+dom_exception _dom_text_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_text_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_TEXT_PROTECT_VTABLE \
+	__dom_text_destroy, \
+	_dom_text_alloc, \
+	_dom_text_copy
+
+
+extern struct dom_text_vtable text_vtable;
+
 #endif
Index: src/core/element.c
===================================================================
--- src/core/element.c	(revision 9058)
+++ src/core/element.c	(working copy)
@@ -3,31 +3,123 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
 #include <stdio.h>
+#include <string.h>
+#include <assert.h>
 
+#include <dom/dom.h>
 #include <dom/core/attr.h>
 #include <dom/core/element.h>
 #include <dom/core/node.h>
 #include <dom/core/string.h>
+#include <dom/core/document.h>
 
 #include "core/attr.h"
 #include "core/document.h"
 #include "core/element.h"
 #include "core/node.h"
+#include "core/namednodemap.h"
+#include "utils/validate.h"
 #include "utils/namespace.h"
 #include "utils/utils.h"
+#include "utils/hashtable.h"
 
+/**
+ * The two numbers are just random ones, maybe we should change it after some
+ * more consideration 
+ */
+#define CHAINS_ATTRIBUTES 31
+#define CHAINS_NAMESPACE  7
+#define CHAINS_NS_ATTRIBUTES 31
+
 static struct dom_element_vtable element_vtable = {
 	{
-		DOM_NODE_VTABLE
+		DOM_NODE_VTABLE_ELEMENT
 	},
 	DOM_ELEMENT_VTABLE
 };
 
+static struct dom_node_protect_vtable element_protect_vtable = {
+	DOM_ELEMENT_PROTECT_VTABLE
+};
+
+static dom_exception _dom_element_get_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, 
+		struct dom_string **value);
+static dom_exception _dom_element_set_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, 
+		struct dom_string *value);
+static dom_exception _dom_element_remove_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name);
+static dom_exception _dom_element_get_attr_node(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, 
+		struct dom_attr **result);
+static dom_exception _dom_element_set_attr_node(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_attr *attr, 
+		struct dom_attr **result);
+static dom_exception _dom_element_remove_attr_node(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_attr *attr, 
+		struct dom_attr **result);
+static dom_exception _dom_element_has_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, bool *result);
+static dom_exception _dom_element_set_id_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, bool is_id);
+
+static unsigned int _dom_element_hash_lwcstring(void *key);
+
+
+/* The operation set for namednodemap */
+static dom_exception attributes_get_length(void *priv,
+		unsigned long *length);
+static dom_exception attributes_get_named_item(void *priv,
+		struct dom_string *name, struct dom_node **node);
+static dom_exception attributes_set_named_item(void *priv,
+		struct dom_node *arg, struct dom_node **node);
+static dom_exception attributes_remove_named_item(
+		void *priv, struct dom_string *name,
+		struct dom_node **node);
+static dom_exception attributes_item(void *priv,
+		unsigned long index, struct dom_node **node);
+static dom_exception attributes_get_named_item_ns(
+		void *priv, struct dom_string *namespace,
+		struct dom_string *localname, struct dom_node **node);
+static dom_exception attributes_set_named_item_ns(
+		void *priv, struct dom_node *arg,
+		struct dom_node **node);
+static dom_exception attributes_remove_named_item_ns(
+		void *priv, struct dom_string *namespace,
+		struct dom_string *localname, struct dom_node **node);
+static void attributes_destroy(void *priv);
+static bool attributes_equal(void *p1, void *p2);
+
+static struct nnm_operation attributes_opt = {
+	attributes_get_length,
+	attributes_get_named_item,
+	attributes_set_named_item,
+	attributes_remove_named_item,
+	attributes_item,
+	attributes_get_named_item_ns,
+	attributes_set_named_item_ns,
+	attributes_remove_named_item_ns,
+	attributes_destroy,
+	attributes_equal
+};
+
+static void *_key(void *key, void *key_pw, dom_alloc alloc, void *pw, 
+		bool clone);
+static void *_value(void *value, void *value_pw, dom_alloc alloc,
+		void *pw, bool clone);
+static void *_nsattributes(void *value, void *value_pw, dom_alloc alloc,
+		void *pw, bool clone);
+
+/*----------------------------------------------------------------------*/
+/* Constructors and Destructors */
+
 /**
- * Initialise an element node
+ * Create an element node
  *
  * \param doc        The owning document
  * \param name       The (local) name of the node to create
@@ -43,41 +135,28 @@
  *
  * The returned element will already be referenced.
  */
-dom_exception dom_element_initialise(struct dom_element *el,
-		struct dom_string *name, struct dom_string *namespace,
-		struct dom_string *prefix, struct dom_element **result)
+dom_exception _dom_element_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct lwc_string_s *namespace,
+		struct lwc_string_s *prefix, struct dom_element **result)
 {
-	dom_exception err;
-	struct dom_document *doc;
+	struct dom_element *el;
 
-	dom_node_get_owner_document(el, &doc);
+	/* Allocate the element */
+	el = _dom_document_alloc(doc, NULL, sizeof(struct dom_element));
+	if (el == NULL)
+		return DOM_NO_MEM_ERR;
 
-	/** \todo Sanity check the tag name */
-
-	/* Initialise the base class */
-	err = dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
-			name, NULL, namespace, prefix);
-	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, el, 0);
-		return err;
-	}
-
-	/* Perform our type-specific initialisation */
-	el->attributes = NULL;
-	el->schema_type_info = NULL;
-
 	/* Init the vtable's destroy function */
 	el->base.base.vtable = &element_vtable;
-	el->base.destroy = &_dom_element_destroy;
+	el->base.vtable = &element_protect_vtable;
 
-	*result = el;
-
-	return DOM_NO_ERR;
+	return _dom_element_initialise(el, doc, name, namespace, prefix, result);
 }
 
 /**
- * Create an element node
+ * Initialise an element node
  *
+ * \param el	     The element
  * \param doc        The owning document
  * \param name       The (local) name of the node to create
  * \param namespace  The namespace URI of the element, or NULL
@@ -92,19 +171,45 @@
  *
  * The returned element will already be referenced.
  */
-dom_exception dom_element_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *namespace,
-		struct dom_string *prefix, struct dom_element **result)
+dom_exception _dom_element_initialise(struct dom_element *el, 
+		struct dom_document *doc, struct lwc_string_s *name, 
+		struct lwc_string_s *namespace, struct lwc_string_s *prefix, 
+		struct dom_element **result)
 {
-	struct dom_element *el;
+	dom_exception err;
 
-	/* Allocate the element */
-	el = dom_document_alloc(doc, NULL, sizeof(struct dom_element));
-	if (el == NULL)
-		return DOM_NO_MEM_ERR;
+	assert(doc != NULL);
+	/** \todo Sanity check the tag name */
 
-	dom_element_initialise(el, name, namespace, prefix, result);
-	
+	err = _dom_document_create_hashtable(doc, CHAINS_ATTRIBUTES, 
+			_dom_element_hash_lwcstring, &el->attributes);
+	if (err != DOM_NO_ERR) {
+		_dom_document_alloc(doc, el, 0);
+		return err;
+	}
+
+	err = _dom_document_create_hashtable(doc, CHAINS_NAMESPACE, 
+			_dom_element_hash_lwcstring, &el->ns_attributes);
+	if (err != DOM_NO_ERR) {
+		_dom_document_alloc(doc, el, 0);
+		_dom_document_alloc(doc, el->attributes, 0);
+		return err;
+	}
+	/* Initialise the base class */
+	err = _dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
+			name, NULL, namespace, prefix);
+	if (err != DOM_NO_ERR) {
+		_dom_document_alloc(doc, el, 0);
+		return err;
+	}
+
+	/* Perform our type-specific initialisation */
+	el->id_ns = NULL;
+	el->id_name = NULL;
+	el->schema_type_info = NULL;
+
+	*result = el;
+
 	return DOM_NO_ERR;
 }
 
@@ -116,54 +221,21 @@
  *
  * The contents of ::element will be destroyed and ::element will be freed.
  */
-void dom_element_destroy(struct dom_document *doc,
+void _dom_element_destroy(struct dom_document *doc,
 		struct dom_element *element)
 {
-	struct dom_node_internal *c, *d;
+	lwc_context *ctx = _dom_document_get_intern_context(doc);
+	assert (ctx != NULL);
 
-	/* Destroy children of this node */
-	for (c = element->base.first_child; c != NULL; c = d) {
-		d = c->next;
-
-		/* Detach child */
-		c->parent = NULL;
-
-		if (c->refcnt > 0) {
-			/* Something is using this child */
-
-			/** \todo add to list of nodes pending deletion */
-
-			continue;
-		}
-
-		/* Detach from sibling list */
-		c->previous = NULL;
-		c->next = NULL;
-
-		dom_node_destroy(c);
+	/* Destroy attributes attached to this node */
+	if (element->attributes != NULL) {
+		_dom_hash_destroy(element->attributes, _key, ctx, _value, ctx);
+		element->attributes = NULL;
 	}
 
-	/* Destroy attributes attached to this node */
-	for (c = (struct dom_node_internal *) element->attributes;
-			c != NULL; c = d) {
-		d = c->next;
-
-		/* Detach child */
-		c->parent = NULL;
-
-		if (c->refcnt > 0) {
-			/* Something is using this attribute */
-
-			/** \todo add to list of nodes pending deletion */
-
-			continue;
-		}
-
-		/* Detach from sibling list */
-		c->previous = NULL;
-		c->next = NULL;
-
-		dom_node_destroy(c);
+	if (element->ns_attributes != NULL) {
+		_dom_hash_destroy(element->ns_attributes, _key, ctx, _nsattributes, ctx);
+		element->ns_attributes = NULL;
 	}
 
 	if (element->schema_type_info != NULL) {
@@ -171,24 +243,15 @@
 	}
 
 	/* Finalise base class */
-	dom_node_finalise(doc, &element->base);
+	_dom_node_finalise(doc, &element->base);
 
 	/* Free the element */
-	dom_document_alloc(doc, element, 0);
+	_dom_document_alloc(doc, element, 0);
 }
 
-/**
- * The destroy virtual function of dom_element 
- * 
- * \param element The element to be destroyed
- **/
-void _dom_element_destroy(struct dom_node_internal *node)
-{
-	struct dom_document *doc;
-	dom_node_get_owner_document(node, &doc);
+/*----------------------------------------------------------------------*/
 
-	dom_element_destroy(doc, (struct dom_element *) node);
-}
+/* The public virtual functions */
 
 /**
  * Retrieve an element's tag name
@@ -224,23 +287,7 @@
 dom_exception _dom_element_get_attribute(struct dom_element *element,
 		struct dom_string *name, struct dom_string **value)
 {
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
-
-	/* Search attributes, looking for name */
-	for (; a != NULL; a = a->next) {
-		if (dom_string_cmp(a->name, name) == 0)
-			break;
-	}
-
-	/* Fill in value */
-	if (a == NULL) {
-		*value = NULL;
-	} else {
-		dom_attr_get_value(((struct dom_attr *) a), value);
-	}
-
-	return DOM_NO_ERR;
+	return _dom_element_get_attr(element, element->attributes, name, value);
 }
 
 /**
@@ -256,58 +303,7 @@
 dom_exception _dom_element_set_attribute(struct dom_element *element,
 		struct dom_string *name, struct dom_string *value)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
-
-	/** \todo validate name */
-
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Search for existing attribute with same name */
-	for (; a != NULL; a = a->next) {
-		if (dom_string_cmp(a->name, name) == 0)
-			break;
-	}
-
-	if (a != NULL) {
-		/* Found an existing attribute, so replace its value */
-		dom_exception err;
-
-		err = dom_attr_set_value((struct dom_attr *) a, value);
-		if (err != DOM_NO_ERR)
-			return err;
-	} else {
-		/* No existing attribute, so create one */
-		dom_exception err;
-		struct dom_attr *attr;
-
-		err = dom_attr_create(e->owner, name, NULL, NULL, &attr);
-		if (err != DOM_NO_ERR)
-			return err;
-
-		/* Set its value */
-		err = dom_attr_set_value(attr, value);
-		if (err != DOM_NO_ERR) {
-			dom_node_unref((struct dom_node *) attr);
-			return err;
-		}
-
-		a = (struct dom_node_internal *) attr;
-
-		/* And insert it into the element */
-		a->previous = NULL;
-		a->next = (struct dom_node_internal *) element->attributes;
-
-		if (a->next != NULL)
-			a->next->previous = a;
-
-		element->attributes = attr;
-	}
-
-	return DOM_NO_ERR;
+	return _dom_element_set_attr(element, element->attributes, name, value);
 }
 
 /**
@@ -321,39 +317,7 @@
 dom_exception _dom_element_remove_attribute(struct dom_element *element,
 		struct dom_string *name)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
-
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Search for existing attribute with same name */
-	for (; a != NULL; a = a->next) {
-		if (dom_string_cmp(a->name, name) == 0)
-			break;
-	}
-
-	/* Detach attr node from list */
-	if (a != NULL) {
-		if (a->previous != NULL)
-			a->previous->next = a->next;
-		else
-			element->attributes = (struct dom_attr *) a->next;
-
-		if (a->next != NULL)
-			a->next->previous = a->previous;
-
-		a->previous = a->next = a->parent = NULL;
-
-		/* And destroy attr */
-		dom_node_unref(a);
-	}
-
-	/** \todo defaulted attribute handling */
-
-	return DOM_NO_ERR;
+	return _dom_element_remove_attr(element, element->attributes, name);
 }
 
 /**
@@ -368,23 +332,11 @@
  * the responsibility of the caller to unref the node once it has
  * finished with it.
  */
-dom_exception _dom_element_get_attribute_node(struct dom_element *element,
+dom_exception _dom_element_get_attribute_node(struct dom_element *element, 
 		struct dom_string *name, struct dom_attr **result)
 {
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
-
-	/* Search attributes, looking for name */
-	for (; a != NULL; a = a->next) {
-		if (dom_string_cmp(a->name, name) == 0)
-			break;
-	}
-
-	if (a != NULL)
-		dom_node_ref(a);
-	*result = (struct dom_attr *) a;
-
-	return DOM_NO_ERR;
+	return _dom_element_get_attr_node(element, element->attributes, name, 
+			result);
 }
 
 /**
@@ -407,78 +359,8 @@
 dom_exception _dom_element_set_attribute_node(struct dom_element *element,
 		struct dom_attr *attr, struct dom_attr **result)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) attr;
-	struct dom_attr *prev = NULL;
-
-	/* Ensure element and attribute belong to the same document */
-	if (e->owner != a->owner)
-		return DOM_WRONG_DOCUMENT_ERR;
-
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Ensure attribute isn't attached to another element */
-	if (a->parent != NULL && a->parent != e)
-		return DOM_INUSE_ATTRIBUTE_ERR;
-
-	/* Attach attr to element, if not already attached */
-	if (a->parent == NULL) {
-
-		/* Search for existing attribute with same name */
-		prev = element->attributes; 
-		while (prev != NULL) {
-			struct dom_node_internal *p = 
-					(struct dom_node_internal *) prev;
-
-			if (dom_string_cmp(a->name, p->name) == 0)
-				break;
-
-			prev = (struct dom_attr *) p->next;
-		}
-
-		a->parent = e;
-
-		if (prev != NULL) {
-			/* Found an existing attribute, so replace it */
-			struct dom_node_internal *p = 
-					(struct dom_node_internal *) prev;
-
-			a->previous = p->previous;
-			a->next = p->next;
-
-			if (a->previous != NULL)
-				a->previous->next = a;
-			else
-				element->attributes = attr;
-
-			if (a->next != NULL)
-				a->next->previous = a;
-
-			/* Invalidate existing attribute's location info */
-			p->next = NULL;
-			p->previous = NULL;
-			p->parent = NULL;
-		} else {
-			/* No existing attribute, so insert at front of list */
-			a->previous = NULL;
-			a->next = (struct dom_node_internal *) 
-					element->attributes;
-
-			if (a->next != NULL)
-				a->next->previous = a;
-
-			element->attributes = attr;
-		}
-	}
-
-	if (prev != NULL)
-		dom_node_ref((struct dom_node *) prev);
-
-	*result = prev;
-
-	return DOM_NO_ERR;
+	return _dom_element_set_attr_node(element, element->attributes, attr, 
+			result);
 }
 
 /**
@@ -499,35 +381,8 @@
 dom_exception _dom_element_remove_attribute_node(struct dom_element *element,
 		struct dom_attr *attr, struct dom_attr **result)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) attr;
-
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Ensure attr is an attribute of element */
-	if (a->parent != e)
-		return DOM_NOT_FOUND_ERR;
-
-	/* Detach attr node from list */
-	if (a->previous != NULL)
-		a->previous->next = a->next;
-	else
-		element->attributes = (struct dom_attr *) a->next;
-
-	if (a->next != NULL)
-		a->next->previous = a->previous;
-
-	a->previous = a->next = a->parent = NULL;
-
-	/** \todo defaulted attribute handling */
-
-	/* Return the detached node */
-	dom_node_ref(a);
-	*result = attr;
-
-	return DOM_NO_ERR;
+	return _dom_element_remove_attr_node(element, element->attributes,
+			attr, result);
 }
 
 /**
@@ -547,9 +402,25 @@
 		struct dom_element *element, struct dom_string *name,
 		struct dom_nodelist **result)
 {
-	return dom_document_get_nodelist(element->base.owner, 
-			(struct dom_node_internal *) element, name, NULL, 
+	dom_exception err;
+	lwc_string *n;
+	lwc_context *ctx;
+	dom_node_internal *base = (dom_node_internal *) element;
+	
+	assert(base->owner != NULL);
+	ctx = _dom_document_get_intern_context(base->owner);
+	assert(ctx != NULL);
+
+	err = _dom_string_intern(name, ctx, &n);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_document_get_nodelist(base->owner, DOM_NODELIST_BY_NAME,
+			(struct dom_node_internal *) element, n, NULL, 
 			NULL, result);
+
+	lwc_context_string_unref(ctx, n);
+	return err;
 }
 
 /**
@@ -573,28 +444,25 @@
 		struct dom_string *namespace, struct dom_string *localname,
 		struct dom_string **value)
 {
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
+	lwc_string *str;
+	dom_exception err;
+	struct dom_hash_table *attrs;
 
-	/** \todo ensure implementation supports XML */
+	if (namespace == NULL)
+		return _dom_element_get_attribute(element, localname, value);
 
-	/* Search attributes, looking for namespace/localname pair */
-	for (; a != NULL; a = a->next) {
-		if (((namespace == NULL && a->namespace == NULL) || 
-			(namespace != NULL && 
-			dom_string_cmp(a->namespace, namespace) == 0)) &&
-				dom_string_cmp(a->name, localname) == 0)
-			break;
-	}
-
-	/* Fill in value */
-	if (a == NULL) {
+	err = _dom_node_get_intern_string(&element->base, namespace, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, str);
+	/* The element has no such namespace */
+	if (attrs == NULL) {
 		*value = NULL;
-	} else {
-		dom_attr_get_value(((struct dom_attr *) a), value);
+		return DOM_NO_ERR;
 	}
 
-	return DOM_NO_ERR;
+	return _dom_element_get_attr(element, attrs, localname, value);
 }
 
 /**
@@ -630,101 +498,54 @@
 		struct dom_string *namespace, struct dom_string *qname,
 		struct dom_string *value)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
-	struct dom_string *prefix, *localname;
+	lwc_string *str;
 	dom_exception err;
+	struct dom_hash_table *attrs;
+	bool added;
 
-	/** \todo ensure XML feature is supported */
+	if (_dom_validate_name(qname) == false)
+		return DOM_INVALID_CHARACTER_ERR;
 
-	/* Validate name */
 	err = _dom_namespace_validate_qname(qname, namespace);
-	if (err != DOM_NO_ERR) {
-		return err;
-	}
+	if (err != DOM_NO_ERR)
+		return DOM_NAMESPACE_ERR;
 
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e)) {
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-	}
-
-	/* Decompose QName */
+	dom_string *localname;
+	dom_string *prefix;
 	err = _dom_namespace_split_qname(qname, &prefix, &localname);
-	if (err != DOM_NO_ERR) {
+	if (err != DOM_NO_ERR)
 		return err;
-	}
 
-	/* Search for existing attribute with same namespace/localname */
-	for (; a != NULL; a = a->next) {
-		if (((namespace == NULL && a->namespace == NULL) || 
-			(namespace != NULL && 
-			dom_string_cmp(a->namespace, namespace) == 0)) &&
-				dom_string_cmp(a->name, localname) == 0)
-			break;
+	/* If there is no namespace, redirect to set_attribute */
+	if (namespace == NULL) {
+		if (prefix != NULL)
+			return DOM_NAMESPACE_ERR;
+		err = _dom_element_set_attribute(element, localname, value);
+		dom_string_unref(localname);
+		return err;
 	}
 
-	if (a != NULL) {
-		/* Found an existing attribute, so replace its prefix & value */
-		dom_exception err;
-
-		err = dom_node_set_prefix(a, prefix);
-		if (err != DOM_NO_ERR) {
-			if (prefix != NULL) {
-				dom_string_unref(prefix);
-			}
-			dom_string_unref(localname);
+	err = _dom_node_get_intern_string(&element->base, namespace, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, str);
+	/* The element has no such namespace */
+	if (attrs == NULL) {
+		dom_document *doc;
+		doc = dom_node_get_owner(element);
+		assert(doc != NULL);
+		err = _dom_document_create_hashtable(doc, CHAINS_NS_ATTRIBUTES,
+				_dom_element_hash_lwcstring, &attrs);
+		if (err != DOM_NO_ERR)
 			return err;
-		}
 
-		err = dom_attr_set_value((struct dom_attr *) a, value);
-		if (err != DOM_NO_ERR) {
-			if (prefix != NULL) {
-				dom_string_unref(prefix);
-			}
-			dom_string_unref(localname);
-			return err;
-		}
-	} else {
-		/* No existing attribute, so create one */
-		dom_exception err;
-		struct dom_attr *attr;
-
-		err = dom_attr_create(e->owner, localname, 
-				namespace, prefix, &attr);
-		if (err != DOM_NO_ERR) {
-			if (prefix != NULL) {
-				dom_string_unref(prefix);
-			}
-			dom_string_unref(localname);
-			return err;
-		}
-
-		/* Set its value */
-		err = dom_attr_set_value(attr, value);
-		if (err != DOM_NO_ERR) {
-			dom_node_unref((struct dom_node *) attr);
-
-			if (prefix != NULL) {
-				dom_string_unref(prefix);
-			}
-			dom_string_unref(localname);
-			return err;
-		}
-
-		a = (struct dom_node_internal *) attr;
-
-		/* And insert it into the element */
-		a->previous = NULL;
-		a->next = (struct dom_node_internal *) element->attributes;
-
-		if (a->next != NULL)
-			a->next->previous = a;
-
-		element->attributes = attr;
+		added = _dom_hash_add(element->ns_attributes, str, attrs, false);
+		if (added == false)
+			return DOM_NO_MEM_ERR;
 	}
 
-	return DOM_NO_ERR;
+	return _dom_element_set_attr(element, attrs, localname, value);
 }
 
 /**
@@ -744,44 +565,24 @@
 dom_exception _dom_element_remove_attribute_ns(struct dom_element *element,
 		struct dom_string *namespace, struct dom_string *localname)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
+	lwc_string *str;
+	dom_exception err;
+	struct dom_hash_table *attrs;
 
-	/** \todo ensure XML feature is supported */
+	if (namespace != NULL)
+		return _dom_element_remove_attribute(element, localname);
 
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Search for existing attribute with same namespace/localname */
-	for (; a != NULL; a = a->next) {
-		if (((namespace == NULL && a->namespace == NULL) || 
-			(namespace != NULL && 
-			dom_string_cmp(a->namespace, namespace) == 0)) &&
-				dom_string_cmp(a->name, localname) == 0)
-			break;
+	err = _dom_node_get_intern_string(&element->base, namespace, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, str);
+	/* The element has no such namespace */
+	if (attrs == NULL) {
+		return DOM_NO_ERR;
 	}
 
-	/* Detach attr node from list */
-	if (a != NULL) {
-		if (a->previous != NULL)
-			a->previous->next = a->next;
-		else
-			element->attributes = (struct dom_attr *) a->next;
-
-		if (a->next != NULL)
-			a->next->previous = a->previous;
-
-		a->previous = a->next = a->parent = NULL;
-
-		/* And destroy attr */
-		dom_node_unref(a);
-	}
-
-	/** \todo defaulted attribute handling */
-
-	return DOM_NO_ERR;
+	return _dom_element_remove_attr(element, attrs, localname);
 }
 
 /**
@@ -805,25 +606,26 @@
 		struct dom_string *namespace, struct dom_string *localname,
 		struct dom_attr **result)
 {
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
+	lwc_string *str;
+	dom_exception err;
+	struct dom_hash_table *attrs;
 
-	/** \todo ensure XML feature is supported */
+	if (namespace == NULL) {
+		return _dom_element_get_attribute_node(element, localname, result);
+	}
 
-	/* Search attributes, looking for namespace/localname */
-	for (; a != NULL; a = a->next) {
-		if (((namespace == NULL && a->namespace == NULL) || 
-			(namespace != NULL && 
-			dom_string_cmp(a->namespace, namespace) == 0)) &&
-				dom_string_cmp(a->name, localname) == 0)
-			break;
+	err = _dom_node_get_intern_string(&element->base, namespace, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, str);
+	/* The element has no such namespace */
+	if (attrs == NULL) {
+		*result = NULL;
+		return DOM_NO_ERR;
 	}
 
-	if (a != NULL)
-		dom_node_ref(a);
-	*result = (struct dom_attr *) a;
-
-	return DOM_NO_ERR;
+	return _dom_element_get_attr_node(element, attrs, localname, result);
 }
 
 /**
@@ -851,84 +653,45 @@
 dom_exception _dom_element_set_attribute_node_ns(struct dom_element *element,
 		struct dom_attr *attr, struct dom_attr **result)
 {
-	struct dom_node_internal *e = (struct dom_node_internal *) element;
-	struct dom_node_internal *a = (struct dom_node_internal *) attr;
-	struct dom_attr *prev = NULL;
+	lwc_string *str;
+	dom_exception err;
+	struct dom_hash_table *attrs;
+	bool added;
+	dom_string *namespace;
 
-	/** \todo ensure XML feature is supported */
+	err = dom_node_get_namespace(attr, (void *) &namespace);
+	if (err != DOM_NO_ERR)
+		return err;
 
-	/* Ensure element and attribute belong to the same document */
-	if (e->owner != a->owner)
-		return DOM_WRONG_DOCUMENT_ERR;
+	if (namespace == NULL)
+		return _dom_element_set_attribute_node(element, attr, result);
 
-	/* Ensure element can be written to */
-	if (_dom_node_readonly(e))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
+	err = _dom_node_get_intern_string(&element->base, namespace, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, str);
+	/* The element has no such namespace */
+	if (attrs == NULL) {
+		dom_document *doc;
+		doc = dom_node_get_owner(element);
+		assert(doc != NULL);
+		err = _dom_document_create_hashtable(doc, CHAINS_NS_ATTRIBUTES,
+				_dom_element_hash_lwcstring, &attrs);
+		if (err != DOM_NO_ERR)
+			return err;
 
-	/* Ensure attribute isn't attached to another element */
-	if (a->parent != NULL && a->parent != e)
-		return DOM_INUSE_ATTRIBUTE_ERR;
-
-	/* Attach attr to element, if not already attached */
-	if (a->parent == NULL) {
-
-		/* Search for existing attribute with same namespace/localname */
-		prev = element->attributes; 
-		while (prev != NULL) {
-			struct dom_node_internal *p = 
-					(struct dom_node_internal *) prev;
-
-			if (((a->namespace == NULL && p->namespace == NULL) || 
-				(a->namespace != NULL && 
-				dom_string_cmp(a->namespace, 
-						p->namespace) == 0)) &&
-				dom_string_cmp(a->name, p->name) == 0)
-			break;
-
-			prev = (struct dom_attr *) p->next;
-		}
-
-		a->parent = e;
-
-		if (prev != NULL) {
-			/* Found an existing attribute, so replace it */
-			struct dom_node_internal *p = 
-					(struct dom_node_internal *) prev;
-
-			a->previous = p->previous;
-			a->next = p->next;
-
-			if (a->previous != NULL)
-				a->previous->next = a;
-			else
-				element->attributes = attr;
-
-			if (a->next != NULL)
-				a->next->previous = a;
-
-			/* Invalidate existing attribute's location info */
-			p->next = NULL;
-			p->previous = NULL;
-			p->parent = NULL;
-		} else {
-			/* No existing attribute, so insert at front of list */
-			a->previous = NULL;
-			a->next = (struct dom_node_internal *) 
-					element->attributes;
-
-			if (a->next != NULL)
-				a->next->previous = a;
-
-			element->attributes = attr;
-		}
+		added = _dom_hash_add(element->ns_attributes, str, attrs, false);
+		if (added == false)
+			return DOM_NO_MEM_ERR;
 	}
 
-	if (prev != NULL)
-		dom_node_ref((struct dom_node *) prev);
+	dom_string *localname;
+	err = dom_node_get_local_name(attr, (void *) &localname);
+	if (err != DOM_NO_ERR)
+		return err;
 
-	*result = prev;
-
-	return DOM_NO_ERR;
+	return _dom_element_set_attr_node(element, attrs, attr, result);
 }
 
 /**
@@ -953,11 +716,39 @@
 		struct dom_element *element, struct dom_string *namespace,
 		struct dom_string *localname, struct dom_nodelist **result)
 {
+	dom_document *doc;
+	dom_exception err;
+	doc = element->base.owner;
+
 	/** \todo ensure XML feature is supported */
 
-	return dom_document_get_nodelist(element->base.owner, 
+	/* Get the interned string from the dom_string */
+	assert(doc->context != NULL);
+	lwc_string *l = NULL, *n = NULL;
+	if (localname != NULL) {
+		err = _dom_string_intern(localname, doc->context, &l);
+		if (err != DOM_NO_ERR)
+			return err;
+	}
+	if (namespace != NULL) {
+		err = _dom_string_intern(namespace, doc->context, &n);
+		if (err != DOM_NO_ERR) {
+			lwc_context_string_unref(doc->context, l);
+
+			return err;
+		}
+	}
+
+	err = _dom_document_get_nodelist(element->base.owner, DOM_NODELIST_BY_NAMESPACE,
 			(struct dom_node_internal *) element, NULL, 
-			namespace, localname, result);
+			n, l, result);
+
+	if (localname != NULL)
+		lwc_context_string_unref(doc->context, l);
+	if (namespace != NULL)
+		lwc_context_string_unref(doc->context, n);
+
+	return err;
 }
 
 /**
@@ -971,18 +762,7 @@
 dom_exception _dom_element_has_attribute(struct dom_element *element,
 		struct dom_string *name, bool *result)
 {
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
-
-	/* Search attributes, looking for name */
-	for (; a != NULL; a = a->next) {
-		if (dom_string_cmp(a->name, name) == 0)
-			break;
-	}
-
-	*result = (a != NULL);
-
-	return DOM_NO_ERR;
+	return _dom_element_has_attr(element, element->attributes, name, result);
 }
 
 /**
@@ -1003,23 +783,25 @@
 		struct dom_string *namespace, struct dom_string *localname,
 		bool *result)
 {
-	struct dom_node_internal *a = (struct dom_node_internal *) 
-			element->attributes;
+	lwc_string *str;
+	dom_exception err;
+	struct dom_hash_table *attrs;
 
-	/** \todo ensure XML feature is supported */
+	if (namespace == NULL)
+		return _dom_element_has_attribute(element, localname, result);
 
-	/* Search attributes, looking for namespace/localname */
-	for (; a != NULL; a = a->next) {
-		if (((namespace == NULL && a->namespace == NULL) || 
-			(namespace != NULL && 
-			dom_string_cmp(a->namespace, namespace) == 0)) &&
-				dom_string_cmp(a->name, localname) == 0)
-			break;
+	err = _dom_node_get_intern_string(&element->base, namespace, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attrs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, str);
+	/* The element has no such namespace */
+	if (attrs == NULL) {
+		*result = false;
+		return DOM_NO_ERR;
 	}
 
-	*result = (a != NULL);
-
-	return DOM_NO_ERR;
+	return _dom_element_has_attr(element, attrs, localname, result);
 }
 
 /**
@@ -1052,15 +834,16 @@
  *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
  *         DOM_NOT_FOUND_ERR               if the specified node is not an
  *                                         attribute of ::element.
+ *
+ * @note: The DOM spec does not say: how to deal with when there are two or 
+ * more isId attribute nodes. Here, the implementation just maintain only
+ * one such attribute node.
  */
 dom_exception _dom_element_set_id_attribute(struct dom_element *element,
 		struct dom_string *name, bool is_id)
 {
-	UNUSED(element);
-	UNUSED(name);
-	UNUSED(is_id);
-
-	return DOM_NOT_SUPPORTED_ERR;
+	return _dom_element_set_id_attr(element, element->attributes, name, 
+			is_id);
 }
 
 /**
@@ -1079,12 +862,27 @@
 		struct dom_string *namespace, struct dom_string *localname,
 		bool is_id)
 {
-	UNUSED(element);
-	UNUSED(namespace);
-	UNUSED(localname);
-	UNUSED(is_id);
+	struct dom_hash_table *hs;
+	dom_exception err;
+	lwc_string *ns;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	if (namespace == NULL)
+		return _dom_element_set_id_attribute(element, localname, is_id);
+
+	err = _dom_node_get_intern_string(&element->base, namespace, &ns);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	hs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, ns);
+	assert(hs != NULL);
+
+	err = _dom_element_set_id_attr(element, hs, localname, is_id);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	element->id_ns = ns;
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1101,59 +899,1075 @@
 dom_exception _dom_element_set_id_attribute_node(struct dom_element *element,
 		struct dom_attr *id_attr, bool is_id)
 {
-	UNUSED(element);
-	UNUSED(id_attr);
-	UNUSED(is_id);
+	struct dom_hash_table *hs;
+	dom_exception err;
+	lwc_string *ns;
+	dom_string *namespace;
+	dom_string *localname;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	err = dom_node_get_namespace(id_attr, &namespace);
+	if (err != DOM_NO_ERR)
+		return err;
+	err = dom_node_get_local_name(id_attr, &localname);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_node_get_intern_string(&element->base, namespace, &ns);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	hs = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, ns);
+	assert(hs != NULL);
+
+	err = _dom_element_set_id_attr(element, hs, localname, is_id);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	element->id_ns = ns;
+
+	return DOM_NO_ERR;
+
 }
 
-/*                                                                            */
+/*------------- The overload virtual functions ------------------------*/
+
+/* Overload function of Node, please refer src/core/node.c for detail */
+dom_exception _dom_element_get_attributes(dom_node_internal *node,
+		struct dom_namednodemap **result)
+{
+	dom_exception err;
+	dom_document *doc;
+
+	doc = dom_node_get_owner(node);
+	assert(doc != NULL);
+
+	err = _dom_namednodemap_create(doc, node, &attributes_opt, result);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	dom_node_ref(node);
+	
+	return DOM_NO_ERR;
+}
+
+/* Overload function of Node, please refer src/core/node.c for detail */
+dom_exception _dom_element_has_attributes(dom_node_internal *node, bool *result)
+{
+	UNUSED(node);
+	*result = true;
+
+	return DOM_NO_ERR;
+}
+
+/* For the following namespace related algorithm take a look at:
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html
+ */
+
+/**
+ * Look up the prefix which match the namespace.
+ *
+ * \param node		The current Node in which we search for
+ * \param namespace	The namespace for which we search a prefix
+ * \param result	The returned prefix
+ */
+dom_exception _dom_element_lookup_prefix(dom_node_internal *node,
+		struct dom_string *namespace, struct dom_string **result)
+{
+	struct dom_element *owner;
+	dom_exception err;
+
+	err = dom_attr_get_owner_element(node, &owner);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (owner == NULL) {
+		*result = NULL;
+		return DOM_NO_ERR;
+	}
+
+	return dom_node_lookup_prefix(owner, namespace, result);
+}
+
+/**
+ * Test whether certain namespace is the default namespace of some node.
+ *
+ * \param node		The Node to test
+ * \param namespace	The namespace to test
+ * \param result	true is the namespace is default namespace
+ */
+dom_exception _dom_element_is_default_namespace(dom_node_internal *node,
+		struct dom_string *namespace, bool *result)
+{
+	struct dom_element *ele = (struct dom_element *) node;
+	lwc_string *ns;
+	dom_string *value;
+	dom_document *doc = node->owner;
+	lwc_context *ctx;
+	dom_exception err;
+
+	assert(doc != NULL);
+	err = _dom_node_get_intern_string(node, namespace, &ns);
+	if (err != DOM_NO_ERR) {
+		return err;
+	}
+	ctx = _dom_document_get_intern_context(doc);
+	assert(ctx != NULL);
+	if (node->prefix == NULL) {
+		lwc_context_string_isequal(ctx, node->namespace, ns, result);
+		lwc_context_string_unref(ctx, ns);
+		return DOM_NO_ERR;
+	}
+
+	bool has;
+	dom_string *xmlns = _dom_namespace_get_xmlns_prefix();
+	err = dom_element_has_attribute(ele, xmlns, &has);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (has == true) {
+		return dom_element_get_attribute(ele, xmlns, &value);
+	}
+
+	lwc_string *ns2;
+	err = _dom_node_get_intern_string(node, value, &ns2);
+	if (err != DOM_NO_ERR) {
+		return err;
+	}
+	
+	if (ns2 != NULL) {
+		lwc_context_string_isequal(ctx, ns2, ns, result);
+		lwc_context_string_unref(ctx, ns);
+		lwc_context_string_unref(ctx, ns2);
+		dom_string_unref(value);
+		return DOM_NO_ERR;
+	}
+	
+
+	return dom_node_is_default_namespace(node->parent, namespace, result);
+}
+
+/**
+ * Look up the namespace with certain prefix.
+ *
+ * \param node		The current node in which we search for the prefix
+ * \param prefix	The prefix to search
+ * \param result	The result namespace if found
+ */
+dom_exception _dom_element_lookup_namespace(dom_node_internal *node,
+		struct dom_string *prefix, struct dom_string **result)
+{
+	lwc_string *pf;
+	dom_exception err;
+
+	err = _dom_node_get_intern_string(node, prefix, &pf);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	/* To some extent, directly compare the two lwc_string pointer
+	 * is better */
+	if (node->namespace != NULL && node->prefix == pf) {
+		assert(node->owner != NULL);
+		return _dom_document_create_string_from_lwcstring(node->owner, pf,
+				result);
+	}
+	
+	bool has;
+	dom_string *xmlns = _dom_namespace_get_xmlns_prefix();
+	err = dom_element_has_attribute_ns(node, dom_namespaces[DOM_NAMESPACE_XMLNS], prefix, &has);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (has == true)
+		return dom_element_get_attribute_ns(node, dom_namespaces[DOM_NAMESPACE_XMLNS], prefix, result);
+
+	err = dom_element_has_attribute(node, xmlns, &has);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (has == true) {
+		return dom_element_get_attribute(node, xmlns, result);
+	}
+
+	return dom_node_lookup_namespace(node->parent, prefix, result);
+}
+
+
+/*----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/**
+ * The destroy virtual function of dom_element 
+ * 
+ * \param element The element to be destroyed
+ **/
+void __dom_element_destroy(struct dom_node_internal *node)
+{
+	struct dom_document *doc = dom_node_get_owner(node);
+
+	_dom_element_destroy(doc, (struct dom_element *) node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_element_alloc(dom_document *doc, struct dom_node_internal *n,
+		struct dom_node_internal **ret)
+{
+	dom_element *e;
+	UNUSED(n);
+
+	e = _dom_document_alloc(doc, NULL, sizeof(struct dom_element));
+	if (e == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) e;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * TODO: How to deal with default attribue:
+ *
+ *  Ask a language binding for default attributes.	
+ *
+ *	So, when we copy a element we copy all its attributes because they
+ *	are all specified. For the methods like importNode and adoptNode, 
+ *	this will make _dom_element_copy can be used in them.
+ */
+dom_exception _dom_element_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	dom_element *ne = (dom_element *) new;
+	dom_element *oe = (dom_element *) old;
+	dom_document *od, *nd;
+	struct dom_hash_table *ht;
+	lwc_context *oc, *nc;
+	dom_exception err;
+
+	err = _dom_node_copy(new, old);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	od = dom_node_get_owner(old);
+	nd = dom_node_get_owner(new);
+	assert(od != NULL);
+	assert(nd != NULL);
+
+	oc = _dom_document_get_intern_context(od);
+	nc = _dom_document_get_intern_context(nd);
+	assert(oc != NULL);
+	assert(nc != NULL);
+
+	dom_alloc alloc;
+	void *pw;
+	_dom_document_get_allocator(nd, &alloc, &pw);
+
+	/* copy the hash tables */
+	ht = _dom_hash_clone(oe->attributes, alloc, pw, _key, nc,
+			_value, nd);
+	if (ht == NULL)
+		return DOM_NO_MEM_ERR;
+	ne->attributes = ht;
+
+	ht = _dom_hash_clone(oe->ns_attributes, alloc, pw, _key, nc,
+			_nsattributes, nd);
+	if (ht == NULL)
+		return DOM_NO_MEM_ERR;
+	ne->ns_attributes = ht;
+
+	/* TODO: deal with dom_type_info, it get no definition ! */
+
+	return DOM_NO_ERR;
+}
+
+
+
 /*----------------------------------------------------------------------------*/
-/*                                                                            */
 
+/* Helper functions */
+
 /**
- * Retrieve a map of attributes associated with an Element
+ * The internal helper function for getAttribute/getAttributeNS.
  *
- * \param element  The element to retrieve the attributes of
- * \param result   Pointer to location to receive attribute map
- * \return DOM_NO_ERR.
+ * \param element	The element
+ * \param hs		The hash table contains the attributes
+ * \param name		The name of the attribute
+ * \param value		The value of the attribute
+ */
+dom_exception _dom_element_get_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, 
+		struct dom_string **value)
+{
+	void *a;
+	dom_exception err;
+	lwc_string *str;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = _dom_hash_get(hs, str);
+
+	/* Fill in value */
+	if (a == NULL) {
+		*value = NULL;
+	} else {
+		dom_attr_get_value(((struct dom_attr *) a), value);
+	}
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The internal helper function for setAttribute and setAttributeNS.
  *
- * The returned NamedNodeMap will be referenced. It is the responsibility
- * of the caller to unref the map once it has finished with it.
+ * \param element	The element
+ * \param hs		The attributes' hash table
+ * \param name		The name of the new attribute
+ * \param value 	The value of the new attribute
  */
-dom_exception dom_element_get_attributes(struct dom_element *element,
-		struct dom_namednodemap **result)
+dom_exception _dom_element_set_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, 
+		struct dom_string *value)
 {
-	return dom_document_get_namednodemap(element->base.owner,
-			(struct dom_node_internal *) element, 
-			DOM_ATTRIBUTE_NODE, result);
+	void *a;
+	dom_exception err;
+	lwc_string *str;
+	bool added;
+	dom_node_internal *e = (dom_node_internal *) element;
+
+	if (_dom_validate_name(name) == false)
+		return DOM_INVALID_CHARACTER_ERR;
+
+	/* Ensure element can be written to */
+	if (_dom_node_readonly(e))
+		return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = _dom_hash_get(hs, str);
+
+	if (a != NULL) {
+		/* Found an existing attribute, so replace its value */
+		dom_exception err;
+
+		err = dom_attr_set_value((struct dom_attr *) a, value);
+		if (err != DOM_NO_ERR)
+			return err;
+	} else {
+		/* No existing attribute, so create one */
+		dom_exception err;
+		struct dom_attr *attr;
+
+		err = _dom_attr_create(e->owner, str, NULL, NULL, true, &attr);
+		if (err != DOM_NO_ERR)
+			return err;
+
+		/* Set its value */
+		err = dom_attr_set_value(attr, value);
+		if (err != DOM_NO_ERR) {
+			dom_node_unref(attr);
+			return err;
+		}
+
+		added = _dom_hash_add(hs, str, attr, false);
+		if (added == false) {
+			/* If we failed at this step, there must be no memory */
+			dom_node_unref(attr);
+			return DOM_NO_MEM_ERR;
+		}
+
+		dom_node_set_parent(attr, element);
+		dom_node_unref(attr);
+		dom_node_remove_pending(attr);
+	}
+
+	return DOM_NO_ERR;
 }
 
 /**
- * Determine if an element has any attributes
+ * Remove an attribute from an element by name
  *
- * \param element  Element to inspect
- * \param result   Pointer to location to receive result
+ * \param element  The element to remove attribute from
+ * \param name     The name of the attribute to remove
+ * \return DOM_NO_ERR                      on success,
+ *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
+ */
+dom_exception _dom_element_remove_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name)
+{
+	void *a;
+	dom_exception err;
+	lwc_string *str;
+	dom_node_internal *e = (dom_node_internal *) element;
+
+	/* Ensure element can be written to */
+	if (_dom_node_readonly(e))
+		return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = (dom_node_internal *) _dom_hash_del(hs, str);
+
+	/* Detach attr node from list */
+	if (a != NULL) {
+		/* And destroy attr */
+		dom_node_set_parent(a, NULL);
+		dom_node_try_destroy(a);
+	}
+
+	/** \todo defaulted attribute handling */
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Retrieve an attribute node from an element by name
+ *
+ * \param element  The element to retrieve attribute node from
+ * \param name     The attribute's name
+ * \param result   Pointer to location to receive attribute node
  * \return DOM_NO_ERR.
+ *
+ * The returned node will have its reference count increased. It is
+ * the responsibility of the caller to unref the node once it has
+ * finished with it.
  */
-dom_exception dom_element_has_attributes(struct dom_element *element,
-		bool *result)
+dom_exception _dom_element_get_attr_node(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, 
+		struct dom_attr **result)
 {
-	*result = (element->attributes != NULL);
+	void *a;
+	dom_exception err;
+	lwc_string *str;
 
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = _dom_hash_get(hs, str);
+
+	/* Fill in value */
+	if (a == NULL) {
+		*result = NULL;
+	} else {
+		*result = (dom_attr *) a;
+		dom_node_ref(*result);
+	}
+
 	return DOM_NO_ERR;
 }
 
 /**
- * Retrieve a pointer to the first attribute attached to an element
+ * Set an attribute node on an element, replacing existing node, if present
  *
- * \param element  The element to retrieve the first attribute from
- * \return Pointer to first attribute, or NULL if none.
+ * \param element  The element to add a node to
+ * \param attr     The attribute node to add
+ * \param result   Pointer to location to receive previous node
+ * \return DOM_NO_ERR                      on success,
+ *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
+ *                                         same document as ::element,
+ *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
+ *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
+ *                                         of another Element node.
+ *
+ * The returned node will have its reference count increased. It is
+ * the responsibility of the caller to unref the node once it has
+ * finished with it.
  */
-struct dom_node_internal *dom_element_get_first_attribute(
-		struct dom_element *element)
+dom_exception _dom_element_set_attr_node(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_attr *attr, 
+		struct dom_attr **result)
 {
-	return (struct dom_node_internal *) element->attributes;
+	dom_exception err;
+	lwc_string *str = NULL;
+	dom_string *name = NULL;
+	bool added;
+	dom_node_internal *e = (dom_node_internal *) element;
+	dom_node_internal *a = (dom_node_internal *) attr;
+
+	/** \todo validate name */
+
+	/* Ensure element and attribute belong to the same document */
+	if (e->owner != a->owner)
+		return DOM_WRONG_DOCUMENT_ERR;
+
+	/* Ensure element can be written to */
+	if (_dom_node_readonly(e))
+		return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+	/* Ensure attribute isn't attached to another element */
+	if (a->parent != NULL && a->parent != e)
+		return DOM_INUSE_ATTRIBUTE_ERR;
+
+	err = dom_node_get_local_name(attr, &name);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = _dom_hash_del(hs, str);
+
+	*result = NULL;
+	if (a != NULL) {
+		dom_node_ref(a);
+		*result = (dom_attr *) a;
+		dom_node_set_parent(a, NULL);
+		dom_node_mark_pending(a);
+	}	
+
+	added = _dom_hash_add(hs, str, attr, false);
+	if (added == false) {
+		/* If we failed at this step, there must be no memory */
+		return DOM_NO_MEM_ERR;
+	}
+	dom_node_set_parent(attr, element);
+	dom_node_remove_pending(attr);
+
+	/* Cleanup */
+	if (name != NULL)
+		dom_string_unref(name);
+
+	return DOM_NO_ERR;
 }
 
+/**
+ * Remove an attribute node from an element
+ *
+ * \param element  The element to remove attribute node from
+ * \param attr     The attribute node to remove
+ * \param result   Pointer to location to receive attribute node
+ * \return DOM_NO_ERR                      on success,
+ *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
+ *         DOM_NOT_FOUND_ERR               if ::attr is not an attribute of
+ *                                         ::element.
+ *
+ * The returned node will have its reference count increased. It is
+ * the responsibility of the caller to unref the node once it has
+ * finished with it.
+ */
+dom_exception _dom_element_remove_attr_node(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_attr *attr, 
+		struct dom_attr **result)
+{
+	void *a;
+	dom_exception err;
+	lwc_string *str;
+	dom_string *name;
+	dom_node_internal *e = (dom_node_internal *) element;
+	
+	/* Ensure element can be written to */
+	if (_dom_node_readonly(e))
+		return DOM_NO_MODIFICATION_ALLOWED_ERR;
+	
+	err = dom_node_get_node_name(attr, &name);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = _dom_hash_del(hs, str);
+
+	/* Now, cleaup the dom_string and lwc_string */
+	dom_string_unref(name);
+	_dom_node_unref_intern_string(&element->base, str);
+
+	/** \todo defaulted attribute handling */
+
+	if (a == NULL || a != (void *) attr) {
+		return DOM_NOT_FOUND_ERR;
+	}
+
+	/* When a Node is removed, it should be destroy. When its refcnt is not 
+	 * zero, it will be added to the document's deletion pending list. 
+	 * When a Node is removed, its parent should be NULL, but its owner should 
+	 * remain to be the document.
+	 */
+	dom_node_ref(a);
+	*result = (dom_attr *) a;
+	dom_node_set_parent(a, NULL);
+	dom_node_mark_pending(a);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Test whether certain attribute is inside the hash table
+ *
+ * \param element	The element
+ * \param hs		The hash table contains the attributes
+ * \param name		The attribute's name
+ * \param result	The return value
+ */
+dom_exception _dom_element_has_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, bool *result)
+{
+	void *a;
+	dom_exception err;
+	lwc_string *str;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	a = _dom_hash_get(hs, str);
+
+	/* Fill in value */
+	if (a == NULL) {
+		*result = false;
+	} else {
+		*result = true;
+	}
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Set/Unset an attribute Node as a ID.
+ *
+ * \param element	The element contains the attribute
+ * \param hs		The hash table which contains the attribute node
+ * \param name		The name of the attribute
+ * \param is_id		true for set the node as a ID attribute, false unset it
+ */
+dom_exception _dom_element_set_id_attr(struct dom_element *element,
+		struct dom_hash_table *hs, struct dom_string *name, bool is_id)
+{
+	dom_attr *attr;
+	lwc_string *str;
+	dom_exception err;
+	struct dom_hash_table *oh;
+
+	/* looking for name */
+	err = _dom_node_get_intern_string(&element->base, name, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	attr = (dom_attr *) _dom_hash_get(hs, str);
+	if (attr == NULL)
+		return DOM_NOT_FOUND_ERR;
+	
+	if (is_id == true) {
+		/* Firstly, clear the previous id attribute if there is one */
+		if (element->id_ns != NULL) {
+			assert(element->id_name != NULL);
+			oh = (struct dom_hash_table *) _dom_hash_get(element->ns_attributes, 
+					element->id_ns);
+		} else {
+			oh = element->attributes;
+		}
+		assert(oh != NULL);
+
+		if (element->id_name != NULL) {
+			attr = (dom_attr *) _dom_hash_get(oh, element->id_name);
+			assert(attr != NULL);
+			_dom_attr_set_isid(attr, false);
+		}
+	}
+
+	_dom_attr_set_isid(attr, is_id);
+
+	element->id_name = str;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Get the ID string of the element
+ *
+ * \param ele		The element
+ * \param id		The ID of this element
+ */
+dom_exception _dom_element_get_id(struct dom_element *ele, lwc_string **id)
+{
+	dom_exception err;
+	dom_string *ret = NULL;
+
+	*id = NULL;
+
+	if (ele->id_ns != NULL && ele->id_name != NULL) {
+		/* There is user specific ID attribute */
+		dom_document *doc;
+		doc = dom_node_get_owner(ele);
+		assert(doc != NULL);
+
+		dom_string *namespace, *name;
+		err = _dom_document_create_string_from_lwcstring(doc, ele->id_ns,
+				&namespace);
+		if (err != DOM_NO_ERR)
+			return err;
+
+		err = _dom_document_create_string_from_lwcstring(doc, 
+				ele->id_name, &name);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(namespace);
+			return err;
+		}
+
+		err = _dom_element_get_attribute_ns(ele, namespace, name, &ret);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(namespace);
+			dom_string_unref(name);
+			return err;
+		}
+
+		dom_string_unref(namespace);
+		dom_string_unref(name);
+
+		err = _dom_node_get_intern_string((dom_node_internal *) ele, ret, id);
+		dom_string_unref(ret);
+		return err;
+	}
+
+	dom_document *doc;
+	doc = dom_node_get_owner(ele);
+	assert(doc != NULL);
+	dom_string *name;
+
+	if (ele->id_name != NULL) {
+		err = _dom_document_create_string_from_lwcstring(doc, 
+				ele->id_name, &name);
+		if (err != DOM_NO_ERR) {
+			return err;
+		}
+	} else {
+		lwc_string *id_name = _dom_document_get_id_name(doc);
+		if (id_name == NULL) {
+			/* No ID attribute at all, just return NULL */
+			*id = NULL;
+			return DOM_NO_ERR;
+		}
+		err = _dom_document_create_string_from_lwcstring(doc, id_name, &name);
+		if (err != DOM_NO_ERR) {
+			return err;
+		}
+	}
+
+	err = _dom_element_get_attribute(ele, name, &ret);
+	if (err != DOM_NO_ERR) {
+		dom_string_unref(name);
+		return err;
+	}
+
+	dom_string_unref(name);
+
+	if (ret != NULL) {
+		err = _dom_node_get_intern_string((dom_node_internal *) ele, ret, id);
+		dom_string_unref(ret);
+	} else {
+		*id = NULL;
+	}
+
+	return err;
+}
+
+
+/* The hash function for attributes and id tables */
+unsigned int _dom_element_hash_lwcstring(void *key)
+{
+	lwc_string *lstr = (lwc_string *) key;
+
+	return lwc_string_hash_value(lstr);
+}
+
+/* -------------- The dom_namednodemap functions ------------------------- */
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_get_length(void *priv,
+		unsigned long *length)
+{
+	unsigned int ret = 0;
+	unsigned int c1, *c2 = NULL;
+	void *key, *value;
+	dom_element *e = (dom_element *) priv;
+
+	ret += _dom_hash_get_length(e->attributes);
+	while( (key = _dom_hash_iterate(e->ns_attributes, &c1, &c2)) != NULL) {
+		value = _dom_hash_get(e->ns_attributes, key);
+		if (value != NULL) {
+			ret += _dom_hash_get_length((struct dom_hash_table *) value);
+		}
+	}
+
+	*length = ret;
+	return DOM_NO_ERR;
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_get_named_item(void *priv,
+		struct dom_string *name, struct dom_node **node)
+{
+	dom_element *e = (dom_element *) priv;
+
+	return _dom_element_get_attribute_node(e, name, (dom_attr **) node);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_set_named_item(void *priv,
+		struct dom_node *arg, struct dom_node **node)
+{
+	dom_element *e = (dom_element *) priv;
+	dom_node_internal *n = (dom_node_internal *) arg;
+
+	if (n->type != DOM_ATTRIBUTE_NODE)
+		return DOM_HIERARCHY_REQUEST_ERR;
+
+	return _dom_element_set_attribute_node(e, (dom_attr *) arg, (dom_attr **) node);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_remove_named_item(
+		void *priv, struct dom_string *name,
+		struct dom_node **node)
+{
+	dom_element *e = (dom_element *) priv;
+	dom_exception err;
+
+	err = _dom_element_get_attribute_node(e, name, (dom_attr **) node);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if (*node == NULL) {
+		return DOM_NOT_FOUND_ERR;
+	}
+	
+	return _dom_element_remove_attribute(e, name);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_item(void *priv,
+		unsigned long index, struct dom_node **node)
+{
+	struct dom_hash_table *ht = NULL;
+	unsigned int num = index + 1;
+	unsigned int len;
+	dom_element *e = (dom_element *) priv;
+	void *key, *value;
+	unsigned int c1, *c2 = NULL;
+
+	len = _dom_hash_get_length(e->attributes);
+	if (num <= len) {
+		ht = e->attributes;
+	} else {
+		num -= len;
+	}
+
+	while( (key = _dom_hash_iterate(e->ns_attributes, &c1, &c2)) != NULL) {
+		value = _dom_hash_get(e->ns_attributes, key);
+		if (value != NULL) {
+			len = _dom_hash_get_length((struct dom_hash_table *) value);
+			if (num <= len) {
+				ht = (struct dom_hash_table *) value;
+				break;
+			} else {
+				num -= len;
+			}
+		}
+	}
+
+	*node = NULL;
+	c2 = NULL;
+	if (ht != NULL)
+	{
+		while( (key = _dom_hash_iterate(ht, &c1, &c2)) != NULL) {
+			value = _dom_hash_get(ht, key);
+			if (--num == 0) {
+				*node = (dom_node *) value;
+				break;
+			}
+		}
+	}
+
+	if (*node != NULL)
+		dom_node_ref(*node);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_get_named_item_ns(
+		void *priv, struct dom_string *namespace,
+		struct dom_string *localname, struct dom_node **node)
+{
+	dom_element *e = (dom_element *) priv;
+
+	return _dom_element_get_attribute_node_ns(e, namespace, localname, (dom_attr **) node);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_set_named_item_ns(
+		void *priv, struct dom_node *arg,
+		struct dom_node **node)
+{
+	dom_element *e = (dom_element *) priv;
+	dom_node_internal *n = (dom_node_internal *) arg;
+
+	if (n->type != DOM_ATTRIBUTE_NODE)
+		return DOM_HIERARCHY_REQUEST_ERR;
+
+	return _dom_element_set_attribute_node_ns(e, (dom_attr *) arg, (dom_attr **) node);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+dom_exception attributes_remove_named_item_ns(
+		void *priv, struct dom_string *namespace,
+		struct dom_string *localname, struct dom_node **node)
+{
+	dom_element *e = (dom_element *) priv;
+	dom_exception err;
+	
+	err = _dom_element_get_attribute_node_ns(e, namespace, localname, (dom_attr **) node);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if (*node == NULL) {
+		return DOM_NOT_FOUND_ERR;
+	}
+
+	return _dom_element_remove_attribute_ns(e, namespace, localname);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+void attributes_destroy(void *priv)
+{
+	dom_element *e = (dom_element *) priv;
+
+	dom_node_unref(e);
+}
+
+/**
+ * Implementation function for NamedNodeMap, see core/namednodemap.h for details
+ */
+bool attributes_equal(void *p1, void *p2)
+{
+	/* We have passed the pointer to this element as the private data,
+	 * and here we just need to compare whether the two elements are 
+	 * equal
+	 */
+	return p1 == p2;
+}
+/* ------------------ End of namednodemap functions ----------------------- */
+
+/**
+ * The key_func of the hash table, see utils/hashtable.h for details
+ */
+void *_key(void *key, void *key_pw, dom_alloc alloc, void *pw, 
+		bool clone)
+{
+	assert(key != NULL);
+	assert(key_pw != NULL);
+
+	UNUSED(alloc);
+	UNUSED(pw);
+
+	if (clone == false) {
+		lwc_context_string_unref((lwc_context *) key_pw, (lwc_string *) key);
+		return NULL;
+	} else {
+		lwc_error err;
+		lwc_string *ret;
+		const char *data = lwc_string_data((lwc_string *) key);
+		size_t len = lwc_string_length((lwc_string *) key);
+		err = lwc_context_intern((lwc_context *) key_pw, data, len, &ret);
+		if (err != lwc_error_ok)
+			return NULL;
+
+		return ret;
+	}
+}
+
+/**
+ * The value_func of the hash table, see utils/hashtable.h for details
+ */
+void *_value(void *value, void *value_pw, dom_alloc alloc,
+		void *pw, bool clone)
+{
+	assert(value != NULL);
+	assert(value_pw != NULL);
+
+	UNUSED(alloc);
+	UNUSED(pw);
+	UNUSED(value_pw);
+
+	if (clone == false) {
+		dom_node_internal *a = (dom_node_internal *) value;
+		a->parent = NULL;
+		dom_node_try_destroy(a);
+		return NULL;
+	} else {
+		dom_exception err;
+		dom_node *node;
+
+		err = dom_document_import_node((dom_document *) value_pw, value, true, &node);
+		if (err != DOM_NO_ERR)
+			return NULL;
+
+		return node;
+	}
+}
+
+/**
+ * The value_func of the hash table, see utils/hashtable.h for details
+ */
+void *_nsattributes(void *value, void *value_pw, dom_alloc alloc,
+		void *pw, bool clone)
+{
+	assert(value != NULL);
+	assert(value_pw != NULL);
+
+	UNUSED(alloc);
+	UNUSED(pw);
+
+	if (clone == false) {
+		_dom_hash_destroy((struct dom_hash_table *) value, _key, value_pw, 
+				_value, value_pw);
+		return NULL;
+	} else {
+		dom_document *doc = (dom_document *) value_pw;
+		lwc_context *ctx = _dom_document_get_intern_context(doc);
+		assert(ctx != NULL);
+		dom_alloc alloc;
+		void *pw;
+		struct dom_hash_table *ret = NULL;
+		_dom_document_get_allocator(doc, &alloc, &pw);
+
+		ret = _dom_hash_clone((struct dom_hash_table *) value, alloc, pw,
+				_key, ctx, _value, doc);
+
+		return ret;
+	}
+}
Index: src/core/characterdata.h
===================================================================
--- src/core/characterdata.h	(revision 9058)
+++ src/core/characterdata.h	(working copy)
@@ -19,15 +19,17 @@
 	struct dom_node_internal base;		/**< Base node */
 };
 
-dom_characterdata *dom_characterdata_create(struct dom_document *doc);
-dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata,
+/* The CharacterData is a intermediate node type, so the following function
+ * may never be used */
+dom_characterdata *_dom_characterdata_create(struct dom_document *doc);
+dom_exception _dom_characterdata_initialise(struct dom_characterdata *cdata,
 		struct dom_document *doc, dom_node_type type,
-		struct dom_string *name, struct dom_string *value);
+		struct lwc_string_s *name, struct dom_string *value);
 
-void dom_characterdata_finalise(struct dom_document *doc,
+void _dom_characterdata_finalise(struct dom_document *doc,
 		struct dom_characterdata *cdata);
 
-/* The virtual functions for characterdata */
+/* The virtual functions for dom_characterdata */
 dom_exception _dom_characterdata_get_data(struct dom_characterdata *cdata,
 		struct dom_string **data);
 dom_exception _dom_characterdata_set_data(struct dom_characterdata *cdata,
@@ -57,4 +59,21 @@
 	_dom_characterdata_delete_data, \
 	_dom_characterdata_replace_data 
 
+/* Follwoing comes the protected vtable 
+ *
+ * Only the _copy function can be used by sub-class of this.
+ */
+void _dom_characterdata_destroy(struct dom_node_internal *node);
+dom_exception _dom_characterdata_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_characterdata_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_CHARACTERDATA_PROTECT_VTABLE \
+	_dom_characterdata_destroy, \
+	_dom_characterdata_alloc, \
+	_dom_characterdata_copy
+
+extern struct dom_characterdata_vtable characterdata_vtable;
+
 #endif
Index: src/core/Makefile
===================================================================
--- src/core/Makefile	(revision 9058)
+++ src/core/Makefile	(working copy)
@@ -1,8 +1,11 @@
 # Sources
-DIR_SOURCES := attr.c cdatasection.c characterdata.c comment.c \
-	document.c document_type.c doc_fragment.c \
-	element.c entity_ref.c implementation.c impllist.c \
-	namednodemap.c node.c nodelist.c \
-	pi.c string.c text.c
+DIR_SOURCES := \
+	string.c node.c \
+	attr.c characterdata.c element.c \
+	implementation.c impllist.c \
+	text.c typeinfo.c comment.c \
+	namednodemap.c nodelist.c \
+	cdatasection.c document_type.c entity_ref.c pi.c \
+	doc_fragment.c document.c 
 
 include build/makefiles/Makefile.subdir
Index: src/core/doc_fragment.h
===================================================================
--- src/core/doc_fragment.h	(revision 9058)
+++ src/core/doc_fragment.h	(working copy)
@@ -13,12 +13,30 @@
 struct dom_document_fragment;
 struct dom_document;
 struct dom_string;
+struct lwc_string_s;
 
-dom_exception dom_document_fragment_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_document_fragment_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_document_fragment **result);
 
-void dom_document_fragment_destroy(struct dom_document *doc,
+void _dom_document_fragment_destroy(struct dom_document *doc,
 		struct dom_document_fragment *frag);
 
+#define _dom_document_fragment_initialise	_dom_node_initialise
+#define _dom_document_fragment_finalise		_dom_node_finalise
+
+
+/* Following comes the protected vtable */
+void _dom_df_destroy(struct dom_node_internal *node);
+dom_exception _dom_df_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_df_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_DF_PROTECT_VTABLE \
+	_dom_df_destroy, \
+	_dom_df_alloc, \
+	_dom_df_copy
+
+
 #endif
Index: src/core/element.h
===================================================================
--- src/core/element.h	(revision 9058)
+++ src/core/element.h	(working copy)
@@ -19,6 +19,7 @@
 struct dom_string;
 struct dom_attr;
 struct dom_type_info;
+struct dom_hash_table;
 
 /**
  * DOM element node
@@ -26,33 +27,30 @@
 struct dom_element {
 	struct dom_node_internal base;		/**< Base node */
 
-	struct dom_attr *attributes;	/**< Element attributes */
+	struct dom_hash_table *attributes;	/**< Element attributes */
 
+	struct dom_hash_table *ns_attributes;	/**< Attributes with prefix */
+
+	struct lwc_string_s *id_ns;	/**< The id attribute's namespace */
+
+	struct lwc_string_s *id_name; 	/**< the id attribute's name */
+
 	struct dom_type_info *schema_type_info;	/**< Type information */
 };
 
-dom_exception dom_element_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *namespace,
-		struct dom_string *prefix, struct dom_element **result);
+dom_exception _dom_element_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct lwc_string_s *namespace,
+		struct lwc_string_s *prefix, struct dom_element **result);
 
-dom_exception dom_element_initialise(struct dom_element *el,
-		struct dom_string *name, struct dom_string *namespace,
-		struct dom_string *prefix, struct dom_element **result);
+dom_exception _dom_element_initialise(struct dom_element *el, 
+		struct dom_document *doc, struct lwc_string_s *name, 
+		struct lwc_string_s *namespace, struct lwc_string_s *prefix, 
+		struct dom_element **result);
 
-void dom_element_destroy(struct dom_document *doc,
+void _dom_element_destroy(struct dom_document *doc,
 		struct dom_element *element);
 
-void _dom_element_destroy(struct dom_node_internal *node);
 
-dom_exception dom_element_get_attributes(struct dom_element *element,
-		struct dom_namednodemap **result);
-
-dom_exception dom_element_has_attributes(struct dom_element *element,
-		bool *result);
-
-struct dom_node_internal *dom_element_get_first_attribute(
-		struct dom_element *element);
-
 /* The virtual functions of dom_element */
 dom_exception _dom_element_get_tag_name(struct dom_element *element,
 		struct dom_string **name);
@@ -123,4 +121,70 @@
 	_dom_element_set_id_attribute_ns, \
 	_dom_element_set_id_attribute_node
 
+/* Overloading dom_node functions */
+dom_exception _dom_element_get_attributes(dom_node_internal *node,
+		struct dom_namednodemap **result);
+dom_exception _dom_element_has_attributes(dom_node_internal *node, bool *result);
+dom_exception _dom_element_normalize(dom_node_internal *node);
+dom_exception _dom_element_lookup_prefix(dom_node_internal *node,
+		struct dom_string *namespace, struct dom_string **result);
+dom_exception _dom_element_is_default_namespace(dom_node_internal *node,
+		struct dom_string *namespace, bool *result);
+dom_exception _dom_element_lookup_namespace(dom_node_internal *node,
+		struct dom_string *prefix, struct dom_string **result);
+#define DOM_NODE_VTABLE_ELEMENT \
+	_dom_node_get_node_name, \
+	_dom_node_get_node_value, \
+	_dom_node_set_node_value, \
+	_dom_node_get_node_type, \
+	_dom_node_get_parent_node, \
+	_dom_node_get_child_nodes, \
+	_dom_node_get_first_child, \
+	_dom_node_get_last_child, \
+	_dom_node_get_previous_sibling, \
+	_dom_node_get_next_sibling, \
+	_dom_element_get_attributes, /*overload*/\
+	_dom_node_get_owner_document, \
+	_dom_node_insert_before, \
+	_dom_node_replace_child, \
+	_dom_node_remove_child, \
+	_dom_node_append_child, \
+	_dom_node_has_child_nodes, \
+	_dom_node_clone_node, \
+	_dom_node_normalize, \
+	_dom_node_is_supported, \
+	_dom_node_get_namespace, \
+	_dom_node_get_prefix, \
+	_dom_node_set_prefix, \
+	_dom_node_get_local_name, \
+	_dom_element_has_attributes, /*overload*/\
+	_dom_node_get_base, \
+	_dom_node_compare_document_position, \
+	_dom_node_get_text_content, \
+	_dom_node_set_text_content, \
+	_dom_node_is_same, \
+	_dom_element_lookup_prefix, /*overload*/\
+	_dom_element_is_default_namespace, /*overload*/\
+	_dom_element_lookup_namespace, /*overload*/\
+	_dom_node_is_equal, \
+	_dom_node_get_feature, \
+	_dom_node_set_user_data, \
+	_dom_node_get_user_data
+
+
+/* The protected virtual function */
+void __dom_element_destroy(dom_node_internal *node);
+dom_exception _dom_element_alloc(struct dom_document *doc, 
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_element_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_ELEMENT_PROTECT_VTABLE \
+	__dom_element_destroy, \
+	_dom_element_alloc, \
+	_dom_element_copy
+
+/* Helper functions*/
+dom_exception _dom_element_get_id(struct dom_element *ele, struct lwc_string_s **id);
+
 #endif
Index: src/core/cdatasection.c
===================================================================
--- src/core/cdatasection.c	(revision 9058)
+++ src/core/cdatasection.c	(working copy)
@@ -3,11 +3,13 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com> 
  */
 
 #include "core/cdatasection.h"
 #include "core/document.h"
 #include "core/text.h"
+#include "utils/utils.h"
 
 /**
  * A DOM CDATA section
@@ -16,6 +18,10 @@
 	struct dom_text base;		/**< Base node */
 };
 
+static struct dom_node_protect_vtable cdata_section_protect_vtable = {
+	DOM_CDATA_SECTION_PROTECT_VTABLE
+};
+
 /**
  * Create a CDATA section
  *
@@ -30,23 +36,27 @@
  *
  * The returned node will already be referenced.
  */
-dom_exception dom_cdata_section_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_cdata_section_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_cdata_section **result)
 {
 	struct dom_cdata_section *c;
 	dom_exception err;
 
 	/* Allocate the comment node */
-	c = dom_document_alloc(doc, NULL, sizeof(struct dom_cdata_section));
+	c = _dom_document_alloc(doc, NULL, sizeof(struct dom_cdata_section));
 	if (c == NULL)
 		return DOM_NO_MEM_ERR;
+	
+	/* Set up vtable */
+	((dom_node_internal *) c)->base.vtable = &text_vtable;
+	((dom_node_internal *) c)->vtable = &cdata_section_protect_vtable;
 
 	/* And initialise the node */
-	err = dom_text_initialise(&c->base, doc, DOM_CDATA_SECTION_NODE,
+	err = _dom_cdata_section_initialise(&c->base, doc, DOM_CDATA_SECTION_NODE,
 			name, value);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, c, 0);
+		_dom_document_alloc(doc, c, 0);
 		return err;
 	}
 
@@ -63,12 +73,56 @@
  *
  * The contents of ::cdata will be destroyed and ::cdata will be freed.
  */
-void dom_cdata_section_destroy(struct dom_document *doc,
+void _dom_cdata_section_destroy(struct dom_document *doc,
 		struct dom_cdata_section *cdata)
 {
 	/* Clean up base node contents */
-	dom_text_finalise(doc, &cdata->base);
+	_dom_cdata_section_finalise(doc, &cdata->base);
 
 	/* Destroy the node */
-	dom_document_alloc(doc, cdata, 0);
+	_dom_document_alloc(doc, cdata, 0);
 }
+
+/*--------------------------------------------------------------------------*/
+
+/* The protected virtual functions */
+
+/**
+ * The virtual destory function of this class
+ */
+void __dom_cdata_section_destroy(struct dom_node_internal *node)
+{
+	struct dom_document *doc;
+	doc = dom_node_get_owner(node);
+
+	_dom_cdata_section_destroy(doc, (struct dom_cdata_section *) node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_cdata_section_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	dom_cdata_section *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_cdata_section));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_cdata_section_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	return _dom_characterdata_copy(new, old);
+}
+
Index: src/core/cdatasection.h
===================================================================
--- src/core/cdatasection.h	(revision 9058)
+++ src/core/cdatasection.h	(working copy)
@@ -9,16 +9,35 @@
 #define dom_internal_core_cdatasection_h_
 
 #include <dom/core/exceptions.h>
+#include <dom/core/cdatasection.h>
 
+struct dom_node_internal;
 struct dom_cdata_section;
 struct dom_document;
 struct dom_string;
+struct lwc_string_s;
 
-dom_exception dom_cdata_section_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_cdata_section_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_cdata_section **result);
 
-void dom_cdata_section_destroy(struct dom_document *doc,
+void _dom_cdata_section_destroy(struct dom_document *doc,
 		struct dom_cdata_section *cdata);
 
+#define _dom_cdata_section_initialise 	_dom_text_initialise
+#define _dom_cdata_section_finalise	_dom_text_finalise
+
+/* Following comes the protected vtable  */
+void __dom_cdata_section_destroy(struct dom_node_internal *node);
+dom_exception _dom_cdata_section_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_cdata_section_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_CDATA_SECTION_PROTECT_VTABLE \
+	__dom_cdata_section_destroy, \
+	_dom_cdata_section_alloc, \
+	_dom_cdata_section_copy
+
+
 #endif
Index: src/core/entity_ref.c
===================================================================
--- src/core/entity_ref.c	(revision 9058)
+++ src/core/entity_ref.c	(working copy)
@@ -3,8 +3,11 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include "core/document.h"
 #include "core/entity_ref.h"
 #include "core/node.h"
@@ -17,6 +20,14 @@
 	struct dom_node_internal base;		/**< Base node */
 };
 
+static struct dom_node_vtable er_vtable = {
+	DOM_NODE_VTABLE
+};
+
+static struct dom_node_protect_vtable er_protect_vtable = {
+	DOM_ER_PROTECT_VTABLE
+};
+
 /**
  * Create an entity reference
  *
@@ -31,24 +42,27 @@
  *
  * The returned node will already be referenced.
  */
-dom_exception dom_entity_reference_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_entity_reference_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_entity_reference **result)
 {
 	struct dom_entity_reference *e;
 	dom_exception err;
 
 	/* Allocate the comment node */
-	e = dom_document_alloc(doc, NULL,
+	e = _dom_document_alloc(doc, NULL,
 			sizeof(struct dom_entity_reference));
 	if (e == NULL)
 		return DOM_NO_MEM_ERR;
 
+	e->base.base.vtable = &er_vtable;
+	e->base.vtable = &er_protect_vtable;
+
 	/* And initialise the node */
-	err = dom_node_initialise(&e->base, doc, DOM_ENTITY_REFERENCE_NODE,
-			name, value, NULL, NULL);
+	err = _dom_entity_reference_initialise(&e->base, doc, 
+			DOM_ENTITY_REFERENCE_NODE, name, value, NULL, NULL);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, e, 0);
+		_dom_document_alloc(doc, e, 0);
 		return err;
 	}
 
@@ -65,52 +79,28 @@
  *
  * The contents of ::entity will be destroyed and ::entity will be freed.
  */
-void dom_entity_reference_destroy(struct dom_document *doc,
+void _dom_entity_reference_destroy(struct dom_document *doc,
 		struct dom_entity_reference *entity)
 {
-	struct dom_node_internal *c, *d;
-
-	/* Destroy children of this node */
-	for (c = entity->base.first_child; c != NULL; c = d) {
-		d = c->next;
-
-		/* Detach child */
-		c->parent = NULL;
-
-		if (c->refcnt > 0) {
-			/* Something is using this child */
-
-			/** \todo add to list of nodes pending deletion */
-
-			continue;
-		}
-
-		/* Detach from sibling list */
-		c->previous = NULL;
-		c->next = NULL;
-
-		dom_node_destroy(c);
-	}
-
 	/* Finalise base class */
-	dom_node_finalise(doc, &entity->base);
+	_dom_entity_reference_finalise(doc, &entity->base);
 
 	/* Destroy fragment */
-	dom_document_alloc(doc, entity, 0);
+	_dom_document_alloc(doc, entity, 0);
 }
 
 /**
- * Get the textual representation of an EntityReference
+ * Get the textual representation of an EntityRererence
  *
  * \param entity  The entity reference to get the textual representation of
  * \param result  Pointer to location to receive result
  * \return DOM_NO_ERR on success.
  *
  * The returned string will have its reference count increased. It is
- * the responsibility of the caller to unref the string once it has
+ * the responsibility of the caller to unrer the string once it has
  * finished with it.
  */
-dom_exception dom_entity_reference_get_textual_representation(
+dom_exception _dom_entity_reference_get_textual_representation(
 		struct dom_entity_reference *entity, struct dom_string **result)
 {
 	UNUSED(entity);
@@ -119,3 +109,45 @@
 	return DOM_NOT_SUPPORTED_ERR;
 }
 
+/*-----------------------------------------------------------------------*/
+
+/* Following comes the protected vtable  */
+
+/**
+ * The virtual destroy function of this class
+ */
+void _dom_er_destroy(struct dom_node_internal *node)
+{
+	_dom_entity_reference_destroy(node->owner, 
+			(struct dom_entity_reference *) node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_er_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	dom_entity_reference *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_entity_reference));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+	
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_er_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	return _dom_node_copy(new, old);
+}
+
Index: src/core/pi.c
===================================================================
--- src/core/pi.c	(revision 9058)
+++ src/core/pi.c	(working copy)
@@ -9,6 +9,8 @@
 #include "core/node.h"
 #include "core/pi.h"
 
+#include "utils/utils.h"
+
 /**
  * A DOM processing instruction
  */
@@ -16,6 +18,13 @@
 	struct dom_node_internal base;		/**< Base node */
 };
 
+static struct dom_node_vtable pi_vtable = {
+	DOM_NODE_VTABLE
+};
+
+static struct dom_node_protect_vtable pi_protect_vtable = {
+	DOM_PI_PROTECT_VTABLE
+};
 /**
  * Create a processing instruction
  *
@@ -30,25 +39,28 @@
  *
  * The returned node will already be referenced.
  */
-dom_exception dom_processing_instruction_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_processing_instruction_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_processing_instruction **result)
 {
 	struct dom_processing_instruction *p;
 	dom_exception err;
 
 	/* Allocate the comment node */
-	p = dom_document_alloc(doc, NULL,
+	p = _dom_document_alloc(doc, NULL,
 			sizeof(struct dom_processing_instruction));
 	if (p == NULL)
 		return DOM_NO_MEM_ERR;
+	
+	p->base.base.vtable = &pi_vtable;
+	p->base.vtable = &pi_protect_vtable;
 
 	/* And initialise the node */
-	err = dom_node_initialise(&p->base, doc,
+	err = _dom_processing_instruction_initialise(&p->base, doc,
 			DOM_PROCESSING_INSTRUCTION_NODE,
 			name, value, NULL, NULL);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, p, 0);
+		_dom_document_alloc(doc, p, 0);
 		return err;
 	}
 
@@ -65,12 +77,53 @@
  *
  * The contents of ::pi will be destroyed and ::pi will be freed.
  */
-void dom_processing_instruction_destroy(struct dom_document *doc,
+void _dom_processing_instruction_destroy(struct dom_document *doc,
 		struct dom_processing_instruction *pi)
 {
 	/* Finalise base class */
-	dom_node_finalise(doc, &pi->base);
+	_dom_processing_instruction_finalise(doc, &pi->base);
 
 	/* Free processing instruction */
-	dom_document_alloc(doc, pi, 0);
+	_dom_document_alloc(doc, pi, 0);
 }
+
+/*-----------------------------------------------------------------------*/
+
+/* Following comes the protected vtable  */
+
+/**
+ * The virtual destory function of this class
+ */
+void _dom_pi_destroy(struct dom_node_internal *node)
+{
+	_dom_processing_instruction_destroy(node->owner, 
+			(struct dom_processing_instruction *) node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_pi_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	struct dom_processing_instruction *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_processing_instruction));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_pi_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	return _dom_node_copy(new, old);
+}
Index: src/core/attr.c
===================================================================
--- src/core/attr.c	(revision 9058)
+++ src/core/attr.c	(working copy)
@@ -3,10 +3,12 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
 #include <stddef.h>
 #include <string.h>
+#include <assert.h>
 
 #include <dom/core/attr.h>
 #include <dom/core/document.h>
@@ -27,22 +29,32 @@
 struct dom_attr {
 	struct dom_node_internal base;		/**< Base node */
 
-	bool specified;			/**< Whether attribute was specified
-					 * or defaulted */
+	bool specified;			/**< Whether the attribute is specified
+							 * or default */
 
 	struct dom_type_info *schema_type_info;	/**< Type information */
 
-	bool is_id;			/**< Attribute is of type ID */
+	bool is_id;			/**< Whether this attribute is a ID attribute */
 };
 
-/* The vtable for dom attr node */
+/* The vtable for dom_attr node */
 static struct dom_attr_vtable attr_vtable = {
 	{
-		DOM_NODE_VTABLE
+		DOM_NODE_VTABLE_ATTR
 	},
 	DOM_ATTR_VTABLE
 };
 
+/* The protected vtable for dom_attr */
+static struct dom_node_protect_vtable attr_protect_vtable = {
+	DOM_ATTR_PROTECT_VTABLE
+};
+
+
+/* -------------------------------------------------------------------- */
+
+/* Constructor and destructor */
+
 /**
  * Create an attribute node
  *
@@ -50,6 +62,7 @@
  * \param name       The (local) name of the node to create
  * \param namespace  The namespace URI of the attribute, or NULL
  * \param prefix     The namespace prefix of the attribute, or NULL
+ * \param specified  Whtether this attribute is specified
  * \param result     Pointer to location to receive created attribute
  * \return DOM_NO_ERR                on success,
  *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
@@ -59,9 +72,10 @@
  *
  * The returned attribute will already be referenced.
  */
-dom_exception dom_attr_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *namespace,
-		struct dom_string *prefix, struct dom_attr **result)
+dom_exception _dom_attr_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct lwc_string_s *namespace,
+		struct lwc_string_s *prefix, bool specified, 
+		struct dom_attr **result)
 {
 	struct dom_attr *a;
 	dom_exception err;
@@ -69,24 +83,50 @@
 	/** \todo Sanity check the attribute name */
 
 	/* Allocate the element */
-	a = dom_document_alloc(doc, NULL, sizeof(struct dom_attr));
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_attr));
 	if (a == NULL)
 		return DOM_NO_MEM_ERR;
 
 	/* Initialise the vtable */
 	a->base.base.vtable = &attr_vtable;
-	a->base.destroy = _dom_attr_destroy;
+	a->base.vtable = &attr_protect_vtable;
 
-	/* Initialise the base class */
-	err = dom_node_initialise(&a->base, doc, DOM_ATTRIBUTE_NODE,
+	/* Initialise the class */
+	err = _dom_attr_initialise(a, doc, name, namespace, prefix, specified, 
+			result);
+	if (err != DOM_NO_ERR) {
+		_dom_document_alloc(doc, a, 0);
+		return err;
+	}
+	return DOM_NO_ERR;
+}
+
+/**
+ * Initialis a dom_attr
+ *
+ * \param a		The dom_attr
+ * \param doc	The document
+ * \param name	The name of this attribute node
+ * \param namespace	The namespace of this attribute
+ * \param prefix	The prefix
+ * \param specified	Whether this node is a specified one
+ * \param result	The returned node
+ */
+dom_exception _dom_attr_initialise(dom_attr *a, 
+		struct dom_document *doc,  struct lwc_string_s *name,
+		struct lwc_string_s *namespace, struct lwc_string_s *prefix,
+		bool specified, struct dom_attr **result)
+{
+	dom_exception err;
+
+	err = _dom_node_initialise(&a->base, doc, DOM_ATTRIBUTE_NODE,
 			name, NULL, namespace, prefix);
 	if (err != DOM_NO_ERR) {
-		dom_document_alloc(doc, a, 0);
 		return err;
 	}
 
 	/* Perform our type-specific initialisation */
-	a->specified = false;
+	a->specified = specified;
 	a->schema_type_info = NULL;
 	a->is_id = false;
 
@@ -96,55 +136,42 @@
 }
 
 /**
- * Destroy an attribute node
+ * The destructor of dom_attr
  *
- * \param doc   The owning document
- * \param attr  The attribute to destroy
- *
- * The contents of ::attr will be destroyed and ::attr will be freed
+ * \param doc	The owner document
+ * \param attr	The attribute
  */
-void dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr)
+void _dom_attr_finalise(dom_document *doc, dom_attr *attr)
 {
-	struct dom_node_internal *c, *d;
-
-	/* Destroy children of this node */
-	for (c = attr->base.first_child; c != NULL; c = d) {
-		d = c->next;
-
-		/* Detach child */
-		c->parent = NULL;
-
-		if (c->refcnt > 0) {
-			/* Something is using this child */
-
-			/** \todo add to list of nodes pending deletion */
-
-			continue;
-		}
-
-		/* Detach from sibling list */
-		c->previous = NULL;
-		c->next = NULL;
-
-		dom_node_destroy(c);
-	}
-
 	/* Now, clean up this node and destroy it */
 
 	if (attr->schema_type_info != NULL) {
 		/** \todo destroy schema type info */
 	}
 
-	dom_node_finalise(doc, &attr->base);
-
-	dom_document_alloc(doc, attr, 0);
+	_dom_node_finalise(doc, &attr->base);
 }
 
-void _dom_attr_destroy(dom_node_internal *node)
+/**
+ * Destroy an attribute node
+ *
+ * \param doc   The owning document
+ * \param attr  The attribute to destroy
+ *
+ * The contents of ::attr will be destroyed and ::attr will be freed
+ */
+void _dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr)
 {
-	UNUSED(node);
+	_dom_attr_finalise(doc, attr);
+
+	_dom_document_alloc(doc, attr, 0);
 }
 
+
+/* -------------------------------------------------------------------- */
+
+/* The public virtual functions */
+
 /**
  * Retrieve an attribute's name
  *
@@ -164,7 +191,7 @@
 }
 
 /**
- * Determine if attribute was specified or defaulted
+ * Determine if attribute was specified or default
  *
  * \param attr    Attribute to inspect
  * \param result  Pointer to location to receive result
@@ -196,8 +223,8 @@
 	struct dom_string *value, *temp;
 	dom_exception err;
 
-	err = dom_document_create_string(a->owner, 
-			(const uint8_t *) "", SLEN(""), &value);
+	err = _dom_document_create_string(a->owner, 
+			NULL, 0, &value);
 	if (err != DOM_NO_ERR) {
 		return err;
 	}
@@ -221,7 +248,7 @@
 			struct dom_string *tr;
 
 			/* Get textual representation of entity */
-			err = dom_entity_reference_get_textual_representation(
+			err = _dom_entity_reference_get_textual_representation(
 					(struct dom_entity_reference *) c,
 					&tr);
 			if (err != DOM_NO_ERR) {
@@ -285,25 +312,22 @@
 		/* Detach child */
 		c->parent = NULL;
 
-		if (c->refcnt > 0) {
-			/* Something is using this child */
-
-			/** \todo add to list of nodes pending deletion */
-
-			continue;
-		}
-
 		/* Detach from sibling list */
 		c->previous = NULL;
 		c->next = NULL;
 
-		dom_node_destroy(c);
+		dom_node_try_destroy(c);
 	}
 
 	/* And insert the text node as the value */
 	((struct dom_node_internal *) text)->parent = a;
 	a->first_child = a->last_child = (struct dom_node_internal *) text;
+	dom_node_unref(text);
+	dom_node_remove_pending(text);
 
+	/* Now the attribute node is specified */
+	attr->specified = true;
+
 	return DOM_NO_ERR;
 }
 
@@ -363,3 +387,196 @@
 
 	return DOM_NO_ERR;
 }
+
+/*------------- The overload virtual functions ------------------------*/
+
+/**
+ * Overload function of Node, please refer node.c for the detail of this 
+ * function.
+ */
+dom_exception _dom_attr_get_node_value(dom_node_internal *node,
+		struct dom_string **result)
+{
+	dom_attr *attr = (dom_attr *) node;
+
+	return _dom_attr_get_value(attr, result);
+}
+
+/**
+ * Overload function of Node, please refer node.c for the detail of this 
+ * function.
+ */
+dom_exception _dom_attr_clone_node(dom_node_internal *node, bool deep,
+		dom_node_internal **result)
+{
+	dom_exception err;
+	dom_attr *attr;
+
+	/* Discard the warnings */
+	UNUSED(deep);
+
+	/* Clone an Attr always clone all its children */
+	err = _dom_node_clone_node(node, true, result);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	attr = (dom_attr *) *result;
+	/* Clone an Attr always result a specified Attr, 
+	 * see DOM Level 3 Node.cloneNode */
+	attr->specified = true;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Overload function of Node, please refer node.c for the detail of this 
+ * function.
+ */
+dom_exception _dom_attr_set_prefix(dom_node_internal *node,
+		struct dom_string *prefix)
+{
+	/* Really I don't know whether there should something
+	 * special to do here */
+	return _dom_node_set_prefix(node, prefix);
+}
+
+/**
+ * Overload function of Node, please refer node.c for the detail of this 
+ * function.
+ */
+dom_exception _dom_attr_lookup_prefix(dom_node_internal *node,
+		struct dom_string *namespace, struct dom_string **result)
+{
+	struct dom_element *owner;
+	dom_exception err;
+
+	err = dom_attr_get_owner_element(node, &owner);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (owner == NULL) {
+		*result = NULL;
+		return DOM_NO_ERR;
+	}
+
+	return dom_node_lookup_prefix(owner, namespace, result);
+}
+
+/**
+ * Overload function of Node, please refer node.c for the detail of this 
+ * function.
+ */
+dom_exception _dom_attr_is_default_namespace(dom_node_internal *node,
+		struct dom_string *namespace, bool *result)
+{
+	struct dom_element *owner;
+	dom_exception err;
+
+	err = dom_attr_get_owner_element(node, &owner);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (owner == NULL) {
+		*result = false;
+		return DOM_NO_ERR;
+	}
+
+	return dom_node_is_default_namespace(owner, namespace, result);
+}
+
+/**
+ * Overload function of Node, please refer node.c for the detail of this 
+ * function.
+ */
+dom_exception _dom_attr_lookup_namespace(dom_node_internal *node,
+		struct dom_string *prefix, struct dom_string **result)
+{
+	struct dom_element *owner;
+	dom_exception err;
+
+	err = dom_attr_get_owner_element(node, &owner);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	if (owner == NULL) {
+		*result = NULL;
+		return DOM_NO_ERR;
+	}
+
+	return dom_node_lookup_namespace(owner, prefix, result);
+}
+
+
+/*----------------------------------------------------------------------*/
+
+/* The protected virtual functions */
+
+/**
+ * The virtual destroy function of this class
+ */
+void __dom_attr_destroy(dom_node_internal *node)
+{
+	dom_document *doc = node->owner;
+
+	assert(doc != NULL);
+	_dom_attr_destroy(doc, (dom_attr *) node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_attr_alloc(struct dom_document *doc, 
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	dom_attr *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_attr));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_attr_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	dom_attr *na = (dom_attr *) new;
+	dom_attr *oa = (dom_attr *) old;
+
+	na->specified = oa->specified;
+	na->is_id = oa->is_id;
+
+	/* TODO: deal with dom_type_info, it get no definition ! */
+
+	return _dom_node_copy(new, old);
+}
+
+
+/**
+ * Set/Unset whether this attribute is a ID attribute 
+ *
+ * \param attr		The attribute
+ * \param is_id		Whether it is a ID attribute
+ */
+void _dom_attr_set_isid(struct dom_attr *attr, bool is_id)
+{
+	attr->is_id = is_id;
+}
+
+/**
+ * Set/Unset whether the attribute is a specified one.
+ *
+ * \param attr	The attribute node
+ * \param specified	Whether this attribute is a specified one
+ */
+void _dom_attr_set_specified(struct dom_attr *attr, bool specified)
+{
+	attr->specified = specified;
+}
Index: src/core/entity_ref.h
===================================================================
--- src/core/entity_ref.h	(revision 9058)
+++ src/core/entity_ref.h	(working copy)
@@ -5,23 +5,42 @@
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
  */
 
-#ifndef dom_internal_core_entityreference_h_
-#define dom_internal_core_entityreference_h_
+#ifndef dom_internal_core_entityrererence_h_
+#define dom_internal_core_entityrererence_h_
 
 #include <dom/core/exceptions.h>
+#include <dom/core/entity_ref.h>
 
 struct dom_document;
 struct dom_entity_reference;
 struct dom_string;
+struct lwc_string_s;
 
-dom_exception dom_entity_reference_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_entity_reference_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_entity_reference **result);
 
-void dom_entity_reference_destroy(struct dom_document *doc,
+void _dom_entity_reference_destroy(struct dom_document *doc,
 		struct dom_entity_reference *entity);
 
-dom_exception dom_entity_reference_get_textual_representation(
+#define _dom_entity_reference_initialise _dom_node_initialise
+#define _dom_entity_reference_finalise	_dom_node_finalise
+
+/* Following comes the protected vtable  */
+void _dom_er_destroy(struct dom_node_internal *node);
+dom_exception _dom_er_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_er_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_ER_PROTECT_VTABLE \
+	_dom_er_destroy, \
+	_dom_er_alloc, \
+	_dom_er_copy
+
+/* Helper functions */
+dom_exception _dom_entity_reference_get_textual_representation(
 		struct dom_entity_reference *entity,
 		struct dom_string **result);
+
 #endif
Index: src/core/pi.h
===================================================================
--- src/core/pi.h	(revision 9058)
+++ src/core/pi.h	(working copy)
@@ -13,12 +13,28 @@
 struct dom_document;
 struct dom_processing_instruction;
 struct dom_string;
+struct lwc_string_s;
 
-dom_exception dom_processing_instruction_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *value,
+dom_exception _dom_processing_instruction_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct dom_string *value,
 		struct dom_processing_instruction **result);
 
-void dom_processing_instruction_destroy(struct dom_document *doc,
+void _dom_processing_instruction_destroy(struct dom_document *doc,
 		struct dom_processing_instruction *pi);
 
+#define _dom_processing_instruction_initialise	_dom_node_initialise
+#define _dom_processing_instruction_finalise 	_dom_node_finalise
+
+/* Following comes the protected vtable  */
+void _dom_pi_destroy(struct dom_node_internal *node);
+dom_exception _dom_pi_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_pi_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_PI_PROTECT_VTABLE \
+	_dom_pi_destroy, \
+	_dom_pi_alloc, \
+	_dom_pi_copy
+
 #endif
Index: src/core/document.c
===================================================================
--- src/core/document.c	(revision 9058)
+++ src/core/document.c	(working copy)
@@ -3,16 +3,21 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
-#include <string.h>
+#include <assert.h>
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include <dom/functypes.h>
 #include <dom/bootstrap/implpriv.h>
+#include <dom/core/attr.h>
+#include <dom/core/element.h>
 #include <dom/core/document.h>
 #include <dom/core/implementation.h>
-#include <dom/core/string.h>
 
+#include "core/string.h"
 #include "core/attr.h"
 #include "core/cdatasection.h"
 #include "core/comment.h"
@@ -24,6 +29,7 @@
 #include "core/nodelist.h"
 #include "core/pi.h"
 #include "core/text.h"
+#include "utils/validate.h"
 #include "utils/namespace.h"
 #include "utils/utils.h"
 
@@ -37,21 +43,6 @@
 	struct dom_doc_nl *prev;	/**< Previous item */
 };
 
-/**
- * Item in list of active namednodemaps
- */
-struct dom_doc_nnm {
-	struct dom_namednodemap *map;	/**< Named node map */
-
-	struct dom_doc_nnm *next;	/**< Next map */
-	struct dom_doc_nnm *prev;	/**< Previous map */
-};
-
-
-/** Interned node name strings, indexed by node type */
-/* Index 0 is unused */
-static struct dom_string *__nodenames_utf8[DOM_NODE_TYPE_COUNT + 1];
-
 /* The virtual functions of this dom_document */
 static struct dom_document_vtable document_vtable = {
 	{
@@ -60,77 +51,23 @@
 	DOM_DOCUMENT_VTABLE
 };
 
-/**
- * Initialise the document module
- *
- * \param alloc  Memory (de)allocation function
- * \param pw     Pointer to client-specific private data
- * \return DOM_NO_ERR on success
- */
-dom_exception _dom_document_initialise(dom_alloc alloc, void *pw)
-{
-	static struct {
-		const char *name;
-		size_t len;
-	} names_utf8[DOM_NODE_TYPE_COUNT + 1] = {
-		{ NULL,			0 },	/* Unused */
-		{ NULL,			0 },	/* Element */
-		{ NULL,			0 },	/* Attr */
-		{ "#text",		5 },	/* Text */
-		{ "#cdata-section",	14 },	/* CDATA section */
-		{ NULL,			0 },	/* Entity reference */
-		{ NULL,			0 },	/* Entity */
-		{ NULL,			0 },	/* Processing instruction */
-		{ "#comment",		8 },	/* Comment */
-		{ "#document",		9 },	/* Document */
-		{ NULL,			0 },	/* Document type */
-		{ "#document-fragment",	18 },	/* Document fragment */
-		{ NULL,			0 }	/* Notation */
-	};
-	dom_exception err;
+static struct dom_node_protect_vtable document_protect_vtable = {
+	DOM_DOCUMENT_PROTECT_VTABLE
+};
 
-	/* Initialise interned node names */
-	for (int i = 0; i <= DOM_NODE_TYPE_COUNT; i++) {
-		if (names_utf8[i].name == NULL) {
-			/* Nothing to intern; skip this entry */
-			__nodenames_utf8[i] = NULL;
-			continue;
-		}
 
-		/* Make string */
-		err = dom_string_create(alloc, pw,
-				(const uint8_t *) names_utf8[i].name,
-				names_utf8[i].len, &__nodenames_utf8[i]);
-		if (err != DOM_NO_ERR) {
-			/* Failed, clean up strings we've created so far */
-			for (int j = 0; j < i; j++) {
-				if (__nodenames_utf8[j] != NULL) {
-					dom_string_unref(__nodenames_utf8[j]);
-				}
-			}
-			return err;
-		}
-	}
+/*----------------------------------------------------------------------*/
 
-	return DOM_NO_ERR;
-}
+/* Intetnally used helper functions */
+static dom_exception dom_document_dup_node(dom_document *doc, 
+		struct dom_node *node, bool deep, struct dom_node **result, 
+		dom_node_operation opt);
 
-/**
- * Finalise the document module
- *
- * \return DOM_NO_ERR.
- */
-dom_exception _dom_document_finalise(void)
-{
-	for (int i = 0; i <= DOM_NODE_TYPE_COUNT; i++) {
-		if (__nodenames_utf8[i] != NULL) {
-			dom_string_unref(__nodenames_utf8[i]);
-		}
-	}
 
-	return DOM_NO_ERR;
-}
+/*----------------------------------------------------------------------*/
 
+/* The constructors and destructors */
+
 /**
  * Create a Document
  *
@@ -138,6 +75,7 @@
  * \param alloc    Memory (de)allocation function
  * \param pw       Pointer to client-specific private data
  * \param doc      Pointer to location to receive created document
+ * \param ctx	   The intern string context of this document
  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
  *
  * ::impl will have its reference count increased.
@@ -145,7 +83,8 @@
  * The returned document will already be referenced.
  */
 dom_exception dom_document_create(struct dom_implementation *impl,
-		dom_alloc alloc, void *pw, struct dom_document **doc)
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document **doc)
 {
 	struct dom_document *d;
 	dom_exception err;
@@ -155,103 +94,108 @@
 	if (d == NULL)
 		return DOM_NO_MEM_ERR;
 
-	/* Set up document allocation context - must be first */
-	d->alloc = alloc;
-	d->pw = pw;
-
 	/* Initialise the virtual table */
 	d->base.base.vtable = &document_vtable;
-	d->base.destroy = &dom_document_destroy;
+	d->base.vtable = &document_protect_vtable;
 
 	/* Initialise base class -- the Document has no parent, so
 	 * destruction will be attempted as soon as its reference count
 	 * reaches zero. Documents own themselves (this simplifies the 
 	 * rest of the code, as it doesn't need to special case Documents)
 	 */
-	err = dom_node_initialise(&d->base, d, DOM_DOCUMENT_NODE,
-			NULL, NULL, NULL, NULL);
+	err = _dom_document_initialise(d, impl, alloc, pw, ctx);
 	if (err != DOM_NO_ERR) {
 		/* Clean up document */
 		alloc(d, 0, pw);
 		return err;
 	}
 
-	/* Initialise remaining type-specific data */
-	if (impl != NULL)
-		dom_implementation_ref(impl);
-	d->impl = impl;
-
-	d->nodelists = NULL;
-	d->maps = NULL;
-
-	d->nodenames = __nodenames_utf8;
-
 	*doc = d;
 
 	return DOM_NO_ERR;
 }
 
-/**
- * Destroy a document
- *
- * \param doc  The document to destroy, which is passed in as a
- * 
- * dom_node_internl
- *
- * The contents of ::doc will be destroyed and ::doc will be freed.
- */
-void dom_document_destroy(struct dom_node_internal *dnode)
+/* Initialise the document */
+dom_exception _dom_document_initialise(struct dom_document *doc, 
+		struct dom_implementation *impl, dom_alloc alloc, void *pw, 
+		struct lwc_context_s *ctx)
 {
-	struct dom_document *doc = (struct dom_document *) dnode;
-	struct dom_node_internal *c, *d;
+	assert(ctx != NULL);
+	assert(alloc != NULL);
+	assert(impl != NULL);
 
-	/* Destroy children of this node */
-	for (c = doc->base.first_child; c != NULL; c = d) {
-		d = c->next;
+	dom_exception err;
+	lwc_string *name;
+	lwc_error lerr;
+	
+	lerr = lwc_context_intern(ctx, "#document", SLEN("#document"), &name);
+	if (lerr != lwc_error_ok)
+		return _dom_exception_from_lwc_error(lerr);
 
-		/* Detach child */
-		c->parent = NULL;
+	dom_implementation_ref(impl);
+	doc->impl = impl;
 
-		if (c->refcnt > 0) {
-			/* Something is using this child */
+	doc->nodelists = NULL;
 
-			/** \todo add to list of nodes pending deletion */
+	/* Set up document allocation context - must be first */
+	doc->alloc = alloc;
+	doc->pw = pw;
+	doc->context = lwc_context_ref(ctx);
 
-			continue;
-		}
+	err = _dom_node_initialise(&doc->base, doc, DOM_DOCUMENT_NODE,
+			name, NULL, NULL, NULL);
+	lwc_context_string_unref(ctx, name);
 
-		/* Detach from sibling list */
-		c->previous = NULL;
-		c->next = NULL;
+	list_init(&doc->pending_nodes);
 
-		dom_node_destroy(c);
-	}
+	doc->id_name = NULL;
 
-	/** \todo Ensure list of nodes pending deletion is empty. If not,
+	return err;
+}
+
+
+/* Finalise the document */
+bool _dom_document_finalise(struct dom_document *doc)
+{
+	/* Finalise base class, delete the tree in force */
+	_dom_node_finalise(doc, &doc->base);
+
+	/* Now, the first_child and last_child should be null */
+	doc->base.first_child = NULL;
+	doc->base.last_child = NULL;
+
+	/**
+	 * Ensure list of nodes pending deletion is empty. If not,
 	 * then we can't yet destroy the document (its destruction will
 	 * have to wait until the pending nodes are destroyed) */
+	if (doc->pending_nodes.next != &doc->pending_nodes)
+		return false;
 
 	/* Ok, the document tree is empty, as is the list of nodes pending
 	 * deletion. Therefore, it is safe to destroy the document. */
-
 	if (doc->impl != NULL)
 		dom_implementation_unref(doc->impl);
 	doc->impl = NULL;
 
-	/* This is paranoia -- if there are any remaining nodelists or
-	 * namednodemaps, then the document's reference count will be
+	/* This is paranoia -- if there are any remaining nodelists,
+	 * then the document's reference count will be
 	 * non-zero as these data structures reference the document because
 	 * they are held by the client. */
 	doc->nodelists = NULL;
-	doc->maps = NULL;
 
-	/* Finalise base class */
-	dom_node_finalise(doc, &doc->base);
+	if (doc->id_name != NULL)
+		lwc_context_string_unref(doc->context, doc->id_name);
+	lwc_context_unref(doc->context);
 
-	/* Free document */
-	doc->alloc(doc, 0, doc->pw);
+	return true;
 }
 
+
+
+/*----------------------------------------------------------------------*/
+
+/* Public virtual functions */
+
 /**
  * Retrieve the doctype of a document
  *
@@ -319,7 +263,7 @@
 {
 	struct dom_node_internal *root;
 
-	/* Find first element node in child list */
+	/* Find the first element node in child list */
 	for (root = doc->base.first_child; root != NULL; root = root->next) {
 		if (root->type == DOM_ELEMENT_NODE)
 			break;
@@ -351,7 +295,21 @@
 dom_exception _dom_document_create_element(struct dom_document *doc,
 		struct dom_string *tag_name, struct dom_element **result)
 {
-	return dom_element_create(doc, tag_name, NULL, NULL, result);
+	lwc_string *name;
+	dom_exception err;
+
+	if (_dom_validate_name(tag_name) == false)
+		return DOM_INVALID_CHARACTER_ERR;
+
+	assert(doc->context != NULL);
+	err = _dom_string_intern(tag_name, doc->context, &name);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = _dom_element_create(doc, name, NULL, NULL, result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -368,9 +326,21 @@
 dom_exception _dom_document_create_document_fragment(struct dom_document *doc,
 		struct dom_document_fragment **result)
 {
-	return dom_document_fragment_create(doc,
-			doc->nodenames[DOM_DOCUMENT_FRAGMENT_NODE],
-			NULL, result);
+	lwc_string *name;
+	dom_exception err;
+	lwc_error lerr;
+
+	assert(doc->context != NULL);
+
+	lerr = lwc_context_intern(doc->context, "#document-fragment", 
+			SLEN("#document-fragment"), &name);
+	if (lerr != lwc_error_ok)
+		return _dom_exception_from_lwc_error(lerr);
+	
+	err = _dom_document_fragment_create(doc, name, NULL, result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -388,8 +358,20 @@
 dom_exception _dom_document_create_text_node(struct dom_document *doc,
 		struct dom_string *data, struct dom_text **result)
 {
-	return dom_text_create(doc, doc->nodenames[DOM_TEXT_NODE],
-			data, result);
+	lwc_string *name;
+	dom_exception err;
+	lwc_error lerr;
+
+	assert(doc->context != NULL);
+
+	lerr = lwc_context_intern(doc->context, "#text", SLEN("#text"), &name);
+	if (lerr != lwc_error_ok)
+		return _dom_exception_from_lwc_error(lerr);
+	
+	err = _dom_text_create(doc, name, data, result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -407,8 +389,20 @@
 dom_exception _dom_document_create_comment(struct dom_document *doc,
 		struct dom_string *data, struct dom_comment **result)
 {
-	return dom_comment_create(doc, doc->nodenames[DOM_COMMENT_NODE],
-			data, result);
+	lwc_string *name;
+	dom_exception err;
+	lwc_error lerr;
+
+	assert(doc->context != NULL);
+
+	lerr = lwc_context_intern(doc->context, "#comment", SLEN("#comment"), &name);
+	if (lerr != lwc_error_ok)
+		return _dom_exception_from_lwc_error(lerr);
+	
+	err = _dom_comment_create(doc, name, data, result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -427,9 +421,21 @@
 dom_exception _dom_document_create_cdata_section(struct dom_document *doc,
 		struct dom_string *data, struct dom_cdata_section **result)
 {
-	return dom_cdata_section_create(doc,
-			doc->nodenames[DOM_CDATA_SECTION_NODE],
-			data, result);
+	lwc_string *name;
+	dom_exception err;
+	lwc_error lerr;
+
+	assert(doc->context != NULL);
+
+	lerr = lwc_context_intern(doc->context, "#cdata-section", 
+			SLEN("#cdata-section"), &name);
+	if (lerr != lwc_error_ok)
+		return _dom_exception_from_lwc_error(lerr);
+
+	err = _dom_cdata_section_create(doc, name, data, result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -452,7 +458,21 @@
 		struct dom_string *data,
 		struct dom_processing_instruction **result)
 {
-	return dom_processing_instruction_create(doc, target, data, result);
+	lwc_string *name;
+	dom_exception err;
+
+	if (_dom_validate_name(target) == false)
+		return DOM_INVALID_CHARACTER_ERR;
+
+	assert(doc->context != NULL);
+	err = _dom_string_intern(target, doc->context, &name);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_processing_instruction_create(doc, name, data, result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -471,7 +491,20 @@
 dom_exception _dom_document_create_attribute(struct dom_document *doc,
 		struct dom_string *name, struct dom_attr **result)
 {
-	return dom_attr_create(doc, name, NULL, NULL, result);
+	lwc_string *n;
+	dom_exception err;
+
+	if (_dom_validate_name(name) == false)
+		return DOM_INVALID_CHARACTER_ERR;
+
+	assert(doc->context != NULL);
+	err = _dom_string_intern(name, doc->context, &n);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_attr_create(doc, n, NULL, NULL, true, result);
+	lwc_context_string_unref(doc->context, n);
+	return err;
 }
 
 /**
@@ -492,7 +525,20 @@
 		struct dom_string *name,
 		struct dom_entity_reference **result)
 {
-	return dom_entity_reference_create(doc, name, NULL, result);
+	lwc_string *n;
+	dom_exception err;
+
+	if (_dom_validate_name(name) == false)
+		return DOM_INVALID_CHARACTER_ERR;
+
+	assert(doc->context != NULL);
+	err = _dom_string_intern(name, doc->context, &n);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_entity_reference_create(doc, n, NULL, result);
+	lwc_context_string_unref(doc->context, n);
+	return err;
 }
 
 /**
@@ -510,8 +556,20 @@
 dom_exception _dom_document_get_elements_by_tag_name(struct dom_document *doc,
 		struct dom_string *tagname, struct dom_nodelist **result)
 {
-	return dom_document_get_nodelist(doc, (struct dom_node_internal *) doc, 
-			tagname, NULL, NULL, result);
+	lwc_string *name;
+	dom_exception err;
+
+	assert(doc->context != NULL);
+	err = _dom_string_intern(tagname, doc->context, &name);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAME, 
+			(struct dom_node_internal *) doc,  name, NULL, NULL, 
+			result);
+	lwc_context_string_unref(doc->context, name);
+
+	return err;
 }
 
 /**
@@ -532,12 +590,9 @@
 dom_exception _dom_document_import_node(struct dom_document *doc,
 		struct dom_node *node, bool deep, struct dom_node **result)
 {
-	UNUSED(doc);
-	UNUSED(node);
-	UNUSED(deep);
-	UNUSED(result);
+	/* TODO: The DOM_INVALID_CHARACTER_ERR exception */
 
-	return DOM_NOT_SUPPORTED_ERR;
+	return dom_document_dup_node(doc, node, deep, result, DOM_NODE_IMPORTED);
 }
 
 /**
@@ -575,7 +630,8 @@
 	struct dom_string *prefix, *localname;
 	dom_exception err;
 
-	/** \todo ensure document supports XML feature */
+	if (_dom_validate_name(qname) == false)
+		return DOM_INVALID_CHARACTER_ERR;
 
 	/* Validate qname */
 	err = _dom_namespace_validate_qname(qname, namespace);
@@ -589,14 +645,58 @@
 		return err;
 	}
 
+	/* Get the interned string from the dom_string */
+	assert(doc->context != NULL);
+	lwc_string *l = NULL, *n = NULL, *p = NULL;
+	if (localname != NULL) {
+		err = _dom_string_intern(localname, doc->context, &l);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(localname);
+			if (prefix != NULL)
+				dom_string_unref(prefix);
+
+			return err;
+		}
+	}
+	if (namespace != NULL) {
+		err = _dom_string_intern(namespace, doc->context, &n);
+		if (err != DOM_NO_ERR) {
+			lwc_context_string_unref(doc->context, l);
+			dom_string_unref(localname);
+			if (prefix != NULL)
+				dom_string_unref(prefix);
+
+			return err;
+		}
+	}
+	if (prefix != NULL) {
+		err = _dom_string_intern(prefix, doc->context, &p);
+		if (err != DOM_NO_ERR) {
+			lwc_context_string_unref(doc->context, l);
+			lwc_context_string_unref(doc->context, n);
+			dom_string_unref(localname);
+			if (prefix != NULL)
+				dom_string_unref(prefix);
+
+			return err;
+		}
+	}
+
 	/* Attempt to create element */
-	err = dom_element_create(doc, localname, namespace, prefix, result);
+	err = _dom_element_create(doc, l, n, p, result);
 
 	/* Tidy up */
-	dom_string_unref(localname);
+	if (localname != NULL) {
+		dom_string_unref(localname);
+		lwc_context_string_unref(doc->context, l);
+	}
 	if (prefix != NULL) {
 		dom_string_unref(prefix);
+		lwc_context_string_unref(doc->context, p);
 	}
+	if (namespace != NULL) {
+		lwc_context_string_unref(doc->context, n);
+	}
 
 	return err;
 }
@@ -636,7 +736,8 @@
 	struct dom_string *prefix, *localname;
 	dom_exception err;
 
-	/** \todo ensure document supports XML feature */
+	if (_dom_validate_name(qname) == false)
+		return DOM_INVALID_CHARACTER_ERR;
 
 	/* Validate qname */
 	err = _dom_namespace_validate_qname(qname, namespace);
@@ -650,14 +751,57 @@
 		return err;
 	}
 
+	/* Get the interned string from the dom_string */
+	assert(doc->context != NULL);
+	lwc_string *l = NULL, *n = NULL, *p = NULL;
+	if (localname != NULL) {
+		err = _dom_string_intern(localname, doc->context, &l);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(localname);
+			if (prefix != NULL)
+				dom_string_unref(prefix);
+
+			return err;
+		}
+	}
+	if (namespace != NULL) {
+		err = _dom_string_intern(namespace, doc->context, &n);
+		if (err != DOM_NO_ERR) {
+			lwc_context_string_unref(doc->context, l);
+			dom_string_unref(localname);
+			if (prefix != NULL)
+				dom_string_unref(prefix);
+
+			return err;
+		}
+	}
+	if (prefix != NULL) {
+		err = _dom_string_intern(prefix, doc->context, &p);
+		if (err != DOM_NO_ERR) {
+			lwc_context_string_unref(doc->context, l);
+			lwc_context_string_unref(doc->context, n);
+			dom_string_unref(localname);
+			if (prefix != NULL)
+				dom_string_unref(prefix);
+
+			return err;
+		}
+	}
 	/* Attempt to create attribute */
-	err = dom_attr_create(doc, localname, namespace, prefix, result);
+	err = _dom_attr_create(doc, l, n, p, true, result);
 
 	/* Tidy up */
-	dom_string_unref(localname);
+	if (localname != NULL) {
+		dom_string_unref(localname);
+		lwc_context_string_unref(doc->context, l);
+	}
 	if (prefix != NULL) {
 		dom_string_unref(prefix);
+		lwc_context_string_unref(doc->context, p);
 	}
+	if (namespace != NULL) {
+		lwc_context_string_unref(doc->context, n);
+	}
 
 	return err;
 }
@@ -679,8 +823,33 @@
 		struct dom_document *doc, struct dom_string *namespace,
 		struct dom_string *localname, struct dom_nodelist **result)
 {
-	return dom_document_get_nodelist(doc, (struct dom_node_internal *) doc, 
-			NULL, namespace, localname, result);
+	dom_exception err;
+	lwc_string *l = NULL, *n = NULL;
+
+	/* Get the interned string from the dom_string */
+	assert(doc->context != NULL);
+	if (localname != NULL) {
+		err = _dom_string_intern(localname, doc->context, &l);
+		if (err != DOM_NO_ERR)
+			return err;
+	}
+	if (namespace != NULL) {
+		err = _dom_string_intern(namespace, doc->context, &n);
+		if (err != DOM_NO_ERR) {
+			lwc_context_string_unref(doc->context, l);
+			return err;
+		}
+	}
+
+	err = _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAMESPACE, 
+			(struct dom_node_internal *) doc, NULL, n, l, result);
+	
+	if (l != NULL)
+		lwc_context_string_unref(doc->context, l);
+	if (n != NULL)
+		lwc_context_string_unref(doc->context, n);
+
+	return err;
 }
 
 /**
@@ -698,11 +867,25 @@
 dom_exception _dom_document_get_element_by_id(struct dom_document *doc,
 		struct dom_string *id, struct dom_element **result)
 {
-	UNUSED(doc);
-	UNUSED(id);
-	UNUSED(result);
+	lwc_string *i;
+	dom_node_internal *root;
+	dom_exception err;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	*result = NULL;
+
+	assert(doc->context != NULL);
+	err = _dom_string_intern(id, doc->context, &i);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_document_get_document_element(doc, (void *) &root);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = _dom_find_element_by_id(root, i, result);
+	dom_node_unref(root);
+
+	return err;
 }
 
 /**
@@ -863,10 +1046,10 @@
 dom_exception _dom_document_get_uri(struct dom_document *doc,
 		struct dom_string **result)
 {
-	UNUSED(doc);
-	UNUSED(result);
+	dom_string_ref(doc->uri);
+	*result = doc->uri;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	return DOM_NO_ERR;
 }
 
 /**
@@ -883,10 +1066,11 @@
 dom_exception _dom_document_set_uri(struct dom_document *doc,
 		struct dom_string *uri)
 {
-	UNUSED(doc);
-	UNUSED(uri);
+	dom_string_unref(doc->uri);
+	dom_string_ref(uri);
+	doc->uri = uri;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	return DOM_NO_ERR;
 }
 
 /**
@@ -903,15 +1087,62 @@
  * The returned node will have its reference count increased. It is
  * the responsibility of the caller to unref the node once it has
  * finished with it.
+ *
+ * @note: The spec said adoptNode may be light weight than the importNode
+ *	  because the former need no Node creation. But in our implementation
+ *	  this can't be ensured. Both adoptNode and importNode create new
+ *	  nodes using the importing/adopting document's resource manager. So,
+ *	  generally, the adoptNode and importNode call the same function
+ *	  dom_document_dup_node.
  */
 dom_exception _dom_document_adopt_node(struct dom_document *doc,
 		struct dom_node *node, struct dom_node **result)
 {
-	UNUSED(doc);
-	UNUSED(node);
-	UNUSED(result);
+	dom_exception err;
+	dom_node_internal *n = (dom_node_internal *) node;
+	
+	*result = NULL;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	if (n->type == DOM_DOCUMENT_NODE ||
+			n->type == DOM_DOCUMENT_TYPE_NODE) {
+		return DOM_NOT_SUPPORTED_ERR;		
+	}
+
+	if (n->type == DOM_ENTITY_NODE ||
+			n->type == DOM_NOTATION_NODE ||
+			n->type == DOM_PROCESSING_INSTRUCTION_NODE ||
+			n->type == DOM_TEXT_NODE ||
+			n->type == DOM_CDATA_SECTION_NODE ||
+			n->type == DOM_COMMENT_NODE) {
+		*result = NULL;
+		return DOM_NO_ERR;
+	}
+
+	/* Support XML when necessary */
+	if (n->type == DOM_ENTITY_REFERENCE_NODE) {
+		return DOM_NOT_SUPPORTED_ERR;
+	}
+
+	err = dom_document_dup_node(doc, node, true, result, DOM_NODE_ADOPTED);
+	if (err != DOM_NO_ERR) {
+		*result = NULL;
+		return err;
+	}
+
+	dom_node_internal *parent = n->parent;
+	dom_node_internal *tmp;
+	if (parent != NULL) {
+		err = dom_node_remove_child(parent, node, (void *) &tmp);
+		if (err != DOM_NO_ERR) {
+			dom_node_unref(*result);
+			*result = NULL;
+			return err;
+		}
+	}
+
+	dom_node_unref(tmp);
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -992,7 +1223,58 @@
 	return DOM_NOT_SUPPORTED_ERR;
 }
 
+/*-----------------------------------------------------------------------*/
+
+/* Overload protectd virtual functions */
+
 /**
+ * The virtual destroy function of this class
+ */
+void _dom_document_destroy(struct dom_node_internal *node)
+{
+	struct dom_document *doc = (struct dom_document *) node;
+
+	if (_dom_document_finalise(doc) == true) {
+		doc->alloc(doc, 0, doc->pw);
+	}
+}
+
+/**
+ * The memory allocation function of this class
+ */
+dom_exception __dom_document_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(n);
+	struct dom_document *a;
+	
+	a = _dom_document_alloc(doc, NULL, sizeof(struct dom_document));
+	if (a == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ret = (dom_node_internal *) a;
+	dom_node_set_owner(*ret, doc);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * The copy constructor function of this class
+ */
+dom_exception _dom_document_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	UNUSED(new);
+	UNUSED(old);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/* Helper functions */
+/**
  * Create a DOM string, using a document's allocation context
  *
  * \param doc     The document
@@ -1007,16 +1289,92 @@
  * The string of characters passed in will be copied for use by the
  * returned DOM string.
  */
-dom_exception dom_document_create_string(struct dom_document *doc,
+dom_exception _dom_document_create_string(struct dom_document *doc,
 		const uint8_t *data, size_t len, struct dom_string **result)
 {
 	return dom_string_create(doc->alloc, doc->pw, data, len, result);
 }
 
-/*                                                                         */
-/* ----------------------------------------------------------------------- */
-/*                                                                         */
+/*
+ * Create a lwc_string 
+ * 
+ * \param doc 		The document object
+ * \param data		The raw string data
+ * \param len		The raw string length
+ * \param result	The resturned lwc_string
+ */
+dom_exception _dom_document_create_lwcstring(struct dom_document *doc,
+		const uint8_t *data, size_t len, struct lwc_string_s **result)
+{
+	lwc_error lerr;
 
+	assert(doc->context != NULL);
+
+	lerr = lwc_context_intern(doc->context, (const char *) data, len, 
+			result);
+	
+	return _dom_exception_from_lwc_error(lerr);
+}
+
+/* Simple accessor for lwc_context of this document */
+struct lwc_context_s *_dom_document_get_intern_context(
+		struct dom_document *doc)
+{
+	return doc->context;
+}
+
+/* Get the resource manager from the document */
+void _dom_document_get_resource_mgr(
+		struct dom_document *doc, struct dom_resource_mgr *rm)
+{
+	rm->alloc = doc->alloc;
+	rm->pw = doc->pw;
+	rm->ctx = doc->context;
+}
+
+/* Simple accessor for allocator data for this document */
+void _dom_document_get_allocator(struct dom_document *doc, dom_alloc *al, 
+		void **pw)
+{
+	*al = doc->alloc;
+	*pw = doc->pw;
+}
+/*
+ * Create a dom_string from a lwc_string.
+ *
+ * \param doc		The document object
+ * \param str		The lwc_string object
+ * \param result 	The retured dom_string
+ */
+dom_exception _dom_document_create_string_from_lwcstring(struct dom_document *doc,
+		struct lwc_string_s *str, struct dom_string **result)
+{
+	assert(doc->context != NULL);
+
+	return _dom_string_create_from_lwcstring(doc->alloc, doc->pw, 
+			doc->context, str, result);
+}
+
+/* Create a hash_table 
+ * 
+ * \param doc		The dom_document
+ * \param chains	The number of chains
+ * \param f			The hash function
+ * \param ht		The returned hash_table
+ */
+dom_exception _dom_document_create_hashtable(struct dom_document *doc,
+		size_t chains, dom_hash_func f, struct dom_hash_table **ht)
+{
+	struct dom_hash_table *ret;
+
+	ret = _dom_hash_create(chains, f, doc->alloc, doc->pw);
+	if (ret == NULL)
+		return DOM_NO_MEM_ERR;
+	
+	*ht = ret;
+	return DOM_NO_ERR;
+}
+
 /**
  * (De)allocate memory with a document's context
  *
@@ -1028,7 +1386,7 @@
  * This call (modulo ::doc) has the same semantics as realloc().
  * It is a thin veneer over the client-provided allocation function.
  */
-void *dom_document_alloc(struct dom_document *doc, void *ptr, size_t size)
+void *_dom_document_alloc(struct dom_document *doc, void *ptr, size_t size)
 {
 	return doc->alloc(ptr, size, doc->pw);
 }
@@ -1037,6 +1395,7 @@
  * Get a nodelist, creating one if necessary
  *
  * \param doc        The document to get a nodelist for
+ * \param type	     The type of the NodeList
  * \param root       Root node of subtree that list applies to
  * \param tagname    Name of nodes in list (or NULL)
  * \param namespace  Namespace part of nodes in list (or NULL)
@@ -1048,16 +1407,16 @@
  * the responsibility of the caller to unref the list once it has
  * finished with it.
  */
-dom_exception dom_document_get_nodelist(struct dom_document *doc,
-		struct dom_node_internal *root, struct dom_string *tagname,
-		struct dom_string *namespace, struct dom_string *localname,
+dom_exception _dom_document_get_nodelist(struct dom_document *doc, nodelist_type type,
+		struct dom_node_internal *root, struct lwc_string_s *tagname,
+		struct lwc_string_s *namespace, struct lwc_string_s *localname,
 		struct dom_nodelist **list)
 {
 	struct dom_doc_nl *l;
 	dom_exception err;
 
 	for (l = doc->nodelists; l; l = l->next) {
-		if (dom_nodelist_match(l->list, root, tagname,
+		if (_dom_nodelist_match(l->list, type, root, tagname,
 				namespace, localname))
 			break;
 	}
@@ -1074,7 +1433,7 @@
 			return DOM_NO_MEM_ERR;
 
 		/* Create nodelist */
-		err = dom_nodelist_create(doc, root, tagname, namespace,
+		err = _dom_nodelist_create(doc, type, root, tagname, namespace,
 				localname, &l->list);
 		if (err != DOM_NO_ERR) {
 			doc->alloc(l, 0, doc->pw);
@@ -1093,7 +1452,7 @@
 	 * If it did, the nodelist's reference count would never reach zero,
 	 * and the list would remain indefinitely. This is not a problem as
 	 * the list notifies the document of its destruction via
-	 * dom_document_remove_nodelist. */
+	 * _dom_document_remove_nodelist. */
 
 	*list = l->list;
 
@@ -1106,7 +1465,7 @@
  * \param doc   The document to remove the list from
  * \param list  The list to remove
  */
-void dom_document_remove_nodelist(struct dom_document *doc,
+void _dom_document_remove_nodelist(struct dom_document *doc,
 		struct dom_nodelist *list)
 {
 	struct dom_doc_nl *l;
@@ -1135,97 +1494,168 @@
 }
 
 /**
- * Get a namednodemap, creating one if necessary
+ * Find element with certain ID in the subtree rooted at root 
  *
- * \param doc   The document to get a namednodemap for
- * \param head  Start of list containing items in map
- * \param type  The type of items in map
- * \param map   Pointer to location to receive map
- * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
+ * \param root		The root element from where we start
+ * \param id		The ID of the target element
+ * \param result	The result element
+ */
+dom_exception _dom_find_element_by_id(dom_node_internal *root, 
+		struct lwc_string_s *id, struct dom_element **result)
+{
+	*result = NULL;
+	dom_node_internal *node = root;
+
+	while (node != NULL) {
+		if (root->type == DOM_ELEMENT_NODE) {
+			lwc_string *real_id;
+			_dom_element_get_id((dom_element *) node, &real_id);
+			if (real_id == id) {
+				*result = (dom_element *) node;
+				return DOM_NO_ERR;
+			}
+		}
+
+		if (node->first_child != NULL) {
+			/* Has children */
+			node = node->first_child;
+		} else if (node->next != NULL) {
+			/* No children, but has siblings */
+			node = node->next;
+		} else {
+			/* No children or siblings. 
+			 * Find first unvisited relation. */
+			struct dom_node_internal *parent = node->parent;
+
+			while (parent != root &&
+					node == parent->last_child) {
+				node = parent;
+				parent = parent->parent;
+			}
+
+			node = node->next;
+		}
+	}
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Duplicate a Node
  *
- * The returned map will have its reference count increased. It is
- * the responsibility of the caller to unref the map once it has
- * finished with it.
+ * \param doc	The documen
+ * \param node	The node to duplicate
+ * \param deep	Whether to make a deep copy
+ * \param result	The returned node
+ * \param opt	Whether this is adopt or import operation
  */
-dom_exception dom_document_get_namednodemap(struct dom_document *doc,
-		struct dom_node_internal *head, dom_node_type type,
-		struct dom_namednodemap **map)
+dom_exception dom_document_dup_node(dom_document *doc, struct dom_node *node,
+		bool deep, struct dom_node **result, dom_node_operation opt)
 {
-	struct dom_doc_nnm *m;
 	dom_exception err;
+	dom_node_internal *n = (dom_node_internal *) node;
 
-	for (m = doc->maps; m; m = m->next) {
-		if (dom_namednodemap_match(m->map, head, type))
-			break;
+	if (opt == DOM_NODE_ADOPTED && _dom_node_readonly(n))
+		return DOM_NO_MODIFICATION_ALLOWED_ERR;
+	
+	if (n->type == DOM_DOCUMENT_NODE ||
+			n->type == DOM_DOCUMENT_TYPE_NODE)
+		return DOM_NOT_SUPPORTED_ERR;
+
+	err = dom_node_alloc(doc, node, result);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_node_copy(*result, node);
+	if (err != DOM_NO_ERR) {
+		_dom_document_alloc(doc, *result, 0);
+		return err;
 	}
 
-	if (m != NULL) {
-		/* Found an existing map, so use it */
-		dom_namednodemap_ref(m->map);
-	} else {
-		/* No existing map */
+	if (n->type == DOM_ATTRIBUTE_NODE) {
+		_dom_attr_set_specified((dom_attr *) node, true);
+		deep = true;
+	}
 
-		/* Create active map entry */
-		m = doc->alloc(NULL, sizeof(struct dom_doc_nnm), doc->pw);
-		if (m == NULL)
-			return DOM_NO_MEM_ERR;
+	if (n->type == DOM_ENTITY_REFERENCE_NODE) {
+		deep = false;
+	}
 
-		/* Create namednodemap */
-		err = dom_namednodemap_create(doc, head, type, &m->map);
-		if (err != DOM_NO_ERR) {
-			doc->alloc(m, 0, doc->pw);
-			return err;
-		}
+	if (n->type == DOM_ELEMENT_NODE) {
+		/* Specified attributes are copyied but not default attributes,
+		 * if the document object hold all the default attributes, we 
+		 * have nothing to do here */
+	}
 
-		/* Add to document's list of active namednodemaps */
-		m->prev = NULL;
-		m->next = doc->maps;
-		if (doc->maps)
-			doc->maps->prev = m;
-		doc->maps = m;
+	if (opt == DOM_NODE_ADOPTED && (n->type == DOM_ENTITY_NODE ||
+			n->type == DOM_NOTATION_NODE)) {
+		/* We did not support XML now */
+		return DOM_NOT_SUPPORTED_ERR;
 	}
 
-	/* Note: the document does not claim a reference on the namednodemap
-	 * If it did, the map's reference count would never reach zero,
-	 * and the list would remain indefinitely. This is not a problem as
-	 * the map notifies the document of its destruction via
-	 * dom_document_remove_namednodempa. */
+	dom_node_internal *child, *r;
+	if (deep == true) {
+		child = ((dom_node_internal *) node)->first_child;
+		while (child != NULL) {
+			err = dom_document_import_node(doc, child, deep, (void *) &r);
+			if (err != DOM_NO_ERR) {
+				_dom_document_alloc(doc, *result, 0);
+				return err;
+			}
 
-	*map = m->map;
+			err = dom_node_append_child(*result, r, (void *) &r);
+			if (err != DOM_NO_ERR) {
+				_dom_document_alloc(doc, *result, 0);
+				dom_node_unref(r);
+				return err;
+			}
+			dom_node_unref(r);
 
+			child = child->next;
+		}
+	}
+
+	/* Call the dom_user_data_handlers */
+	dom_user_data *ud;
+	ud = n->user_data;
+	while (ud != NULL) {
+		if (ud->handler != NULL)
+			ud->handler(opt, ud->key, ud->data, 
+					node, *result);
+		ud = ud->next;
+	}
+
 	return DOM_NO_ERR;
 }
 
 /**
- * Remove a namednodemap
+ * Try to destory the document. 
+ * Delete the document if:
+ * 1. The refcnt reach zero
+ * 2. The pending list is empty
  *
- * \param doc  The document to remove the map from
- * \param map  The map to remove
+ * else, do nothing.
  */
-void dom_document_remove_namednodemap(struct dom_document *doc,
-		struct dom_namednodemap *map)
+void _dom_document_try_destroy(struct dom_document *doc)
 {
-	struct dom_doc_nnm *m;
-
-	for (m = doc->maps; m; m = m->next) {
-		if (m->map == map)
-			break;
-	}
-
-	if (m == NULL) {
-		/* This should never happen; we should probably abort here */
+	if (doc->base.refcnt != 0 || doc->base.parent != NULL)
 		return;
-	}
 
-	/* Remove from list */
-	if (m->prev != NULL)
-		m->prev->next = m->next;
-	else
-		doc->maps = m->next;
+	_dom_document_destroy((dom_node_internal *) doc);
+}
 
-	if (m->next != NULL)
-		m->next->prev = m->prev;
-
-	/* And free item */
-	doc->alloc(m, 0, doc->pw);
+/**
+ * Set the ID attribute name of this document
+ *
+ * \param doc	The document object
+ * \param name	The ID name of the elements in this document
+ *
+ * @note: The lwc_context of the param 'name' must be the same one with
+ * 		  document's, this should be assured by the client.
+ */
+void _dom_document_set_id_name(dom_document *doc, struct lwc_string_s *name)
+{
+	if (doc->id_name != NULL)
+		lwc_context_string_unref(doc->context, doc->id_name);
+	doc->id_name = lwc_context_string_ref(doc->context, name);
 }
Index: src/core/document_type.c
===================================================================
--- src/core/document_type.c	(revision 9058)
+++ src/core/document_type.c	(working copy)
@@ -4,15 +4,20 @@
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
  * Copyright 2007 James Shaw <jshaw at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
+#include <assert.h>
+
 #include <dom/core/document_type.h>
-#include <dom/core/string.h>
 #include <dom/bootstrap/implpriv.h>
 
+#include "core/string.h"
 #include "core/document_type.h"
 #include "core/node.h"
 #include "utils/utils.h"
+#include "utils/namespace.h"
+#include "utils/resource_mgr.h"
 
 /**
  * DOM DocumentType node
@@ -20,12 +25,13 @@
 struct dom_document_type {
 	struct dom_node_internal base;		/**< Base node */
 
+	struct dom_implementation *impl;	/**< Owning implementation */
+
 	/** \todo other members */
 	struct dom_string *public_id;	/**< Doctype public ID */
 	struct dom_string *system_id;	/**< Doctype system ID */
 
-	dom_alloc alloc;		/**< Memory (de)allocation function */
-	void *pw;			/**< Pointer to private data */
+	struct dom_resource_mgr res;
 };
 
 static struct dom_document_type_vtable document_type_vtable = {
@@ -35,6 +41,15 @@
 	DOM_DOCUMENT_TYPE_VTABLE
 };
 
+static struct dom_node_protect_vtable dt_protect_vtable = {
+	DOM_DT_PROTECT_VTABLE
+};
+
+
+/*----------------------------------------------------------------------*/
+
+/* Constructors and destructors */
+
 /**
  * Create a document type node
  *
@@ -52,7 +67,8 @@
  */
 dom_exception dom_document_type_create(struct dom_string *qname,
 		struct dom_string *public_id, struct dom_string *system_id,
-		dom_alloc alloc, void *pw, struct dom_document_type **doctype)
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document_type **doctype)
 {
 	struct dom_document_type *result;
 	dom_exception err;
@@ -62,29 +78,13 @@
 	if (result == NULL)
 		return DOM_NO_MEM_ERR;
 
-	/* Initialise base node */
-	err = dom_node_initialise(&result->base, NULL, DOM_DOCUMENT_TYPE_NODE,
-			qname, NULL, NULL, NULL);
-	if (err != DOM_NO_ERR) {
-		alloc(result, 0, pw);
-		return err;
-	}
-
 	/* Initialise the vtable */
 	result->base.base.vtable = &document_type_vtable;
-	result->base.destroy = &dom_document_type_destroy;
+	result->base.vtable = &dt_protect_vtable;
+	
+	err = _dom_document_type_initialise(result, qname, public_id, system_id,
+			alloc, pw, ctx);
 
-	/* Get public and system IDs */
-	dom_string_ref(public_id);
-	result->public_id = public_id;
-
-	dom_string_ref(system_id);
-	result->system_id = system_id;
-
-	/* Fill in allocation information */
-	result->alloc = alloc;
-	result->pw = pw;
-
 	*doctype = result;
 
 	return DOM_NO_ERR;
@@ -97,22 +97,107 @@
  *
  * The contents of ::doctype will be destroyed and ::doctype will be freed.
  */
-void dom_document_type_destroy(struct dom_node_internal *doctypenode)
+void _dom_document_type_destroy(struct dom_node_internal *doctypenode)
 {
 	struct dom_document_type *doctype = 
 			(struct dom_document_type *)doctypenode;
 
-	/* Finish with public and system IDs */
-	dom_string_unref(doctype->system_id);
-	dom_string_unref(doctype->public_id);
-
 	/* Finalise base class */
-	dom_node_finalise(doctype->base.owner, &doctype->base);
+	_dom_document_type_finalise(doctype);
 
 	/* Free doctype */
-	doctype->alloc(doctype, 0, doctype->pw);
+	doctype->res.alloc(doctype, 0, doctype->res.pw);
 }
 
+/* Initialise this document_type */
+dom_exception _dom_document_type_initialise(struct dom_document_type *doctype,
+		struct dom_string *qname, struct dom_string *public_id,
+		struct dom_string *system_id, dom_alloc alloc, void *pw,
+		struct lwc_context_s *ctx)
+{
+	dom_exception err;
+
+	dom_string *prefix, *localname;
+	err = _dom_namespace_split_qname(qname, &prefix, &localname);
+	if (err != DOM_NO_ERR) {
+		alloc(doctype, 0, pw);
+		return err;
+	}
+
+	lwc_string *lprefix = NULL, *lname = NULL;
+	if (prefix != NULL) {
+		err = _dom_string_intern(prefix, ctx, &lprefix);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(prefix);
+			dom_string_unref(localname);
+			alloc(doctype, 0, pw);
+			return err;
+		}
+	}
+
+	if (localname != NULL) {
+		err = _dom_string_intern(localname, ctx, &lname);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(prefix);
+			dom_string_unref(localname);
+			if (lprefix != NULL)
+				lwc_context_string_unref(ctx, lprefix);
+			alloc(doctype, 0, pw);
+			return err;
+		}
+	}
+
+	/* TODO: I should figure out how the namespaceURI can be got */
+
+	/* Initialise base node */
+	err = _dom_node_initialise_generic(&doctype->base, NULL, alloc, pw, ctx, 
+			DOM_DOCUMENT_TYPE_NODE, lname, NULL, NULL, lprefix);
+	if (err != DOM_NO_ERR) {
+		alloc(doctype, 0, pw);
+		return err;
+	}
+
+	/* Get public and system IDs */
+	if (public_id != NULL)
+		dom_string_ref(public_id);
+	doctype->public_id = public_id;
+
+	if (system_id != NULL)
+		dom_string_ref(system_id);
+	doctype->system_id = system_id;
+
+	if (prefix != NULL)
+		dom_string_unref(prefix);
+	if (localname != NULL)
+		dom_string_unref(localname);
+
+	/* Fill in allocation information */
+	doctype->res.alloc = alloc;
+	doctype->res.pw = pw;
+	doctype->res.ctx = ctx;
+
+	return DOM_NO_ERR;
+}
+
+/* The destructor function of dom_document_type */
+void _dom_document_type_finalise(struct dom_document_type *doctype)
+{
+	if (doctype->public_id != NULL)
+		dom_string_unref(doctype->public_id);
+	if (doctype->system_id != NULL)
+		dom_string_unref(doctype->system_id);
+	
+	assert(doctype->base.owner != NULL || doctype->base.user_data == NULL);
+	
+	_dom_node_finalise_generic(&doctype->base, doctype->res.alloc, doctype->res.pw,
+			doctype->res.ctx);
+}
+
+
+/*----------------------------------------------------------------------*/
+
+/* Virtual functions */
+
 /**
  * Retrieve a document type's name
  *
@@ -238,3 +323,64 @@
 	return DOM_NOT_SUPPORTED_ERR;
 }
 
+/*-----------------------------------------------------------------------*/
+
+/* Overload protected virtual functions */
+
+/**
+ * The virtual destroy function of this class
+ */
+void _dom_dt_destroy(struct dom_node_internal *node)
+{
+	_dom_document_type_destroy(node);
+}
+
+/**
+ * The memory allocator of this class
+ */
+dom_exception _dom_dt_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(doc);
+	UNUSED(n);
+	UNUSED(ret);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * The copy constructor of this class
+ */
+dom_exception _dom_dt_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	UNUSED(new);
+	UNUSED(old);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+
+/*----------------------------------------------------------------------*/
+
+/* Helper functions */
+
+/* Get the resource manager of this object */
+void _dom_document_type_get_resource_mgr(
+		struct dom_document_type *dt, struct dom_resource_mgr *rm)
+{
+	rm->alloc = dt->res.alloc;
+	rm->pw = dt->res.pw;
+	rm->ctx = dt->res.ctx;
+}
+
+/**
+ * Get the implementation which created this dom_document_type
+ *
+ * \param dt	The document type object
+ */
+struct dom_implementation *_dom_document_type_get_impl(
+		struct dom_document_type *dt)
+{
+	return dt->impl;
+}
Index: src/core/attr.h
===================================================================
--- src/core/attr.h	(revision 9058)
+++ src/core/attr.h	(working copy)
@@ -13,26 +13,31 @@
 struct dom_document;
 struct dom_string;
 struct dom_type_info;
+struct lwc_string_s;
 
-dom_exception dom_attr_create(struct dom_document *doc,
-		struct dom_string *name, struct dom_string *namespace,
-		struct dom_string *prefix, struct dom_attr **result);
-void dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr);
-/* The virtual destroy function */
-void _dom_attr_destroy(dom_node_internal *node);
+dom_exception _dom_attr_create(struct dom_document *doc,
+		struct lwc_string_s *name, struct lwc_string_s *namespace,
+		struct lwc_string_s *prefix, bool specified, 
+		struct dom_attr **result);
+void _dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr);
+dom_exception _dom_attr_initialise(struct dom_attr *a, 
+		struct dom_document *doc,  struct lwc_string_s *name,
+		struct lwc_string_s *namespace, struct lwc_string_s *prefix,
+		bool specified, struct dom_attr **result);
+void _dom_attr_finalise(dom_document *doc, struct dom_attr *attr);
 
-/* Virtual functions for dom attr */
+/* Virtual functions for dom_attr */
 dom_exception _dom_attr_get_name(struct dom_attr *attr,
-                struct dom_string **result);
+				struct dom_string **result);
 dom_exception _dom_attr_get_specified(struct dom_attr *attr, bool *result);
 dom_exception _dom_attr_get_value(struct dom_attr *attr,
-                struct dom_string **result);
+				struct dom_string **result);
 dom_exception _dom_attr_set_value(struct dom_attr *attr,
-                struct dom_string *value);
+				struct dom_string *value);
 dom_exception _dom_attr_get_owner(struct dom_attr *attr,
-                struct dom_element **result);
+				struct dom_element **result);
 dom_exception _dom_attr_get_schema_type_info(struct dom_attr *attr,
-                struct dom_type_info **result);
+				struct dom_type_info **result);
 dom_exception _dom_attr_is_id(struct dom_attr *attr, bool *result);
 
 #define DOM_ATTR_VTABLE 	\
@@ -44,4 +49,73 @@
 	_dom_attr_get_schema_type_info, \
 	_dom_attr_is_id
 
+/* Overloading dom_node functions */
+dom_exception _dom_attr_get_node_value(dom_node_internal *node,
+		struct dom_string **result);
+dom_exception _dom_attr_clone_node(dom_node_internal *node, bool deep,
+		dom_node_internal **result);
+dom_exception _dom_attr_set_prefix(dom_node_internal *node,
+		struct dom_string *prefix);
+dom_exception _dom_attr_normalize(dom_node_internal *node);
+dom_exception _dom_attr_lookup_prefix(dom_node_internal *node,
+		struct dom_string *namespace, struct dom_string **result);
+dom_exception _dom_attr_is_default_namespace(dom_node_internal *node,
+		struct dom_string *namespace, bool *result);
+dom_exception _dom_attr_lookup_namespace(dom_node_internal *node,
+		struct dom_string *prefix, struct dom_string **result);
+#define DOM_NODE_VTABLE_ATTR \
+	_dom_node_get_node_name, \
+	_dom_attr_get_node_value, /*overload*/\
+	_dom_node_set_node_value, \
+	_dom_node_get_node_type, \
+	_dom_node_get_parent_node, \
+	_dom_node_get_child_nodes, \
+	_dom_node_get_first_child, \
+	_dom_node_get_last_child, \
+	_dom_node_get_previous_sibling, \
+	_dom_node_get_next_sibling, \
+	_dom_node_get_attributes, \
+	_dom_node_get_owner_document, \
+	_dom_node_insert_before, \
+	_dom_node_replace_child, \
+	_dom_node_remove_child, \
+	_dom_node_append_child, \
+	_dom_node_has_child_nodes, \
+	_dom_attr_clone_node, /*overload*/\
+	_dom_node_normalize, \
+	_dom_node_is_supported, \
+	_dom_node_get_namespace, \
+	_dom_node_get_prefix, \
+	_dom_attr_set_prefix, /*overload*/\
+	_dom_node_get_local_name, \
+	_dom_node_has_attributes, \
+	_dom_node_get_base, \
+	_dom_node_compare_document_position, \
+	_dom_node_get_text_content, \
+	_dom_node_set_text_content, \
+	_dom_node_is_same, \
+	_dom_attr_lookup_prefix, /*overload*/\
+	_dom_attr_is_default_namespace, /*overload*/\
+	_dom_attr_lookup_namespace, /*overload*/\
+	_dom_node_is_equal, \
+	_dom_node_get_feature, \
+	_dom_node_set_user_data, \
+	_dom_node_get_user_data
+
+/* The protected virtual functions */
+void __dom_attr_destroy(dom_node_internal *node);
+dom_exception _dom_attr_alloc(struct dom_document *doc, 
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_attr_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_ATTR_PROTECT_VTABLE \
+	__dom_attr_destroy, \
+	_dom_attr_alloc, \
+	_dom_attr_copy
+
+
+inline void _dom_attr_set_isid(struct dom_attr *attr, bool is_id);
+inline void _dom_attr_set_specified(struct dom_attr *attr, bool specified);
+
 #endif
Index: src/core/document.h
===================================================================
--- src/core/document.h	(revision 9058)
+++ src/core/document.h	(working copy)
@@ -12,10 +12,15 @@
 #include <stddef.h>
 
 #include <dom/core/node.h>
-#include <dom/core/string.h>
 
+#include "core/string.h"
 #include "core/node.h"
+#include "core/nodelist.h"
 
+#include "utils/hashtable.h"
+#include "utils/resource_mgr.h"
+#include "utils/list.h"
+
 struct dom_document;
 struct dom_namednodemap;
 struct dom_node;
@@ -32,7 +37,6 @@
 struct dom_configuration;
 
 struct dom_doc_nl;
-struct dom_doc_nnm;
 
 /**
  * DOM document
@@ -46,14 +50,38 @@
 
 	struct dom_doc_nl *nodelists;	/**< List of active nodelists */
 
-	struct dom_doc_nnm *maps;	/**< List of active namednodemaps */
+	struct dom_string *uri;		/**< The uri of this document */
 
-	struct dom_string **nodenames;	/**< Interned nodenames */
+	struct lwc_context_s *context;	/**< The internment context */
 
 	dom_alloc alloc;		/**< Memory (de)allocation function */
 	void *pw;			/**< Pointer to client data */
+
+	struct list_entry pending_nodes;	/**< The deletion pending list */
+
+	struct lwc_string_s *id_name;	/**< The ID attribute's name */
 };
 
+/* Initialise the document */
+dom_exception _dom_document_initialise(struct dom_document *doc, 
+		struct dom_implementation *impl, dom_alloc alloc, void *pw, 
+		struct lwc_context_s *ctx);
+
+/* Finalise the document */
+bool _dom_document_finalise(struct dom_document *doc);
+
+/* Create a dom_string from C string */
+dom_exception _dom_document_create_string(struct dom_document *doc,
+		const uint8_t *data, size_t len, struct dom_string **result);
+/* Create a lwc_string from C string */
+dom_exception _dom_document_create_lwcstring(struct dom_document *doc,
+		const uint8_t *data, size_t len, struct lwc_string_s **result);
+/* Create a dom_string from a lwc_string */
+dom_exception _dom_document_create_string_from_lwcstring(struct dom_document *doc,
+		struct lwc_string_s *str, struct dom_string **result);
+
+
+/* Begin the virtual functions */
 dom_exception _dom_document_get_doctype(struct dom_document *doc,
 		struct dom_document_type **result);
 dom_exception _dom_document_get_implementation(struct dom_document *doc,
@@ -156,34 +184,65 @@
 	_dom_document_get_dom_config, \
 	_dom_document_normalize, \
 	_dom_document_rename_node
+/* End of vtable */
 
 
-/* Initialise the document module */
-dom_exception _dom_document_initialise(dom_alloc alloc, void *pw);
-/* Finalise the document module */
-dom_exception _dom_document_finalise(void);
+/* Following comes the protected vtable  */
+void _dom_document_destroy(struct dom_node_internal *node);
+dom_exception __dom_document_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_document_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
 
-/* Destroy a document */
-void dom_document_destroy(struct dom_node_internal *dnode);
+#define DOM_DOCUMENT_PROTECT_VTABLE \
+	_dom_document_destroy, \
+	__dom_document_alloc, \
+	_dom_document_copy
 
+
+/*---------------------------- Helper functions ---------------------------*/
+/* Try to destroy the document:
+ * When the refcnt is zero and the pending list is empty, we can destroy this
+ * document.
+ */
+void _dom_document_try_destroy(struct dom_document *doc);
 /* (De)allocate memory */
-void *dom_document_alloc(struct dom_document *doc, void *ptr, size_t size);
+void *_dom_document_alloc(struct dom_document *doc, void *ptr, size_t size);
 
+/* Get the internment context */
+inline struct lwc_context_s *_dom_document_get_intern_context(
+		struct dom_document *doc);
+
+/* Get the resource manager inside this document, a resource manager
+ * is an object which contain the memory allocator/intern string context,
+ * with which we can alloc strings or intern strings */
+void _dom_document_get_resource_mgr(
+		struct dom_document *doc, struct dom_resource_mgr *rm);
+
+/* Get the internal allocator and its pointer */
+inline void _dom_document_get_allocator(struct dom_document *doc, dom_alloc *al, 
+		void **pw);
+
+/* Create a hash_table */
+dom_exception _dom_document_create_hashtable(struct dom_document *doc,
+		size_t chains, dom_hash_func f, struct dom_hash_table **ht);
+
 /* Get a nodelist, creating one if necessary */
-dom_exception dom_document_get_nodelist(struct dom_document *doc,
-		struct dom_node_internal *root, struct dom_string *tagname,
-		struct dom_string *namespace, struct dom_string *localname,
+dom_exception _dom_document_get_nodelist(struct dom_document *doc, nodelist_type type,
+		struct dom_node_internal *root, struct lwc_string_s *tagname,
+		struct lwc_string_s *namespace, struct lwc_string_s *localname,
 		struct dom_nodelist **list);
 /* Remove a nodelist */
-void dom_document_remove_nodelist(struct dom_document *doc,
+void _dom_document_remove_nodelist(struct dom_document *doc,
 		struct dom_nodelist *list);
 
-/* Get a namednodemap, creating one if necessary */
-dom_exception dom_document_get_namednodemap(struct dom_document *doc,
-		struct dom_node_internal *head, dom_node_type type,
-		struct dom_namednodemap **map);
-/* Remove a namednodemap */
-void dom_document_remove_namednodemap(struct dom_document *doc,
-		struct dom_namednodemap *map);
+/* Find element with certain ID in the subtree rooted at root */
+dom_exception _dom_find_element_by_id(dom_node_internal *root, 
+		struct lwc_string_s *id, struct dom_element **result);
 
+/* Set the ID attribute name of this document */
+void _dom_document_set_id_name(struct dom_document *doc, struct lwc_string_s *name);
+
+#define _dom_document_get_id_name(d) (d->id_name)
+
 #endif
Index: src/core/document_type.h
===================================================================
--- src/core/document_type.h	(revision 9058)
+++ src/core/document_type.h	(working copy)
@@ -9,9 +9,16 @@
 #define dom_internal_core_document_type_h_
 
 struct dom_document_type;
+struct dom_resource_mgr;
+struct dom_implementation;
 
 /* Destroy a document type */
-void dom_document_type_destroy(struct dom_node_internal *doctypenode);
+void _dom_document_type_destroy(struct dom_node_internal *doctypenode);
+dom_exception _dom_document_type_initialise(struct dom_document_type *doctype,
+		struct dom_string *qname, struct dom_string *public_id,
+		struct dom_string *system_id, dom_alloc alloc, void *pw,
+		struct lwc_context_s *ctx);
+void _dom_document_type_finalise(struct dom_document_type *doctype);
 
 /* The virtual functions of DocumentType */
 dom_exception _dom_document_type_get_name(struct dom_document_type *doc_type,
@@ -40,5 +47,22 @@
 	_dom_document_type_get_system_id, \
 	_dom_document_type_get_internal_subset
 
+/* Following comes the protected vtable  */
+void _dom_dt_destroy(struct dom_node_internal *node);
+dom_exception _dom_dt_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_dt_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_DT_PROTECT_VTABLE \
+	_dom_dt_destroy, \
+	_dom_dt_alloc, \
+	_dom_dt_copy
+
+/* Helper functions */
+void _dom_document_type_get_resource_mgr(
+		struct dom_document_type *dt, struct dom_resource_mgr *rm);
+struct dom_implementation *_dom_document_type_get_impl(
+		struct dom_document_type *dt);
+
 #endif
-
Index: src/core/implementation.c
===================================================================
--- src/core/implementation.c	(revision 9058)
+++ src/core/implementation.c	(working copy)
@@ -59,8 +59,6 @@
  * \param public_id  The external subset public identifier
  * \param system_id  The external subset system identifier
  * \param doctype    Pointer to location to receive result
- * \param alloc      Memory (de)allocation function
- * \param pw         Pointer to client-specific private data
  * \return DOM_NO_ERR on success,
  *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
  *         DOM_NAMESPACE_ERR         if ::qname is malformed,
@@ -79,11 +77,11 @@
 dom_exception dom_implementation_create_document_type(
 		struct dom_implementation *impl, struct dom_string *qname,
 		struct dom_string *public_id, struct dom_string *system_id,
-		struct dom_document_type **doctype,
-		dom_alloc alloc, void *pw)
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document_type **doctype)
 {
 	return impl->create_document_type(impl, qname, public_id, system_id,
-			doctype, alloc, pw);
+			alloc, pw, ctx, doctype);
 }
 
 /**
@@ -94,8 +92,6 @@
  * \param qname      The qualified name of the document element
  * \param doctype    The type of document to create
  * \param doc        Pointer to location to receive result
- * \param alloc      Memory (de)allocation function
- * \param pw         Pointer to client-specific private data
  * \return DOM_NO_ERR on success,
  *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
  *         DOM_NAMESPACE_ERR         if ::qname is malformed, or if ::qname
@@ -125,11 +121,11 @@
 		struct dom_implementation *impl,
 		struct dom_string *namespace, struct dom_string *qname,
 		struct dom_document_type *doctype,
-		struct dom_document **doc,
-		dom_alloc alloc, void *pw)
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+		struct dom_document **doc)
 {
-	return impl->create_document(impl, namespace, qname, doctype, doc,
-			alloc, pw);
+	return impl->create_document(impl, namespace, qname, doctype, alloc, 
+			pw, ctx, doc);
 }
 
 /**
@@ -140,8 +136,6 @@
  * \param feature  The requested feature
  * \param version  The version number of the feature
  * \param object   Pointer to location to receive object
- * \param alloc    Memory (de)allocation function
- * \param pw       Pointer to client-specific private data
  * \return DOM_NO_ERR.
  *
  * Any memory allocated by this call should be allocated using
@@ -150,8 +144,7 @@
 dom_exception dom_implementation_get_feature(
 		struct dom_implementation *impl,
 		struct dom_string *feature, struct dom_string *version,
-		void **object,
-		dom_alloc alloc, void *pw)
+		void **object)
 {
-	return impl->get_feature(impl, feature, version, object, alloc, pw);
+	return impl->get_feature(impl, feature, version, object);
 }
Index: src/core/node.c
===================================================================
--- src/core/node.c	(revision 9058)
+++ src/core/node.c	(working copy)
@@ -3,6 +3,7 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
 #include <assert.h>
@@ -10,9 +11,15 @@
 #include <stdio.h>
 
 #include <dom/core/attr.h>
+#include <dom/core/text.h>
 #include <dom/core/document.h>
-#include <dom/core/string.h>
+#include <dom/core/namednodemap.h>
+#include <dom/core/nodelist.h>
+#include <dom/core/implementation.h>
+#include <dom/core/document_type.h>
 
+#include "core/string.h"
+#include "core/namednodemap.h"
 #include "core/attr.h"
 #include "core/cdatasection.h"
 #include "core/comment.h"
@@ -25,6 +32,7 @@
 #include "core/pi.h"
 #include "core/text.h"
 #include "utils/utils.h"
+#include "utils/resource_mgr.h"
 
 static bool _dom_node_permitted_child(const dom_node_internal *parent, 
 		const dom_node_internal *child);
@@ -48,21 +56,31 @@
 	DOM_NODE_VTABLE
 };
 
+static struct dom_node_protect_vtable node_protect_vtable = {
+	DOM_NODE_PROTECT_VTABLE
+};
+
+
+
+/*----------------------------------------------------------------------*/
+
+/* The constructor and destructor of this object */
+
 /**
  * Create a DOM node and compose the vtable
  *
  * Return        The new constructed DOM node or NULL if fail.
  */
-dom_node_internal * dom_node_create(struct dom_document *doc)
+dom_node_internal * _dom_node_create(struct dom_document *doc)
 {
-	dom_node_internal *node = dom_document_alloc(doc, NULL, 
+	dom_node_internal *node = _dom_document_alloc(doc, NULL, 
 			sizeof(struct dom_node_internal));
 
 	if (node == NULL)
 		return NULL;
 
 	node->base.vtable = &node_vtable;
-	node->destroy = _dom_node_destroy;
+	node->vtable = &node_protect_vtable;
 	return node;
 }
 
@@ -86,9 +104,6 @@
 	bool null_owner_permitted = (node->type == DOM_DOCUMENT_NODE || 
 			node->type == DOM_DOCUMENT_TYPE_NODE);
 
-	/* This function simply acts as a central despatcher
-	 * for type-specific destructors. */
-
 	assert(null_owner_permitted || owner != NULL); 
 
 	if (!null_owner_permitted) {
@@ -98,56 +113,19 @@
 		dom_node_ref(owner);
 	}
 
-/* This type dependent switch is not necessary from now.
-   But I still keep them for a while untill all the functions works well.
-	switch (node->type) {
-	case DOM_ELEMENT_NODE:
-		dom_element_destroy(owner, (struct dom_element *) node);
-		break;
-	case DOM_ATTRIBUTE_NODE:
-		dom_attr_destroy(owner, (struct dom_attr *) node);
-		break;
-	case DOM_TEXT_NODE:
-		dom_text_destroy(owner, (struct dom_text *) node);
-		break;
-	case DOM_CDATA_SECTION_NODE:
-		dom_cdata_section_destroy(owner,
-				(struct dom_cdata_section *) node);
-		break;
-	case DOM_ENTITY_REFERENCE_NODE:
-		dom_entity_reference_destroy(owner,
-				(struct dom_entity_reference *) node);
-		break;
-	case DOM_ENTITY_NODE:
-		break;
-	case DOM_PROCESSING_INSTRUCTION_NODE:
-		dom_processing_instruction_destroy(owner,
-				(struct dom_processing_instruction *) node);
-		break;
-	case DOM_COMMENT_NODE:
-		dom_comment_destroy(owner, (struct dom_comment *) node);
-		break;
-	case DOM_DOCUMENT_NODE:
-		dom_document_destroy((struct dom_document *) node);
-		break;
-	case DOM_DOCUMENT_TYPE_NODE:
-		dom_document_type_destroy((struct dom_document_type *) node);
-		break;
-	case DOM_DOCUMENT_FRAGMENT_NODE:
-		dom_document_fragment_destroy(owner,
-				(struct dom_document_fragment *) node);
-		break;
-	case DOM_NOTATION_NODE:
-		break;
-	}
-*/
+	/* Finalise this node, this should also destroy all the child nodes. */
+	_dom_node_finalise(owner, node);
+
 	if (!null_owner_permitted) {
-		/* Release the reference we claimed on the document. If this 
-		 * is the last reference held on the document and the list 
-		 * of nodes pending deletion is empty, then the document will 
+		/* Release the reference we claimed on the document. If this
+		 * is the last reference held on the document and the list
+		 * of nodes pending deletion is empty, then the document will
 		 * be destroyed. */
 		dom_node_unref(owner);
 	}
+
+	/* Release our memory */
+	_dom_document_alloc(owner, node, 0);
 }
 
 /**
@@ -165,13 +143,63 @@
  * ::name, ::value, ::namespace, and ::prefix  will have their reference 
  * counts increased.
  */
-dom_exception dom_node_initialise(dom_node_internal *node,
+dom_exception _dom_node_initialise(dom_node_internal *node,
 		struct dom_document *doc, dom_node_type type,
-		struct dom_string *name, struct dom_string *value,
-		struct dom_string *namespace, struct dom_string *prefix)
+		struct lwc_string_s *name, struct dom_string *value,
+		struct lwc_string_s *namespace, struct lwc_string_s *prefix)
 {
+	lwc_context *ctx;
+	dom_alloc alloc;
+	void *pw;
+	dom_exception err;
+
+	ctx = _dom_document_get_intern_context(doc);
+	/* The lwc_context for a document newer can be NULL */
+	assert(ctx != NULL);
+
+	_dom_document_get_allocator(doc, &alloc, &pw);
+
+	err = _dom_node_initialise_generic(node, doc, alloc, pw, ctx, type, name, 
+			value, namespace, prefix);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Initialise a DOM node
+ *
+ * \param node       The node to initialise
+ * \param doc		 The document object
+ * \param alloc      The memory allocator 
+ * \param pw	     The allocator private pointer data
+ * \param ctx	     The intern context
+ * \param type       The node type required
+ * \param name       The node (local) name, or NULL
+ * \param value      The node value, or NULL
+ * \param namespace  Namespace URI to use for node, or NULL
+ * \param prefix     Namespace prefix to use for node, or NULL
+ * \return DOM_NO_ERR on success.
+ *
+ * ::name, ::value, ::namespace, and ::prefix  will have their reference 
+ * counts increased.
+ */
+dom_exception _dom_node_initialise_generic(
+		struct dom_node_internal *node, struct dom_document *doc,
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+	 	dom_node_type type, struct lwc_string_s *name, 
+		struct dom_string *value, struct lwc_string_s *namespace, 
+		struct lwc_string_s *prefix)
+{
+	UNUSED(alloc);
+	UNUSED(pw);
+
+	assert(ctx != NULL);
+	node->owner = doc;
+
 	if (name != NULL)
-		dom_string_ref(name);
+		lwc_context_string_ref(ctx, name);
 	node->name = name;
 
 	if (value != NULL)
@@ -204,15 +232,14 @@
 	 * deletion. This list will not be forcibly emptied, as it contains
 	 * those nodes (and their sub-trees) in use by client code.
 	 */
-	node->owner = doc;
 
 	if (namespace != NULL) {
-		dom_string_ref(namespace);
+		lwc_context_string_ref(ctx, namespace);
 	}
 	node->namespace = namespace;
 
 	if (prefix != NULL) {
-		dom_string_ref(prefix);
+		lwc_context_string_ref(ctx, prefix);
 	}
 	node->prefix = prefix;
 
@@ -220,6 +247,12 @@
 
 	node->refcnt = 1;
 
+	list_init(&node->pending_list);
+	if (node->type != DOM_DOCUMENT_NODE) {
+		/* A Node should be in the pending list when it is created */
+		dom_node_mark_pending(node);
+	}
+
 	return DOM_NO_ERR;
 }
 
@@ -232,33 +265,65 @@
  * The contents of ::node will be cleaned up. ::node will not be freed.
  * All children of ::node should have been removed prior to finalisation.
  */
-void dom_node_finalise(struct dom_document *doc, dom_node_internal *node)
+void _dom_node_finalise(struct dom_document *doc, dom_node_internal *node)
 {
+	lwc_context *ctx;
+	dom_alloc alloc;
+	void *pw;
+
+	ctx = _dom_document_get_intern_context(doc);
+	/* The lwc_context for a document newer can be NULL */
+	assert(ctx != NULL);
+
+	_dom_document_get_allocator(doc, &alloc, &pw);
+
+	_dom_node_finalise_generic(node, alloc, pw, ctx);
+}
+
+/**
+ * Finalise a DOM node
+ *
+ * \param node  The node to finalise
+ * \param alloc The allocator
+ * \param pw	The allocator private data
+ * \param ctx	The intern string context
+ *
+ * The contents of ::node will be cleaned up. ::node will not be freed.
+ * All children of ::node should have been removed prior to finalisation.
+ */
+void _dom_node_finalise_generic(dom_node_internal *node, dom_alloc alloc, 
+		void *pw, struct lwc_context_s *ctx)
+{
 	struct dom_user_data *u, *v;
 
-	/* Standalone DocumentType nodes may not have user data attached */
-	assert(node->type != DOM_DOCUMENT_TYPE_NODE || 
-			node->user_data == NULL);
+	UNUSED(alloc);
+	UNUSED(pw);
 
+	assert(ctx != NULL);
+
 	/* Destroy user data */
 	for (u = node->user_data; u != NULL; u = v) {
 		v = u->next;
-
 		dom_string_unref(u->key);
-
-		dom_document_alloc(doc, u, 0);
+		alloc(u, 0, pw);
 	}
+	node->user_data = NULL;
 
 	if (node->prefix != NULL)
-		dom_string_unref(node->prefix);
+		lwc_context_string_unref(ctx, node->prefix);
 
 	if (node->namespace != NULL)
-		dom_string_unref(node->namespace);
+		lwc_context_string_unref(ctx, node->namespace);
 
-	/** \todo check if this node is in list of nodes pending deletion.
-	 * If so, it must be removed from the list, so the document gets
-	 * destroyed once the list is empty (and no longer referenced) */
-	node->owner = NULL;
+	/* Destroy all the child nodes of this node */
+	struct dom_node_internal *p = node->first_child;
+	struct dom_node_internal *n = NULL;
+	while (p != NULL) {
+		n = p->next;
+		p->parent = NULL;
+		dom_node_try_destroy(p);
+		p = n;
+	}
 
 	/* Paranoia */
 	node->next = NULL;
@@ -271,7 +336,19 @@
 		dom_string_unref(node->value);
 
 	if (node->name != NULL)
-		dom_string_unref(node->name);
+		lwc_context_string_unref(ctx, node->name);
+
+	/* Detach from the pending list, if we are in it */
+	if (node->pending_list.prev != &node->pending_list) {
+		assert (node->pending_list.next != &node->pending_list); 
+		list_del(&node->pending_list);
+		if (node->owner != NULL && node->type != DOM_DOCUMENT_NODE) {
+			/* Deleting this node from the pending list may cause the list to be
+			 * null and we should try to destroy the document.
+			 */
+			_dom_document_try_destroy(node->owner);
+		}
+	}
 }
 
 /**
@@ -284,6 +361,11 @@
 	node->refcnt++;
 }
 
+
+/* ---------------------------------------------------------------------*/
+
+/* The public virtual function of this interface Node */
+
 /**
  * Release a reference on a DOM node
  *
@@ -291,15 +373,20 @@
  *
  * If the reference count reaches zero and the node is not part of any
  * document, any memory claimed by the node will be released.
+ *
+ * If the parent of the node is NULL but the reference count does not reach
+ * zero, this means we should put this node to the document's deletion pending
+ * list. When the refcnt reach zero, we delete it.
  */
 void _dom_node_unref(dom_node_internal *node)
 {
+	if (node == NULL)
+		return;
+
 	if (node->refcnt > 0)
 		node->refcnt--;
 
-	if (node->refcnt == 0 && node->parent == NULL) {
-		dom_node_destroy(node);
-	}
+	dom_node_try_destroy(node);
 }
 
 /**
@@ -316,50 +403,84 @@
 dom_exception _dom_node_get_node_name(dom_node_internal *node,
 		struct dom_string **result)
 {
-	struct dom_string *node_name;
+	struct dom_string *node_name, *temp;
+	dom_document *doc;
+	dom_exception err;
+	struct dom_resource_mgr rm;
 
+	doc = node->owner;
+	/* Document Node and DocumentType Node can have no owner */
+	assert(node->type == DOM_DOCUMENT_TYPE_NODE ||
+			node->type == DOM_DOCUMENT_NODE ||
+			doc != NULL);
+
 	assert(node->name != NULL);
 
+	if (doc != NULL) {
+		_dom_document_get_resource_mgr(doc, &rm);
+	} else if (node->type == DOM_DOCUMENT_TYPE_NODE) {
+		_dom_document_type_get_resource_mgr((dom_document_type *) node, &rm);
+	}
+
 	/* If this node was created using a namespace-aware method and
 	 * has a defined prefix, then nodeName is a QName comprised
 	 * of prefix:name. */
-	if ((node->type == DOM_ELEMENT_NODE ||
-			node->type == DOM_ATTRIBUTE_NODE) &&
-			node->prefix != NULL) {
+	if(node->prefix != NULL) {
 		struct dom_string *colon;
-		dom_exception err;
 
-		err = dom_document_create_string(node->owner, 
+		err = _dom_resource_mgr_create_string(&rm, 
 				(const uint8_t *) ":", SLEN(":"), &colon);
 		if (err != DOM_NO_ERR) {
 			return err;
 		}
 
+		/* Make a temp prefix dom_string */
+		err = _dom_resource_mgr_create_string_from_lwcstring(&rm, 
+				node->prefix, &temp);
+		if (err != DOM_NO_ERR) {
+			dom_string_unref(colon);
+			return err;
+		}
+
 		/* Prefix + : */
-		err = dom_string_concat(node->prefix, colon, &node_name);
+		err = dom_string_concat(temp, colon, &node_name);
 		if (err != DOM_NO_ERR) {
+			dom_string_unref(temp);
 			dom_string_unref(colon);
 			return err;
 		}
+		/*Finished with temp*/
+		dom_string_unref(temp);
 
 		/* Finished with colon */
 		dom_string_unref(colon);
 
+		/* Make a temp name dom_string */
+		err = _dom_resource_mgr_create_string_from_lwcstring(&rm, 
+				node->name, &temp);
+		if (err != DOM_NO_ERR) {
+			return err;
+		}
 		/* Prefix + : + Localname */
-		err = dom_string_concat(node_name, node->name, &colon);
+		err = dom_string_concat(node_name, temp, &colon);
 		if (err != DOM_NO_ERR) {
+			dom_string_unref(temp);
 			dom_string_unref(node_name);
 			return err;
 		}
 
+		/* Finished with temp */
+		dom_string_unref(temp);
 		/* Finished with intermediate node name */
 		dom_string_unref(node_name);
 
 		node_name = colon;
 	} else {
-		dom_string_ref(node->name);
-
-		node_name = node->name;
+		err = _dom_resource_mgr_create_string_from_lwcstring(&rm, 
+				node->name, &node_name);
+		if (err != DOM_NO_ERR) {
+			return err;
+		}
 	}
 
 	*result = node_name;
@@ -384,10 +505,6 @@
 dom_exception _dom_node_get_node_value(dom_node_internal *node,
 		struct dom_string **result)
 {
-	if (node->type == DOM_ATTRIBUTE_NODE) {
-		return dom_attr_get_value((struct dom_attr *) node, result);
-	}
-
 	if (node->value != NULL)
 		dom_string_ref(node->value);
 
@@ -412,6 +529,9 @@
 dom_exception _dom_node_set_node_value(dom_node_internal *node,
 		struct dom_string *value)
 {
+	/* TODO
+	 * Whether we should change this to a virtual function? 
+	 */
 	/* This is a NOP if the value is defined to be null. */
 	if (node->type == DOM_DOCUMENT_NODE || 
 			node->type == DOM_DOCUMENT_FRAGMENT_NODE || 
@@ -507,7 +627,7 @@
 	if (node->owner == NULL)
 		return DOM_NOT_SUPPORTED_ERR;
 
-	return dom_document_get_nodelist(node->owner, node, 
+	return _dom_document_get_nodelist(node->owner, DOM_NODELIST_CHILDREN, node, 
 			NULL, NULL, NULL, result);
 }
 
@@ -630,13 +750,10 @@
 dom_exception _dom_node_get_attributes(dom_node_internal *node,
 		struct dom_namednodemap **result)
 {
-	if (node->type != DOM_ELEMENT_NODE) {
-		*result = NULL;
+	UNUSED(node);
+	*result = NULL;
 
-		return DOM_NO_ERR;
-	}
-
-	return dom_element_get_attributes((struct dom_element *) node, result);
+	return DOM_NO_ERR;
 }
 
 /**
@@ -664,7 +781,7 @@
 
 	/* If there is an owner, increase its reference count */
 	if (node->owner != NULL)
-		dom_node_ref((dom_node_internal *) node->owner);
+		dom_node_ref(node->owner);
 
 	*result = node->owner;
 
@@ -729,19 +846,10 @@
 	}
 
 	/* Ensure that new_child is permitted as a child of node */
-	if (!_dom_node_permitted_child(node, new_child))
+	if (new_child->type != DOM_DOCUMENT_FRAGMENT_NODE && 
+			!_dom_node_permitted_child(node, new_child))
 		return DOM_HIERARCHY_REQUEST_ERR;
 
-	/* DocumentType nodes are created outside the Document so, 
-	 * if we're trying to attach a DocumentType node, then we
-	 * also need to set its owner. */
-	if (node->type == DOM_DOCUMENT_NODE &&
-			new_child->type == DOM_DOCUMENT_TYPE_NODE) {
-		/* See long comment in dom_node_initialise as to why 
-		 * we don't ref the document here */
-		new_child->owner = (struct dom_document *) node;
-	}
-
 	/* Attempting to insert a node before itself is a NOP */
 	if (new_child == ref_child) {
 		dom_node_ref(new_child);
@@ -759,9 +867,18 @@
 		_dom_node_detach(new_child);
 	}
 
+	/* When a Node is attached, it should be removed from the pending list */
+	dom_node_remove_pending(new_child);
+
 	/* If new_child is a DocumentFragment, insert its children 
 	 * Otherwise, insert new_child */
 	if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
+		/* Test the children of the docment fragment can be appended */
+		dom_node_internal *c = new_child->first_child;
+		for (; c != NULL; c = c->next)
+			if (!_dom_node_permitted_child(node, c))
+				return DOM_HIERARCHY_REQUEST_ERR;
+
 		if (new_child->first_child != NULL) {
 			_dom_node_attach_range(new_child->first_child, 
 					new_child->last_child, 
@@ -783,6 +900,16 @@
 						  : ref_child);
 	}
 
+	/* DocumentType nodes are created outside the Document so, 
+	 * if we're trying to attach a DocumentType node, then we
+	 * also need to set its owner. */
+	if (node->type == DOM_DOCUMENT_NODE &&
+			new_child->type == DOM_DOCUMENT_TYPE_NODE) {
+		/* See long comment in _dom_node_initialise as to why 
+		 * we don't ref the document here */
+		new_child->owner = (struct dom_document *) node;
+	}
+
 	/** \todo Is it correct to return DocumentFragments? */
 
 	dom_node_ref(new_child);
@@ -853,9 +980,22 @@
 	}
 
 	/* Ensure that new_child is permitted as a child of node */
-	if (!_dom_node_permitted_child(node, new_child))
-		return DOM_HIERARCHY_REQUEST_ERR;
+	if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
+		/* If this node is a doc fragment, we should test all its 
+		 * children nodes */
+		dom_node_internal *c;
+		c = new_child->first_child;
+		while (c != NULL) {
+			if (!_dom_node_permitted_child(node, c))
+				return DOM_HIERARCHY_REQUEST_ERR;
 
+			c = c->next;
+		}
+	} else {
+		if (!_dom_node_permitted_child(node, new_child))
+			return DOM_HIERARCHY_REQUEST_ERR;
+	}
+
 	/* Attempting to replace a node with itself is a NOP */
 	if (new_child == old_child) {
 		dom_node_ref(old_child);
@@ -878,6 +1018,8 @@
 
 	/* Sort out the return value */
 	dom_node_ref(old_child);
+	/* The replaced node should be marded pending */
+	dom_node_mark_pending(old_child);
 	*result = old_child;
 
 	return DOM_NO_ERR;
@@ -922,8 +1064,13 @@
 	/* Detach the node */
 	_dom_node_detach(old_child);
 
-	/* Sort out the return value */
+	/* When a Node is removed, it should be destroy. When its refcnt is not 
+	 * zero, it will be added to the document's deletion pending list. 
+	 * When a Node is removed, its parent should be NULL, but its owner should 
+	 * remain to be the document.
+	 */
 	dom_node_ref(old_child);
+	dom_node_try_destroy(old_child);
 	*result = old_child;
 
 	return DOM_NO_ERR;
@@ -1015,15 +1162,66 @@
  *
  * \todo work out what happens when cloning Document, DocumentType, Entity
  * and Notation nodes.
+ *
+ * Note: we adopt a OO paradigm, this clone_node just provide a basic operation
+ * of clone. Special clones like Attr/EntitiReference stated above should provide
+ * their overload of this interface in their implementation file. 
  */
 dom_exception _dom_node_clone_node(dom_node_internal *node, bool deep,
 		dom_node_internal **result)
 {
-	UNUSED(node);
-	UNUSED(deep);
-	UNUSED(result);
+	dom_node_internal *n, *child, *r;
+	dom_exception err;
+	dom_document *doc;
+	dom_user_data *ud;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	doc = node->owner;
+	assert(doc != NULL);
+
+	err = dom_node_alloc(doc, node, &n);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = dom_node_copy(n, node);
+	if (err != DOM_NO_ERR) {
+		_dom_document_alloc(doc, n, 0);
+		return err;
+	}
+
+	if (deep) {
+		child = node->first_child;
+		while (child != NULL) {
+			err = dom_node_clone_node(child, deep, (void *) &r);
+			if (err != DOM_NO_ERR) {
+				dom_node_unref(n);
+				return err;
+			}
+
+			err = dom_node_append_child(n, r, (void *) &r);
+			if (err != DOM_NO_ERR) {
+				dom_node_unref(n);
+				return err;
+			}
+			
+			/* Clean up the new node, we have reference it two times */
+			dom_node_unref(r);
+			dom_node_unref(r);
+			child = child->next;
+		}
+	}
+
+	*result = n;
+
+	/* Call the dom_user_data_handlers */
+	ud = node->user_data;
+	while (ud != NULL) {
+		if (ud->handler != NULL)
+			ud->handler(DOM_NODE_CLONED, ud->key, ud->data, 
+					(dom_node *) node, (dom_node *) n);
+		ud = ud->next;
+	}
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1038,9 +1236,36 @@
  */
 dom_exception _dom_node_normalize(dom_node_internal *node)
 {
-	UNUSED(node);
+	dom_node_internal *n, *p;
+	dom_exception err;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	p = node->first_child;
+	if (p == NULL)
+		return DOM_NO_ERR;
+
+	n = p->next;
+
+	while (n != NULL) {
+		if (n->type == DOM_TEXT_NODE && p->type == DOM_TEXT_NODE) {
+			err = _dom_merge_adjacent_text(p, n);
+			if (err != DOM_NO_ERR)
+				return err;
+
+			_dom_node_detach(n);
+			dom_node_unref(n);
+			n = p->next;
+			continue;
+		}
+		if (n->type != DOM_TEXT_NODE) {
+			err = dom_node_normalize(n);
+			if (err != DOM_NO_ERR)
+				return err;
+		}
+		p = n;
+		n = n->next;
+	}
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1054,15 +1279,22 @@
  * \return DOM_NO_ERR.
  */
 dom_exception _dom_node_is_supported(dom_node_internal *node,
-		struct dom_string *feature, dom_node_internal *version,
+		struct dom_string *feature, struct dom_string *version,
 		bool *result)
 {
-	UNUSED(node);
-	UNUSED(feature);
-	UNUSED(version);
-	UNUSED(result);
+	dom_document *doc;
+	dom_implementation *impl; 
+	bool has;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	doc = node->owner;
+	assert(doc != NULL);
+	dom_document_get_implementation(doc, &impl);
+	assert(impl != NULL);
+	dom_implementation_has_feature(impl, feature, version, &has);
+
+	*result = has;
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1079,13 +1311,18 @@
 dom_exception _dom_node_get_namespace(dom_node_internal *node,
 		struct dom_string **result)
 {
+	lwc_context *ctx;
+
+	assert(node->owner != NULL);
+	ctx = _dom_document_get_intern_context(node->owner);
+	assert(ctx != NULL);
+
 	/* If there is a namespace, increase its reference count */
 	if (node->namespace != NULL)
-		dom_string_ref(node->namespace);
+		lwc_context_string_ref(ctx, node->namespace);
 
-	*result = node->namespace;
-
-	return DOM_NO_ERR;
+	return _dom_document_create_string_from_lwcstring(node->owner, node->namespace,
+			result);
 }
 
 /**
@@ -1102,13 +1339,18 @@
 dom_exception _dom_node_get_prefix(dom_node_internal *node,
 		struct dom_string **result)
 {
+	lwc_context *ctx;
+
+	assert(node->owner != NULL);
+	ctx = _dom_document_get_intern_context(node->owner);
+	assert(ctx != NULL);
+	
 	/* If there is a prefix, increase its reference count */
 	if (node->prefix != NULL)
-		dom_string_ref(node->prefix);
+		lwc_context_string_ref(ctx, node->prefix);
 
-	*result = node->prefix;
-
-	return DOM_NO_ERR;
+	return _dom_document_create_string_from_lwcstring(node->owner, node->prefix,
+			result);
 }
 
 /**
@@ -1137,6 +1379,13 @@
 dom_exception _dom_node_set_prefix(dom_node_internal *node,
 		struct dom_string *prefix)
 {
+	dom_exception err;
+	lwc_string *str;
+	lwc_context *docctx;
+
+	docctx = _dom_document_get_intern_context(node->owner);
+	assert(docctx != NULL);
+
 	/* Only Element and Attribute nodes created using 
 	 * namespace-aware methods may have a prefix */
 	if ((node->type != DOM_ELEMENT_NODE &&
@@ -1154,7 +1403,7 @@
 
 	/* No longer want existing prefix */
 	if (node->prefix != NULL) {
-		dom_string_unref(node->prefix);
+		lwc_context_string_unref(docctx, node->prefix);
 	}
 
 	/* Set the prefix */
@@ -1163,8 +1412,11 @@
 		if (dom_string_length(prefix) == 0) {
 			node->prefix = NULL;
 		} else {
-			dom_string_ref(prefix);
-			node->prefix = prefix;
+			err = _dom_node_get_intern_string(node, prefix, &str);
+			if (err != DOM_NO_ERR)
+				return err;
+
+			node->prefix = str;
 		}
 	} else {
 		node->prefix = NULL;
@@ -1186,7 +1438,13 @@
  */
 dom_exception _dom_node_get_local_name(dom_node_internal *node,
 		struct dom_string **result)
-{
+{	
+	lwc_context *ctx;
+
+	assert(node->owner != NULL);
+	ctx = _dom_document_get_intern_context(node->owner);
+	assert(ctx != NULL);
+	
 	/* Only Element and Attribute nodes may have a local name */
 	if (node->type != DOM_ELEMENT_NODE && 
 			node->type != DOM_ATTRIBUTE_NODE) {
@@ -1194,19 +1452,13 @@
 		return DOM_NO_ERR;
 	}
 
-	/* Node must have been created using a namespace-aware method */
-	if (node->namespace == NULL) {
-		*result = NULL;
-		return DOM_NO_ERR;
-	}
-
 	/* The node may have a local name, reference it if so */
 	if (node->name != NULL) {
-		dom_string_ref(node->name);
+		lwc_context_string_ref(ctx, node->name);
 	}
-	*result = node->name;
 
-	return DOM_NO_ERR;
+	return _dom_document_create_string_from_lwcstring(node->owner, node->name,
+			result);
 }
 
 /**
@@ -1218,13 +1470,10 @@
  */
 dom_exception _dom_node_has_attributes(dom_node_internal *node, bool *result)
 {
-	if (node->type != DOM_ELEMENT_NODE) {
-		*result = false;
+	UNUSED(node);
+	*result = false;
 
-		return DOM_NO_ERR;
-	}
-
-	return dom_element_has_attributes((struct dom_element *) node, result);
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1286,10 +1535,21 @@
 dom_exception _dom_node_get_text_content(dom_node_internal *node,
 		struct dom_string **result)
 {
-	UNUSED(node);
-	UNUSED(result);
+	dom_node_internal *n;
+	dom_string *str;
+	dom_string *ret;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	assert(node->owner != NULL);
+
+	for (n = node->first_child; n != NULL; n = n->next) {
+		dom_node_get_text_content(n, &ret);
+		dom_string_concat(str, ret, &str);
+	}
+
+	dom_string_ref(str);
+	*result = str;
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1306,10 +1566,36 @@
 dom_exception _dom_node_set_text_content(dom_node_internal *node,
 		struct dom_string *content)
 {
-	UNUSED(node);
-	UNUSED(content);
+	dom_node_internal *n, *p, *r;
+	dom_document *doc;
+	dom_text *text;
+	dom_exception err;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	n = node->first_child;
+
+	while (n != NULL) {
+		p = n;
+		n = n->next;
+		/* Add the (void *) casting to avoid gcc warning:
+		 * dereferencing type-punned pointer will break 
+		 * strict-aliasing rules */
+		err = dom_node_remove_child(node, n, (void *) &r);
+		if (err != DOM_NO_ERR)
+			return err;
+	}
+
+	doc = node->owner;
+	assert(doc != NULL);
+
+	err = dom_document_create_text_node(doc, content, &text);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_node_append_child(node, text, (void *) &r);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1345,11 +1631,12 @@
 dom_exception _dom_node_lookup_prefix(dom_node_internal *node,
 		struct dom_string *namespace, struct dom_string **result)
 {
-	UNUSED(node);
-	UNUSED(namespace);
-	UNUSED(result);
+	if (node->parent != NULL)
+		return dom_node_lookup_prefix(node, namespace, result);
+	else
+		*result = NULL;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1363,11 +1650,11 @@
 dom_exception _dom_node_is_default_namespace(dom_node_internal *node,
 		struct dom_string *namespace, bool *result)
 {
-	UNUSED(node);
-	UNUSED(namespace);
-	UNUSED(result);
-
-	return DOM_NOT_SUPPORTED_ERR;
+	if (node->parent != NULL)
+		return dom_node_is_default_namespace(node, namespace, result);
+	else
+		*result = false;
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1385,11 +1672,12 @@
 dom_exception _dom_node_lookup_namespace(dom_node_internal *node,
 		struct dom_string *prefix, struct dom_string **result)
 {
-	UNUSED(node);
-	UNUSED(prefix);
-	UNUSED(result);
+	if (node->parent != NULL)
+		return dom_node_lookup_namespace(node->parent, prefix, result);
+	else
+		*result = NULL;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1410,15 +1698,104 @@
  *   + publicId, systemId, internalSubset are equal
  *   + The node entities are equal
  *   + The node notations are equal
+ * TODO: in document_type, we should override this virtual function
  */
 dom_exception _dom_node_is_equal(dom_node_internal *node,
 		dom_node_internal *other, bool *result)
 {
-	UNUSED(node);
-	UNUSED(other);
-	UNUSED(result);
+	dom_exception err;
+	dom_string *s1, *s2;
+	lwc_context *c1, *c2;
+	dom_namednodemap *m1, *m2;
+	dom_nodelist *l1, *l2;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	if (node->type != other->type){
+		*result = false;
+		return DOM_NO_ERR;
+	}
+
+	assert(node->owner != NULL);
+	assert(other->owner != NULL);
+
+	err = dom_node_get_node_name(node, &s1);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = dom_node_get_node_name(other, &s2);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if (dom_string_cmp(s1, s2) != 0) {
+		*result = false;
+		return DOM_NO_ERR;
+	}
+	
+	c1 = _dom_document_get_intern_context(node->owner);
+	assert(c1 != NULL);
+
+	c2 = _dom_document_get_intern_context(other->owner);
+	assert(c2 != NULL);
+	
+	if (c1 == c2) {
+		if (node->name != other->name || 
+				node->namespace != other->namespace ||
+				node->prefix != other->prefix) {
+			*result = false;
+			return DOM_NO_ERR;
+		}
+	} else {
+		if (_dom_lwc_string_compare_raw(node->name, other->name) != 0){
+			*result = false;
+			return DOM_NO_ERR;
+		}
+
+		if (_dom_lwc_string_compare_raw(node->namespace, other->namespace) != 0){
+			*result = false;
+			return DOM_NO_ERR;
+		}
+
+		if (_dom_lwc_string_compare_raw(node->prefix, other->prefix) != 0){
+			*result = false;
+			return DOM_NO_ERR;
+		}
+	}
+
+	if (dom_string_cmp(node->value, other->value) != 0) {
+		*result = false;
+		return DOM_NO_ERR;
+	}
+
+	// Following comes the attributes
+	err = dom_node_get_attributes(node, &m1);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_node_get_attributes(other, &m2);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if (dom_namednodemap_equal(m1, m2) != true) {
+		*result = false;
+		return DOM_NO_ERR;
+	}
+
+	// Finally the childNodes
+	err = dom_node_get_child_nodes(node, &l1);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	err = dom_node_get_child_nodes(other, &l2);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if (dom_nodelist_equal(l1, l2) != true) {
+		*result = false;
+		return DOM_NO_ERR;
+	}
+
+	*result = true;
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1435,12 +1812,23 @@
 		struct dom_string *feature, struct dom_string *version,
 		void **result)
 {
-	UNUSED(node);
-	UNUSED(feature);
-	UNUSED(version);
-	UNUSED(result);
+	dom_document *doc;
+	dom_implementation *impl; 
+	bool has;
 
-	return DOM_NOT_SUPPORTED_ERR;
+	doc = node->owner;
+	assert(doc != NULL);
+	dom_document_get_implementation(doc, &impl);
+	assert(impl != NULL);
+	dom_implementation_has_feature(impl, feature, version, &has);
+
+	if (has) {
+		*result = node;
+	} else {
+		*result = NULL;
+	}
+
+	return DOM_NO_ERR;
 }
 
 /**
@@ -1479,14 +1867,14 @@
 
 		*result = ud->data;
 
-		dom_document_alloc(node->owner, ud, 0);
+		_dom_document_alloc(node->owner, ud, 0);
 
 		return DOM_NO_ERR;
 	}
 
 	/* Otherwise, create a new user data object if one wasn't found */
 	if (ud == NULL) {
-		ud = dom_document_alloc(node->owner, NULL, 
+		ud = _dom_document_alloc(node->owner, NULL, 
 				sizeof(struct dom_user_data));
 		if (ud == NULL)
 			return DOM_NO_MEM_ERR;
@@ -1542,10 +1930,127 @@
 	return DOM_NO_ERR;
 }
 
-/*                                                                            */
+
 /*----------------------------------------------------------------------------*/
-/*                                                                            */
 
+/* The protected virtual functions */
+
+/* We should never call this pure-virtual function directly */
+dom_exception _dom_node_alloc(struct dom_document *doc, 
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	UNUSED(doc);
+	UNUSED(n);
+	UNUSED(ret);
+
+	return DOM_NOT_SUPPORTED_ERR;
+}
+
+
+/* 
+ * Copy the internal attributes of a Node from old to new
+ */
+dom_exception _dom_node_copy(dom_node_internal *new, dom_node_internal *old)
+{
+	lwc_context *nctx, *octx;
+	dom_exception err;
+
+	new->vtable = old->vtable;
+	new->base.vtable = old->base.vtable;
+
+	assert(old->owner != NULL);
+	octx = _dom_document_get_intern_context(old->owner);
+	assert(octx != NULL);
+
+	assert(new->owner != NULL);
+	nctx = _dom_document_get_intern_context(old->owner);
+	assert(nctx != NULL);
+
+	new->type = old->type;
+	new->parent = NULL;
+	new->first_child = NULL;
+	new->last_child = NULL;
+	new->previous = NULL;
+	new->next = NULL;
+	new->owner = old->owner;
+
+	if (octx == nctx) {
+		lwc_context_string_ref(octx, old->name);
+		new->name = old->name;
+
+		if (old->namespace != NULL)
+			lwc_context_string_ref(octx, old->namespace);
+		new->namespace = old->namespace;
+
+		if (old->prefix != NULL)
+			lwc_context_string_ref(octx, old->prefix);
+		new->prefix = old->prefix;
+	} else {
+		lwc_string *str;
+		lwc_error lerr;
+
+		lerr = lwc_context_intern(nctx, lwc_string_data(old->name),
+				lwc_string_length(old->name), &str);
+		if (lerr != lwc_error_ok)
+			return _dom_exception_from_lwc_error(lerr);
+
+		new->name = str;
+
+		if (old->namespace != NULL) {
+			lerr = lwc_context_intern(nctx, 
+					lwc_string_data(old->namespace),
+					lwc_string_length(old->namespace), &str);
+			if (lerr != lwc_error_ok)
+				return _dom_exception_from_lwc_error(lerr);
+
+			new->namespace = str;
+		} else
+			new->namespace = NULL;
+
+		if (old->prefix != NULL) {
+			lerr = lwc_context_intern(nctx, 
+					lwc_string_data(old->prefix),
+					lwc_string_length(old->prefix), &str);
+			if (lerr != lwc_error_ok)
+				return _dom_exception_from_lwc_error(lerr);
+
+			new->prefix = str;
+		} else
+			new->prefix = NULL;
+	}
+
+	dom_alloc al;
+	void *pw;
+	
+	if (old->value != NULL) {
+		_dom_document_get_allocator(new->owner, &al, &pw);
+		dom_string *value;
+		err = dom_string_clone(al, pw, old->value, &value);
+		if (err != DOM_NO_ERR)
+			return err;
+		
+		new->value = value;
+	} else {
+		new->value = NULL;
+	}
+	
+	new->user_data = NULL;
+	new->refcnt = 1;
+
+	list_init(&new->pending_list);
+	/* The new copyed node has no parent, 
+	 * so it should be put in the pending list. 
+	 */
+	dom_node_mark_pending(new);
+
+	return DOM_NO_ERR;
+}
+
+
+/*----------------------------------------------------------------------------*/
+
+/*  The helper functions */
+
 /**
  * Determine if a node is permitted as a child of another node
  *
@@ -1626,23 +2131,21 @@
  */
 bool _dom_node_readonly(const dom_node_internal *node)
 {
-	/* DocumentType and Notation nodes are read only */
-	if (node->type == DOM_DOCUMENT_TYPE_NODE ||
-			node->type == DOM_NOTATION_NODE)
+	const dom_node_internal *n = node;
+
+	/* DocumentType and Notation ns are read only */
+	if (n->type == DOM_DOCUMENT_TYPE_NODE ||
+			n->type == DOM_NOTATION_NODE)
 		return true;
 
-	/* Entity nodes and their descendants are read only */
-	for (; node != NULL; node = node->parent) {
-		if (node->type == DOM_ENTITY_NODE)
+	/* Entity ns and their descendants are read only 
+	 * EntityReference ns and their descendants are read only */
+	for (n = node; n != NULL; n = n->parent) {
+		if (n->type == DOM_ENTITY_NODE
+				|| n->type == DOM_ENTITY_REFERENCE_NODE)
 			return true;
 	}
 
-	/* EntityReference nodes and their descendants are read only */
-	for (; node != NULL; node = node->parent) {
-		if (node->type == DOM_ENTITY_REFERENCE_NODE)
-			return true;
-	}
-
 	/* Otherwise, it's writable */
 	return false;
 }
@@ -1668,6 +2171,10 @@
  */
 void _dom_node_detach(dom_node_internal *node)
 {
+	/* When a Node is not in the document tree, it must be in the 
+		   pending list */
+	dom_node_mark_pending(node);
+
 	_dom_node_detach_range(node, node);
 }
 
@@ -1701,8 +2208,9 @@
 	else
 		parent->last_child = last;
 
-	for (dom_node_internal *n = first; n != last->next; n = n->next)
+	for (dom_node_internal *n = first; n != last->next; n = n->next) {
 		n->parent = parent;
+	}
 }
 
 /**
@@ -1726,8 +2234,9 @@
 	else
 		last->parent->last_child = first->previous;
 
-	for (dom_node_internal *n = first; n != last->next; n = n->next)
+	for (dom_node_internal *n = first; n != last->next; n = n->next) {
 		n->parent = NULL;
+	}
 
 	first->previous = NULL;
 	last->next = NULL;
@@ -1771,9 +2280,208 @@
 	else
 		old->parent->last_child = last;
 
-	for (dom_node_internal *n = first; n != last->next; n = n->next)
+	for (dom_node_internal *n = first; n != last->next; n = n->next) {
 		n->parent = old->parent;
+	}
 
 	old->previous = old->next = old->parent = NULL;
 }
 
+/**
+ * Migrate one lwc_string from one context to another, this function 
+ * may be used when we import/adopt a Node between documents.
+ *
+ * \param old	The source context
+ * \param new	The new context
+ * \param string	The lwc_string to migrate
+ */
+dom_exception _redocument_lwcstring(lwc_context *old, lwc_context *new, 
+		lwc_string **string)
+{
+	lwc_string *str;
+	lwc_error lerr;
+
+	lerr = lwc_context_intern(new, lwc_string_data(*string),
+			lwc_string_length(*string), &str);
+	if (lerr != lwc_error_ok)
+		return _dom_exception_from_lwc_error(lerr);
+
+	lwc_context_string_unref(old, *string);
+	*string = str;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Migrate one dom_string from one document to another, this function 
+ * may be used when we import/adopt a Node between documents.
+ *
+ * \param old	The source document 
+ * \param new	The new document
+ * \param string	The dom_string to migrate
+ */
+dom_exception _redocument_domstring(dom_document *old, dom_document* new,
+		dom_string **string)
+{
+	dom_exception err;
+	dom_string *str;
+
+	UNUSED(old);
+	err = _dom_document_create_string(new, NULL, 0, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_string_dup(*string, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	dom_string_unref(*string);
+	*string = str;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Merge two adjacent text into one text node.
+ *
+ * \param p	The first text node
+ * \param n	The second text node
+ */
+dom_exception _dom_merge_adjacent_text(dom_node_internal *p, dom_node_internal *n)
+{
+	assert(p->type = DOM_TEXT_NODE);
+	assert(n->type = DOM_TEXT_NODE);
+
+	dom_string *str;
+	dom_exception err;
+
+	err = dom_text_get_whole_text(n, &str);
+	if (err != DOM_NO_ERR)
+		return err;
+	
+	err = dom_characterdata_append_data(p, str);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	dom_string_unref(str);
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Intern a dom_string using the node's owner document's lwc_context
+ *
+ * \param node	The node
+ * \param str	The dom_string to be interned
+ * \param intern	The returned interned string
+ */
+dom_exception _dom_node_get_intern_string(dom_node_internal *node, 
+		dom_string *str, lwc_string **intern)
+{
+	dom_exception err;
+	lwc_context *ctx, *docctx;
+	lwc_string *ret;
+
+	assert(str != NULL);
+	assert(node->owner != NULL);
+
+	docctx = _dom_document_get_intern_context(node->owner);
+	assert(docctx != NULL);
+
+	err = dom_string_get_intern(str, &ctx, &ret);
+	if (err != DOM_NO_ERR)
+		return err;
+
+	if (ctx != docctx) {
+		err = _dom_string_intern(str, docctx, &ret);
+		if (err != DOM_NO_ERR)
+			return err;
+	}
+	
+	*intern = ret;
+
+	return DOM_NO_ERR;
+}
+
+/**
+ * Unref a lwc_string used in this node
+ *
+ * \param node 	The node
+ * \param intern	The lwc_string to unref
+ */
+void _dom_node_unref_intern_string(dom_node_internal *node, 
+		struct lwc_string_s *intern)
+{
+	struct dom_resource_mgr rm;	
+	struct dom_document *doc = node->owner;
+
+	if (doc != NULL) {
+		_dom_document_get_resource_mgr(doc, &rm);
+	} else if (node->type == DOM_DOCUMENT_TYPE_NODE) {
+		_dom_document_type_get_resource_mgr((dom_document_type *) node, &rm);
+	}
+
+	lwc_context_string_unref(rm.ctx, intern);
+}
+
+/**
+ * Try to destroy this node. 
+ * When some node owns this node, (such as an elment owns its attribute nodes)
+ * when this node being not owned, the owner should call this function to try
+ * to destroy this node. 
+ *
+ * @note: Owning a node does not means this node's refcnt is above zero.
+ *
+ * \param node	The node to destroy
+ */
+void _dom_node_try_destroy(dom_node_internal *node)
+{
+	if (node == NULL)
+		return;
+
+	if (node->parent == NULL) {
+		if (node->refcnt == 0) {
+			dom_node_destroy(node);
+		} else if (node->pending_list.prev == &node->pending_list){
+			assert (node->pending_list.next == &node->pending_list);
+		    list_append(&node->owner->pending_nodes, &node->pending_list);
+		}
+	}
+}
+
+/**
+ * To add some node to the pending list, when a node is removed from its parent
+ * or an attribute is removed from its element
+ */
+void _dom_node_mark_pending(dom_node_internal *node)
+{
+	struct dom_document *doc = node->owner;
+
+	/* TODO: the pending_list is located at in dom_document, but some
+	 * nodes can be created without a document created, such as a 
+	 * dom_document_type node. For this reason, we should test whether
+	 * the doc is NULL
+	 */ 
+	if (doc != NULL) {
+		/* The node must not be in the pending list */
+		assert(node->pending_list.prev == &node->pending_list);
+
+		list_append(&doc->pending_nodes, &node->pending_list);
+	}
+}
+
+/**
+ * To remove the node from the pending list, this may happen when
+ * a node is removed and then appended to another parent
+ */
+void _dom_node_remove_pending(dom_node_internal *node)
+{
+	struct dom_document *doc = node->owner;
+
+	if (doc != NULL) {
+		/* The node must be in the pending list */
+		assert(node->pending_list.prev != &node->pending_list);
+
+		list_del(&node->pending_list);
+	}
+}
Index: src/core/namednodemap.c
===================================================================
--- src/core/namednodemap.c	(revision 9058)
+++ src/core/namednodemap.c	(working copy)
@@ -3,8 +3,11 @@
  * Licensed under the MIT License,
  *                http://www.opensource.org/licenses/mit-license.php
  * Copyright 2007 John-Mark Bell <jmb at netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku at gmail.com>
  */
 
+#include <assert.h>
+
 #include <dom/core/element.h>
 #include <dom/core/node.h>
 #include <dom/core/string.h>
@@ -22,9 +25,10 @@
 struct dom_namednodemap {
 	struct dom_document *owner;	/**< Owning document */
 
-	struct dom_node_internal *head;		/**< Start of item list */
+	void *priv;			/**< Private data */
 
-	dom_node_type type;		/**< Type of items in map */
+	struct nnm_operation *opt;	/**< The underlaid operation 
+					 * 	implementations */
 
 	uint32_t refcnt;		/**< Reference count */
 };
@@ -33,7 +37,7 @@
  * Create a namednodemap
  *
  * \param doc   The owning document
- * \param head  Start of list containing items in map
+ * \param   Start of list containing items in map
  * \param type  The type of items in the map
  * \param map   Pointer to location to receive created map
  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
@@ -49,24 +53,21 @@
  * explicitly reference it. The client must unref the map once it is
  * finished with it.
  */
-dom_exception dom_namednodemap_create(struct dom_document *doc,
-		struct dom_node_internal *head, dom_node_type type,
+dom_exception _dom_namednodemap_create(struct dom_document *doc,
+		void *priv, struct nnm_operation *opt,
 		struct dom_namednodemap **map)
 {
 	struct dom_namednodemap *m;
 
-	m = dom_document_alloc(doc, NULL, sizeof(struct dom_namednodemap));
+	m = _dom_document_alloc(doc, NULL, sizeof(struct dom_namednodemap));
 	if (m == NULL)
 		return DOM_NO_MEM_ERR;
 
-	dom_node_ref((struct dom_node *) doc);
 	m->owner = doc;
 
-	dom_node_ref(head);
-	m->head = head;
+	m->priv = priv;
+	m->opt = opt;
 
-	m->type = type;
-
 	m->refcnt = 1;
 
 	*map = m;
@@ -81,6 +82,7 @@
  */
 void dom_namednodemap_ref(struct dom_namednodemap *map)
 {
+	assert(map != NULL);
 	map->refcnt++;
 }
 
@@ -94,22 +96,15 @@
  */
 void dom_namednodemap_unref(struct dom_namednodemap *map)
 {
+	if (map == NULL)
+		return;
+
 	if (--map->refcnt == 0) {
-		struct dom_node_internal *owner = 
-				(struct dom_node_internal *) map->owner;
+		/* Call the implementation specific destroy */
+		map->opt->namednodemap_destroy(map->priv);
 
-		dom_node_unref(map->head);
-
-		/* Remove map from document */
-		dom_document_remove_namednodemap(map->owner, map);
-
 		/* Destroy the map object */
-		dom_document_alloc(map->owner, map, 0);
-
-		/* And release our reference on the owning document
-		 * This must be last as, otherwise, it's possible that
-		 * the document is destroyed before we are */
-		dom_node_unref(owner);
+		_dom_document_alloc(map->owner, map, 0);
 	}
 }
 
@@ -123,29 +118,8 @@
 dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
 		unsigned long *length)
 {
-	struct dom_node_internal *cur;
-	unsigned long len = 0;
-
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-		cur = dom_element_get_first_attribute(
-				(struct dom_element *) map->head);
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		return DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	for (; cur != NULL; cur = cur->next) {
-		len++;
-	}
-
-	*length = len;
-
-	return DOM_NO_ERR;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_get_length(map->priv, length);
 }
 
 /**
@@ -162,33 +136,8 @@
 dom_exception _dom_namednodemap_get_named_item(struct dom_namednodemap *map,
 		struct dom_string *name, struct dom_node **node)
 {
-	struct dom_node_internal *cur;
-
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-		cur = dom_element_get_first_attribute(
-				(struct dom_element *) map->head);
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		return DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	for (; cur != NULL; cur = cur->next) {
-		if (dom_string_cmp(cur->name, name) == 0) {
-			break;
-		}
-	}
-
-	if (cur != NULL) {
-		dom_node_ref(cur);
-	}
-	*node = (struct dom_node *) cur;
-
-	return DOM_NO_ERR;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_get_named_item(map->priv, name, node);
 }
 
 /**
@@ -218,46 +167,8 @@
 dom_exception _dom_namednodemap_set_named_item(struct dom_namednodemap *map,
 		struct dom_node *arg, struct dom_node **node)
 {
-	dom_exception err;
-	struct dom_node_internal *n = (struct dom_node_internal *) arg;
-
-	/* Ensure arg and map belong to the same document */
-	if (n->owner != map->owner)
-		return DOM_WRONG_DOCUMENT_ERR;
-
-	/* Ensure map is writable */
-	if (_dom_node_readonly(map->head))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Ensure arg isn't attached to another element */
-	if (n->type == DOM_ATTRIBUTE_NODE && n->parent != NULL && 
-			n->parent != map->head)
-		return DOM_INUSE_ATTRIBUTE_ERR;
-
-	/* Ensure arg is permitted in the map */
-	if (n->type != map->type)
-		return DOM_HIERARCHY_REQUEST_ERR;
-
-	/* Now delegate to the container-specific function. 
-	 * NamedNodeMaps are live, so this is fine. */
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-		err = dom_element_set_attribute_node(
-				(struct dom_element *) map->head, 
-				(struct dom_attr *) arg, 
-				(struct dom_attr **) node);
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		err = DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	/* Reference counting is handled by the container-specific call */
-
-	return err;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_set_named_item(map->priv, arg, node);
 }
 
 /**
@@ -278,44 +189,8 @@
 		struct dom_namednodemap *map, struct dom_string *name,
 		struct dom_node **node)
 {
-	dom_exception err;
-
-	/* Ensure map is writable */
-	if (_dom_node_readonly(map->head))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Now delegate to the container-specific function. 
-	 * NamedNodeMaps are live, so this is fine. */
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-	{
-		struct dom_attr *attr;
-
-		err = dom_element_get_attribute_node(
-				(struct dom_element *) map->head,
-				name, &attr);
-		if (err == DOM_NO_ERR) {
-			err = dom_element_remove_attribute_node(
-				(struct dom_element *) map->head, 
-				attr, (struct dom_attr **) node);
-			if (err == DOM_NO_ERR) {
-				/* No longer want attr */
-				dom_node_unref((struct dom_node *) attr);
-			}
-		}
-	}
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		err = DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	/* Reference counting is handled by the container-specific call */
-
-	return err;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_remove_named_item(map->priv, name, node);
 }
 
 /**
@@ -335,36 +210,8 @@
 dom_exception _dom_namednodemap_item(struct dom_namednodemap *map,
 		unsigned long index, struct dom_node **node)
 {
-	struct dom_node_internal *cur;
-	unsigned long count = 0;
-
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-		cur = dom_element_get_first_attribute(
-				(struct dom_element *) map->head);
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		return DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	for (; cur != NULL; cur = cur->next) {
-		count++;
-
-		if ((index + 1) == count) {
-			break;
-		}
-	}
-
-	if (cur != NULL) {
-		dom_node_ref(cur);
-	}
-	*node = (struct dom_node *) cur;
-
-	return DOM_NO_ERR;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_item(map->priv, index, node);
 }
 
 /**
@@ -387,38 +234,8 @@
 		struct dom_namednodemap *map, struct dom_string *namespace,
 		struct dom_string *localname, struct dom_node **node)
 {
-	struct dom_node_internal *cur;
-
-	/** \todo ensure XML feature is supported */
-
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-		cur = dom_element_get_first_attribute(
-				(struct dom_element *) map->head);
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		return DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	for (; cur != NULL; cur = cur->next) {
-		if (((namespace == NULL && cur->namespace == NULL) || 
-			(namespace != NULL && 
-			dom_string_cmp(cur->namespace, namespace) == 0)) &&
-				dom_string_cmp(cur->name, localname) == 0) {
-			break;
-		}
-	}
-
-	if (cur != NULL) {
-		dom_node_ref(cur);
-	}
-	*node = (struct dom_node *) cur;
-
-	return DOM_NO_ERR;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_get_named_item_ns(map->priv, namespace, localname, node);
 }
 
 /**
@@ -454,48 +271,8 @@
 		struct dom_namednodemap *map, struct dom_node *arg,
 		struct dom_node **node)
 {
-	dom_exception err;
-	struct dom_node_internal *n = (struct dom_node_internal *) arg;
-
-	/** \todo ensure XML feature is supported */
-
-	/* Ensure arg and map belong to the same document */
-	if (n->owner != map->owner)
-		return DOM_WRONG_DOCUMENT_ERR;
-
-	/* Ensure map is writable */
-	if (_dom_node_readonly(map->head))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Ensure arg isn't attached to another element */
-	if (n->type == DOM_ATTRIBUTE_NODE && n->parent != NULL && 
-			n->parent != map->head)
-		return DOM_INUSE_ATTRIBUTE_ERR;
-
-	/* Ensure arg is permitted in the map */
-	if (n->type != map->type)
-		return DOM_HIERARCHY_REQUEST_ERR;
-
-	/* Now delegate to the container-specific function. 
-	 * NamedNodeMaps are live, so this is fine. */
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-		err = dom_element_set_attribute_node_ns(
-				(struct dom_element *) map->head, 
-				(struct dom_attr *) arg, 
-				(struct dom_attr **) node);
-		break;
-	case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		err = DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	/* Reference counting is handled by the container-specific call */
-
-	return err;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_set_named_item_ns(map->priv, arg, node);
 }
 
 /**
@@ -521,61 +298,28 @@
 		struct dom_namednodemap *map, struct dom_string *namespace,
 		struct dom_string *localname, struct dom_node **node)
 {
-	dom_exception err;
-
-	/** \todo ensure XML feature is supported */
-
-	/* Ensure map is writable */
-	if (_dom_node_readonly(map->head))
-		return DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-	/* Now delegate to the container-specific function. 
-	 * NamedNodeMaps are live, so this is fine. */
-	switch (map->type) {
-	case DOM_ATTRIBUTE_NODE:
-	{
-		struct dom_attr *attr;
-
-		err = dom_element_get_attribute_node_ns(
-				(struct dom_element *) map->head,
-				namespace, localname, &attr);
-		if (err == DOM_NO_ERR) {
-			err = dom_element_remove_attribute_node(
-				(struct dom_element *) map->head, 
-				attr, (struct dom_attr **) node);
-			if (err == DOM_NO_ERR) {
-				/* No longer want attr */
-				dom_node_unref((struct dom_node *) attr);
-			}
-		}
-	}
-		break;
-case DOM_NOTATION_NODE:
-	case DOM_ENTITY_NODE:
-		/** \todo handle notation and entity nodes */
-	default:
-		err = DOM_NOT_SUPPORTED_ERR;
-		break;
-	}
-
-	/* Reference counting is handled by the container-specific call */
-
-	return err;
+	assert(map->opt != NULL);
+	return map->opt->namednodemap_remove_named_item_ns(map->priv, namespace, localname, node);
 }
 
 /**
- * Match a namednodemap instance against a set of creation parameters
+ * Compare whether two NamedNodeMap are equal.
  *
- * \param map   The map to match
- * \param head  Start of list containing items in map
- * \param type  The type of items in the map
- * \return true if list matches, false otherwise
  */
-bool dom_namednodemap_match(struct dom_namednodemap *map,
-		struct dom_node_internal *head, dom_node_type type)
+bool _dom_namednodemap_equal(struct dom_namednodemap *m1, 
+		struct dom_namednodemap *m2)
 {
-	if (map->head == head && map->type == type)
-		return true;
+	assert(m1->opt != NULL);
+	return (m1->opt == m2->opt && m1->opt->namednodemap_equal(m1->priv, m2->priv));
+}
 
-	return false;
+/**
+ * Update the dom_namednodemap to make it as a proxy of another object
+ *
+ * \param map	The dom_namednodemap
+ * \param priv	The private data to change to
+ */
+void _dom_namednodemap_update(struct dom_namednodemap *map, void *priv)
+{
+	map->priv = priv;
 }
Index: src/core/node.h
===================================================================
--- src/core/node.h	(revision 9058)
+++ src/core/node.h	(working copy)
@@ -10,8 +10,13 @@
 
 #include <stdbool.h>
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include <dom/core/node.h>
+#include <dom/functypes.h>
 
+#include "utils/list.h"
+
 /**
  * User data context attached to a DOM node
  */
@@ -23,7 +28,23 @@
 	struct dom_user_data *next;	/**< Next in list */
 	struct dom_user_data *prev;	/**< Previous in list */
 };
+typedef struct dom_user_data dom_user_data;
 
+/* Internally, we need virtual functions too */
+typedef struct dom_node_protect_vtable {
+
+	void (*destroy)(dom_node_internal *n);
+					/**< The destroy vitual function, it 
+					 * should be privated to client */
+	dom_exception (*alloc)(struct dom_document *doc, 
+			dom_node_internal *n, dom_node_internal **ret);
+					/**< Alloc the memory of the new Node */
+	dom_exception (*copy)(dom_node_internal *new, dom_node_internal *old);
+					/**< Copy the old to new as well as 
+					 * all its attribute, but not its childs
+					 */
+} dom_node_protect_vtable; 
+
 /**
  * The real DOM node object
  *
@@ -31,11 +52,9 @@
  */
 struct dom_node_internal {
 	struct dom_node base;		/**< The vtable base */
-	void (*destroy)(dom_node_internal *n);
-					/**< The destroy vitual function, it 
-					 * should be privated to client */
+	void *vtable;			/**< The protected vtable */
 
-	struct dom_string *name;	/**< Node name (this is the local part 
+	struct lwc_string_s *name;	/**< Node name (this is the local part 
 					 * of a QName in the cases where a 
 					 * namespace exists) */
 	struct dom_string *value;	/**< Node value */
@@ -48,27 +67,37 @@
 
 	struct dom_document *owner;	/**< Owning document */
 
-	struct dom_string *namespace;	/**< Namespace URI */
-	struct dom_string *prefix;	/**< Namespace prefix */
+	struct lwc_string_s *namespace;	/**< Namespace URI */
+	struct lwc_string_s *prefix;	/**< Namespace prefix */
 
 	struct dom_user_data *user_data;	/**< User data list */
 
 	uint32_t refcnt;		/**< Reference count */
+
+	struct list_entry pending_list; /**< The document delete pending list */
 };
 
-dom_node_internal * dom_node_create(struct dom_document *doc);
+dom_node_internal * _dom_node_create(struct dom_document *doc);
 
-dom_exception dom_node_initialise(struct dom_node_internal *node,
+dom_exception _dom_node_initialise(struct dom_node_internal *node,
 		struct dom_document *doc, dom_node_type type,
-		struct dom_string *name, struct dom_string *value,
-		struct dom_string *namespace, struct dom_string *prefix);
+		struct lwc_string_s *name, struct dom_string *value,
+		struct lwc_string_s *namespace, struct lwc_string_s *prefix);
 
-void dom_node_finalise(struct dom_document *doc, dom_node_internal *node);
+dom_exception _dom_node_initialise_generic(
+		struct dom_node_internal *node, struct dom_document *doc,
+		dom_alloc alloc, void *pw, struct lwc_context_s *ctx,
+	 	dom_node_type type, struct lwc_string_s *name, 
+		struct dom_string *value, struct lwc_string_s *namespace, 
+		struct lwc_string_s *prefix);
 
+void _dom_node_finalise(struct dom_document *doc, dom_node_internal *node);
+void _dom_node_finalise_generic(dom_node_internal *node, dom_alloc alloc, 
+		void *pw, struct lwc_context_s *ctx);
+
 bool _dom_node_readonly(const dom_node_internal *node);
 
 /* The DOM Node's vtable methods */
-void _dom_node_destroy(struct dom_node_internal *node);
 dom_exception _dom_node_get_node_name(dom_node_internal *node,
 		struct dom_string **result);
 dom_exception _dom_node_get_node_value(dom_node_internal *node,
@@ -110,7 +139,7 @@
 		dom_node_internal **result);
 dom_exception _dom_node_normalize(dom_node_internal *node);
 dom_exception _dom_node_is_supported(dom_node_internal *node,
-		struct dom_string *feature, dom_node_internal *version,
+		struct dom_string *feature, struct dom_string *version,
 		bool *result);
 dom_exception _dom_node_get_namespace(dom_node_internal *node,
 		struct dom_string **result);
@@ -188,11 +217,84 @@
 	_dom_node_get_user_data
 
 
+/* Follwoing comes the protected vtable */
+void _dom_node_destroy(struct dom_node_internal *node);
+dom_exception _dom_node_alloc(struct dom_document *doc,
+		struct dom_node_internal *n, struct dom_node_internal **ret);
+dom_exception _dom_node_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old);
+
+#define DOM_NODE_PROTECT_VTABLE \
+	_dom_node_destroy, \
+	_dom_node_alloc, \
+	_dom_node_copy
+
+
 /* The destroy API should be used inside DOM module */
-static inline void dom_node_destroy(struct dom_node *node)
+static inline void dom_node_destroy(struct dom_node_internal *node)
 {
-	((dom_node_internal *) node)->destroy((dom_node_internal *) node);
+	((dom_node_protect_vtable *) node->vtable)->destroy(node);
 }
-#define dom_node_destroy(n) dom_node_destroy((dom_node *) (n))
+#define dom_node_destroy(n) dom_node_destroy((dom_node_internal *) (n))
 
+/* Alloc the Node */
+static inline dom_exception dom_node_alloc(struct dom_document *doc, 
+		struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+	return ((dom_node_protect_vtable *) n->vtable)->alloc(doc, n, ret);
+}
+#define dom_node_alloc(d,n,r) dom_node_alloc((struct dom_document *) (d), \
+		(dom_node_internal *) (n), (dom_node_internal **) (r))
+
+
+/* Copy the Node old to new */
+static inline dom_exception dom_node_copy(struct dom_node_internal *new, 
+		struct dom_node_internal *old)
+{
+	return ((dom_node_protect_vtable *) old->vtable)->copy(new, old);
+}
+#define dom_node_copy(n,o) dom_node_copy((dom_node_internal *) (n), \
+		(dom_node_internal *) (o))
+
+/* Following are some helper functions */
+#define dom_node_get_owner(n) ((dom_node_internal *) (n))->owner
+
+#define dom_node_set_owner(n, d) ((dom_node_internal *) (n))->owner = \
+		(struct dom_document *) (d)
+
+#define dom_node_get_parent(n) ((dom_node_internal *) (n))->parent
+
+#define dom_node_set_parent(n, p) ((dom_node_internal *) (n))->parent = \
+		(dom_node_internal *) (p)
+
+#define dom_node_get_refcount(n) ((dom_node_internal *) (n))->refcnt
+
+dom_exception _redocument_lwcstring(lwc_context *old, lwc_context *new, 
+		lwc_string **string);
+dom_exception _redocument_domstring(struct dom_document *old, 
+		struct dom_document* new, struct dom_string **string);
+dom_exception _dom_merge_adjacent_text(dom_node_internal *p, dom_node_internal *n);
+/* Used to extract the lwc_string from dom_string of function param. 
+ * If there is no lwc_string inside the param, create one use the node->owner
+ * as document */
+dom_exception _dom_node_get_intern_string(dom_node_internal *node, 
+		struct dom_string *str, struct lwc_string_s **intern);
+void _dom_node_unref_intern_string(dom_node_internal *node, 
+		struct lwc_string_s *inter);
+
+/**
+ * Try to destroy the node, if its refcnt is not zeor, then append it to the
+ * owner document's pending list
+ */
+void _dom_node_try_destroy(dom_node_internal *node);
+#define dom_node_try_destroy(n) _dom_node_try_destroy((dom_node_internal *) (n))
+
+/* To add some node to the pending list */
+void _dom_node_mark_pending(dom_node_internal *node);
+#define dom_node_mark_pending(n) _dom_node_mark_pending((dom_node_internal *) (n))
+/* To remove the node from the pending list, this may happen when
+ * a node is removed and then appended to another parent */
+void _dom_node_remove_pending(dom_node_internal *node);
+#define dom_node_remove_pending(n) _dom_node_remove_pending((dom_node_internal *) (n))
+
 #endif
Index: src/core/impllist.c
===================================================================
--- src/core/impllist.c	(revision 9058)
+++ src/core/impllist.c	(working copy)
@@ -9,6 +9,8 @@
 #include <dom/core/implementation.h>
 #include <dom/core/impllist.h>
 
+extern void dom_implementation_list_destroy(struct dom_implementation_list *list);
+
 /**
  * Claim a reference on a DOM implementation list
  *
@@ -29,22 +31,8 @@
  */
 void dom_implementation_list_unref(struct dom_implementation_list *list)
 {
-	struct dom_implementation_list_item *i, *j;
-
 	if (--list->refcnt == 0) {
-		/* Destroy all list entries */
-		for (i = list->head; i; i = j) {
-			j = i->next;
-
-			/* Unreference the implementation */
-			dom_implementation_unref(i->impl);
-
-			/* And free the entry */
-			list->alloc(i, 0, list->pw);
-		}
-
-		/* Free the list object */
-		list->alloc(list, 0, list->pw);
+		dom_implementation_list_destroy(list);
 	}
 }
 
Index: src/core/namednodemap.h
===================================================================
--- src/core/namednodemap.h	(revision 9058)
+++ src/core/namednodemap.h	(working copy)
@@ -18,14 +18,54 @@
 struct dom_namednodemap;
 struct dom_string;
 
+struct nnm_operation {
+	dom_exception (*namednodemap_get_length)(void *priv,
+			unsigned long *length);
+
+	dom_exception (*namednodemap_get_named_item)(void *priv,
+			struct dom_string *name, struct dom_node **node);
+
+	dom_exception (*namednodemap_set_named_item)(void *priv,
+			struct dom_node *arg, struct dom_node **node);
+
+	dom_exception (*namednodemap_remove_named_item)(
+			void *priv, struct dom_string *name,
+			struct dom_node **node);
+
+	dom_exception (*namednodemap_item)(void *priv,
+			unsigned long index, struct dom_node **node);
+
+	dom_exception (*namednodemap_get_named_item_ns)(
+			void *priv, struct dom_string *namespace,
+			struct dom_string *localname, struct dom_node **node);
+
+	dom_exception (*namednodemap_set_named_item_ns)(
+			void *priv, struct dom_node *arg,
+			struct dom_node **node);
+
+	dom_exception (*namednodemap_remove_named_item_ns)(
+			void *priv, struct dom_string *namespace,
+			struct dom_string *localname, struct dom_node **node);
+
+	void (*namednodemap_destroy)(void *priv);
+
+	bool (*namednodemap_equal)(void *p1, void *p2);
+};
+
 /* Create a namednodemap */
-dom_exception dom_namednodemap_create(struct dom_document *doc,
-		struct dom_node_internal *head, dom_node_type type,
+dom_exception _dom_namednodemap_create(struct dom_document *doc,
+		void *priv, struct nnm_operation *opt,
 		struct dom_namednodemap **map);
 
+/* Update the private data */
+void _dom_namednodemap_update(struct dom_namednodemap *map, void *priv);
 
-/* Match a namednodemap instance against a set of creation parameters */
-bool dom_namednodemap_match(struct dom_namednodemap *map,
-		struct dom_node_internal *head, dom_node_type type);
+/* Test whether two maps are equal */
+bool _dom_namednodemap_equal(struct dom_namednodemap *m1, 
+		struct dom_namednodemap *m2);
 
+#define dom_namednodemap_equal(m1, m2) _dom_namednodemap_equal( \
+		(struct dom_namednodemap *) (m1), \
+		(struct dom_namednodemap *) (m2))
+
 #endif
Index: src/bootstrap/init_fini.c
===================================================================
--- src/bootstrap/init_fini.c	(revision 9058)
+++ src/bootstrap/init_fini.c	(working copy)
@@ -8,9 +8,10 @@
 #include <stdbool.h>
 
 #include <dom/bootstrap/init_fini.h>
+#include <dom/bootstrap/implregistry.h>
 
-#include "core/document.h"
 #include "utils/namespace.h"
+#include "bootstrap/implementation.h"
 
 static bool __initialised;
 
@@ -32,16 +33,22 @@
 		return DOM_NO_ERR;
 	}
 
-	err = _dom_document_initialise(alloc, pw);
+	err = _dom_namespace_initialise(alloc, pw);
 	if (err != DOM_NO_ERR) {
 		return err;
 	}
 
-	err = _dom_namespace_initialise(alloc, pw);
+	err = dom_implregistry_dom_implementation_initialise(
+			alloc, pw);
 	if (err != DOM_NO_ERR) {
 		return err;
 	}
 
+	err = _dom_implementation_initialise(alloc, pw);
+	if (err != DOM_NO_ERR) {
+		return err;
+	}
+	
 	__initialised = true;
 
 	return DOM_NO_ERR;
@@ -63,16 +70,13 @@
 		return DOM_NO_ERR;
 	}
 
+	_dom_implementation_finalise();
+
 	err = _dom_namespace_finalise();
 	if (err != DOM_NO_ERR) {
 		return err;
 	}
 
-	err = _dom_document_finalise();
-	if (err != DOM_NO_ERR) {
-		return err;
-	}
-
 	__initialised = false;
 
 	return DOM_NO_ERR;
Index: src/bootstrap/implregistry.c
===================================================================
--- src/bootstrap/implregistry.c	(revision 9058)
+++ src/bootstrap/implregistry.c	(working copy)
@@ -11,7 +11,10 @@
 #include <dom/bootstrap/implregistry.h>
 
 #include <dom/core/impllist.h>
+#include <dom/core/implementation.h>
 
+void dom_implementation_list_destroy(struct dom_implementation_list *list);
+
 /**
  * Item in list of registered DOM implementation sources
  */
@@ -23,14 +26,23 @@
 };
 
 static struct dom_impl_src_item *sources; /**< List of registered sources */
+static dom_alloc alloc;
+static void *pw;
 
+dom_exception dom_implregistry_dom_implementation_initialise(
+		dom_alloc allocator, void *ptr)
+{
+	alloc = allocator;
+	pw = ptr;
+
+	return DOM_NO_ERR;
+}
+
 /**
  * Retrieve a DOM implementation from the registry
  *
  * \param features  String containing required features
  * \param impl      Pointer to location to receive implementation
- * \param alloc     Function to (de)allocate memory
- * \param pw        Pointer to client-specific private data
  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
  *
  * Any memory allocated by this call should be allocated using
@@ -43,16 +55,14 @@
  */
 dom_exception dom_implregistry_get_dom_implementation(
 		struct dom_string *features,
-		struct dom_implementation **impl,
-		dom_alloc alloc, void *pw)
+		struct dom_implementation **impl)
 {
 	struct dom_impl_src_item *item;
 	struct dom_implementation *found = NULL;
 	dom_exception err;
 
 	for (item = sources; item; item = item->next) {
-		err = item->source->get_dom_implementation(features, &found,
-				alloc, pw);
+		err = item->source->get_dom_implementation(features, &found);
 		if (err != DOM_NO_ERR)
 			return err;
 
@@ -71,8 +81,6 @@
  *
  * \param features  String containing required features
  * \param list      Pointer to location to receive list
- * \param alloc     Function to (de)allocate memory
- * \param pw        Pointer to client-specific private data
  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
  *
  * Any memory allocated by this call should be allocated using
@@ -88,8 +96,7 @@
  */
 dom_exception dom_implregistry_get_dom_implementation_list(
 		struct dom_string *features,
-		struct dom_implementation_list **list,
-		dom_alloc alloc, void *pw)
+		struct dom_implementation_list **list)
 {
 	struct dom_implementation_list *l;
 	struct dom_impl_src_item *item;
@@ -100,16 +107,15 @@
 		return DOM_NO_MEM_ERR;
 
 	l->head = NULL;
-	l->alloc = alloc;
-	l->pw = pw;
 	l->refcnt = 1;
+	l->destroy = dom_implementation_list_destroy;
 
 	for (item = sources; item; item = item->next) {
 		struct dom_implementation_list *plist = NULL;
 		struct dom_implementation_list_item *plast = NULL;
 
 		err = item->source->get_dom_implementation_list(features,
-				&plist, alloc, pw);
+				&plist);
 		if (err != DOM_NO_ERR) {
 			dom_implementation_list_unref(l);
 			return err;
@@ -156,12 +162,9 @@
  * Register a DOM implementation source with the DOM library
  *
  * \param source  The implementation source to register
- * \param alloc   Memory (de)allocation function
- * \param pw      Pointer to client-specific private data
  * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
  */
-dom_exception dom_register_source(struct dom_implementation_source *source,
-		dom_alloc alloc, void *pw)
+dom_exception dom_register_source(struct dom_implementation_source *source)
 {
 	struct dom_impl_src_item *item;
 
@@ -182,3 +185,26 @@
 	return DOM_NO_ERR;
 }
 
+/**
+ * Destory a dom_implementation_list
+ *
+ * \param list	The list to destory
+ */
+void dom_implementation_list_destroy(struct dom_implementation_list *list)
+{
+	struct dom_implementation_list_item *i, *j;
+
+	/* Destroy all list entries */
+	for (i = list->head; i; i = j) {
+		j = i->next;
+
+		/* Unreference the implementation */
+		dom_implementation_unref(i->impl);
+
+		/* And free the entry */
+		alloc(i, 0, pw);
+	}
+
+	/* Free the list object */
+	alloc(list, 0, pw);
+}
Index: src/bootstrap/Makefile
===================================================================
--- src/bootstrap/Makefile	(revision 9058)
+++ src/bootstrap/Makefile	(working copy)
@@ -1,3 +1,3 @@
-DIR_SOURCES := implregistry.c init_fini.c
+DIR_SOURCES := implregistry.c init_fini.c implementation.c
 
 include build/makefiles/Makefile.subdir
Index: bindings/xml/xmlparser.h
===================================================================
--- bindings/xml/xmlparser.h	(revision 9058)
+++ bindings/xml/xmlparser.h	(working copy)
@@ -16,12 +16,14 @@
 #include "xmlerror.h"
 
 struct dom_document;
+struct lwc_context_s;
 
 typedef struct dom_xml_parser dom_xml_parser;
 
 /* Create an XML parser instance */
 dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc,
-		dom_alloc alloc, void *pw, dom_msg msg, void *mctx);
+		dom_alloc alloc, void *pw, dom_msg msg, void *mctx, 
+		struct lwc_context_s *ctx);
 
 /* Destroy an XML parser instance */
 void dom_xml_parser_destroy(dom_xml_parser *parser);
Index: bindings/xml/Makefile
===================================================================
--- bindings/xml/Makefile	(revision 9058)
+++ bindings/xml/Makefile	(working copy)
@@ -1,5 +1,5 @@
 ifeq ($(WITH_LIBXML_BINDING),yes)
-  DIR_SOURCES := xmlbinding.c xmlparser.c
+  DIR_SOURCES := xmlparser.c
 
   DIR_INSTALL_ITEMS := /include/dom/bindings/libxml:xmlbinding.h;xmlerror.h;xmlparser.h
 
Index: bindings/xml/xmlparser.c
===================================================================
--- bindings/xml/xmlparser.c	(revision 9058)
+++ bindings/xml/xmlparser.c	(working copy)
@@ -7,6 +7,7 @@
 
 #include <stdbool.h>
 #include <string.h>
+#include <assert.h>
 
 #include <libxml/parser.h>
 #include <libxml/SAX2.h>
@@ -15,10 +16,14 @@
 #include <dom/bootstrap/implpriv.h>
 #include <dom/dom.h>
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include "xmlerror.h"
 #include "xmlparser.h"
 #include "utils.h"
 
+#include "core/document.h"
+
 static void xml_parser_start_document(void *ctx);
 static void xml_parser_end_document(void *ctx);
 static void xml_parser_start_element_ns(void *ctx, const xmlChar *localname,
@@ -42,6 +47,8 @@
 		struct dom_node *parent, xmlNodePtr child);
 static void xml_parser_add_entity_reference(dom_xml_parser *parser,
 		struct dom_node *parent, xmlNodePtr child);
+static void xml_parser_add_entity(dom_xml_parser *parser, 
+        struct dom_node *parent, xmlNodePtr child);
 static void xml_parser_add_comment(dom_xml_parser *parser,
 		struct dom_node *parent, xmlNodePtr child);
 static void xml_parser_add_document_type(dom_xml_parser *parser,
@@ -97,6 +104,8 @@
 
 	dom_msg msg;			/**< Informational message function */
 	void *mctx;			/**< Pointer to client data */
+
+	struct lwc_context_s *ctx;	/**< The lwc_context of the parser */
 };
 
 /**
@@ -153,11 +162,13 @@
  * parser encoding is not yet implemented
  */
 dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc,
-		dom_alloc alloc, void *pw, dom_msg msg, void *mctx)
+		dom_alloc alloc, void *pw, dom_msg msg, void *mctx,
+		lwc_context *ctx)
 {
 	dom_xml_parser *parser;
 	struct dom_string *features;
 	dom_exception err;
+	int ret;
 
 	UNUSED(enc);
 	UNUSED(int_enc);
@@ -176,6 +187,11 @@
 		return NULL;
 	}
 
+	/* Use options of parsing context, don't substiute entities */
+	ret = xmlCtxtUseOptions(parser->xml_ctx, XML_PARSE_DTDATTR | 
+			XML_PARSE_DTDLOAD);
+	assert(ret == 0);
+
 	parser->doc = NULL;
 
 	parser->complete = false;
@@ -205,7 +221,7 @@
 
 	/* Now, try to get an appropriate implementation from the registry */
 	err = dom_implregistry_get_dom_implementation(features,
-			&parser->impl, (dom_alloc) alloc, pw);
+			&parser->impl);
 	if (err != DOM_NO_ERR) {
 		dom_string_unref(features);
 		dom_string_unref(parser->udkey);
@@ -224,6 +240,8 @@
 	parser->msg = msg;
 	parser->mctx = mctx;
 
+	parser->ctx = ctx;
+
 	return parser;
 }
 
@@ -240,9 +258,7 @@
 
 	xmlFreeParserCtxt(parser->xml_ctx);
 
-	/** \todo Do we want to clean up the document here, too? */
-	/* Obviously, document cleanup wouldn't happen if the client has
-	 * claimed the document from us via xml_parser_get_document() */
+	xmlFreeDoc(parser->xml_ctx->myDoc);
 
 	parser->alloc(parser, 0, parser->pw);
 }
@@ -281,6 +297,8 @@
 dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser)
 {
 	xmlParserErrors err;
+	lwc_string *name = NULL;
+	lwc_error lerr;
 
 	err = xmlParseChunk(parser->xml_ctx, "", 0, 1);
 	if (err != XML_ERR_OK) {
@@ -291,6 +309,17 @@
 
 	parser->complete = true;
 
+	/**
+	 * TODO: In future, this string "id" should be extracted from the 
+	 * document schema file instead of just setting it as "id".
+	 */
+	lerr = lwc_context_intern(parser->ctx, "id", SLEN("id"), &name);
+	if (lerr != lwc_error_ok)
+		return  _dom_exception_from_lwc_error(lerr);
+	
+	_dom_document_set_id_name(parser->doc, name);
+	lwc_context_string_unref(parser->ctx, name);
+
 	return DOM_XML_OK;
 }
 
@@ -326,9 +355,8 @@
 			/* namespace */ NULL,
 			/* qname */ NULL,
 			/* doctype */ NULL,
-			&doc,
-			(dom_alloc) parser->alloc,
-			parser->pw);
+			parser->alloc, parser->pw, parser->ctx,
+			&doc);
 	if (err != DOM_NO_ERR) {
 		parser->msg(DOM_MSG_CRITICAL, parser->mctx, 
 				"Failed creating document");
@@ -620,6 +648,9 @@
 	case XML_DTD_NODE:
 		xml_parser_add_document_type(parser, parent, child);
 		break;
+    case XML_ENTITY_DECL:
+        xml_parser_add_entity(parser, parent, child);
+        break;
 	default:
 		parser->msg(DOM_MSG_NOTICE, parser->mctx,
 				"Unsupported node type: %s",
@@ -647,7 +678,7 @@
 		struct dom_string *tag_name;
 
 		/* Create tag name DOM string */
-		err = dom_document_create_string(parser->doc,
+		err = _dom_document_create_string(parser->doc,
 				child->name, strlen((const char *) child->name),
 				&tag_name);
 		if (err != DOM_NO_ERR) {
@@ -680,7 +711,7 @@
 		uint8_t qnamebuf[qnamelen + 1 /* '\0' */];
 
 		/* Create namespace DOM string */
-		err = dom_document_create_string(parser->doc,
+		err = _dom_document_create_string(parser->doc,
 				child->ns->href,
 				strlen((const char *) child->ns->href),
 				&namespace);
@@ -699,7 +730,7 @@
 			(const char *) child->name);
 
 		/* Create qname DOM string */
-		err = dom_document_create_string(parser->doc,
+		err = _dom_document_create_string(parser->doc,
 				qnamebuf,
 				qnamelen,
 				&qname);
@@ -738,7 +769,7 @@
 			struct dom_string *name;
 
 			/* Create attribute name DOM string */
-			err = dom_document_create_string(parser->doc,
+			err = _dom_document_create_string(parser->doc,
 					a->name,
 					strlen((const char *) a->name),
 					&name);
@@ -772,7 +803,7 @@
 			uint8_t qnamebuf[qnamelen + 1 /* '\0' */];
 
 			/* Create namespace DOM string */
-			err = dom_document_create_string(parser->doc,
+			err = _dom_document_create_string(parser->doc,
 					a->ns->href,
 					strlen((const char *) a->ns->href),
 					&namespace);
@@ -791,7 +822,7 @@
 				(const char *) a->name);
 
 			/* Create qname DOM string */
-			err = dom_document_create_string(parser->doc,
+			err = _dom_document_create_string(parser->doc,
 					qnamebuf,
 					qnamelen,
 					&qname);
@@ -833,18 +864,29 @@
 			goto cleanup;
 		}
 
-		/* And add attribute to the element */
-		err = dom_element_set_attribute_node(el, attr, &prev_attr);
-		if (err != DOM_NO_ERR) {
-			dom_node_unref((struct dom_node *) attr);
-			parser->msg(DOM_MSG_ERROR, parser->mctx,
-					"Failed attaching attribute '%s'",
-					a->name);
-			goto cleanup;
+		if (a->ns == NULL) {
+			/* And add attribute to the element */
+			err = dom_element_set_attribute_node(el, attr, &prev_attr);
+			if (err != DOM_NO_ERR) {
+				dom_node_unref((struct dom_node *) attr);
+				parser->msg(DOM_MSG_ERROR, parser->mctx,
+						"Failed attaching attribute '%s'",
+						a->name);
+				goto cleanup;
+			}
+		} else {
+			err = dom_element_set_attribute_node_ns(el, attr, &prev_attr);
+			if (err != DOM_NO_ERR) {
+				dom_node_unref((struct dom_node *) attr);
+				parser->msg(DOM_MSG_ERROR, parser->mctx,
+						"Failed attaching attribute '%s'",
+						a->name);
+				goto cleanup;
+			}
 		}
 
 		/* We're not interested in the previous attribute (if any) */
-		if (prev_attr != NULL)
+		if (prev_attr != NULL && prev_attr != attr)
 			dom_node_unref((struct dom_node *) prev_attr);
 
 		/* We're no longer interested in the attribute node */
@@ -900,7 +942,7 @@
 	dom_exception err;
 
 	/* Create DOM string data for text node */
-	err = dom_document_create_string(parser->doc, child->content,
+	err = _dom_document_create_string(parser->doc, child->content,
 			strlen((const char *) child->content), &data);
 	if (err != DOM_NO_ERR) {
 		parser->msg(DOM_MSG_CRITICAL, parser->mctx,
@@ -961,7 +1003,7 @@
 	dom_exception err;
 
 	/* Create DOM string data for cdata section */
-	err = dom_document_create_string(parser->doc, child->content,
+	err = _dom_document_create_string(parser->doc, child->content,
 			strlen((const char *) child->content), &data);
 	if (err != DOM_NO_ERR) {
 		parser->msg(DOM_MSG_CRITICAL, parser->mctx,
@@ -1023,7 +1065,7 @@
 	dom_exception err;
 
 	/* Create name of entity reference */
-	err = dom_document_create_string(parser->doc, child->name,
+	err = _dom_document_create_string(parser->doc, child->name,
 			strlen((const char *) child->name), &name);
 	if (err != DOM_NO_ERR) {
 		parser->msg(DOM_MSG_CRITICAL, parser->mctx,
@@ -1075,6 +1117,14 @@
 	dom_node_unref((struct dom_node *) entity);
 }
 
+static void xml_parser_add_entity(dom_xml_parser *parser, 
+        struct dom_node *parent, xmlNodePtr child)
+{
+    UNUSED(parser);
+    UNUSED(parent);
+    UNUSED(child);
+}
+
 /**
  * Add a comment to the DOM
  *
@@ -1090,7 +1140,7 @@
 	dom_exception err;
 
 	/* Create DOM string data for comment */
-	err = dom_document_create_string(parser->doc, child->content,
+	err = _dom_document_create_string(parser->doc, child->content,
 			strlen((const char *) child->content), &data);
 	if (err != DOM_NO_ERR) {
 		parser->msg(DOM_MSG_CRITICAL, parser->mctx,
@@ -1152,7 +1202,7 @@
 	dom_exception err;
 
 	/* Create qname for doctype */
-	err = dom_document_create_string(parser->doc, dtd->name,
+	err = _dom_document_create_string(parser->doc, dtd->name,
 			strlen((const char *) dtd->name), &qname);
 	if (err != DOM_NO_ERR) {
 		parser->msg(DOM_MSG_CRITICAL, parser->mctx,
@@ -1161,7 +1211,7 @@
 	}
 
 	/* Create public ID for doctype */
-	err = dom_document_create_string(parser->doc,
+	err = _dom_document_create_string(parser->doc,
 			dtd->ExternalID,
 			(dtd->ExternalID == NULL) ? 0
 				: strlen((const char *) dtd->ExternalID),
@@ -1174,7 +1224,7 @@
 	}
 
 	/* Create system ID for doctype */
-	err = dom_document_create_string(parser->doc,
+	err = _dom_document_create_string(parser->doc,
 			dtd->SystemID,
 			(dtd->SystemID == NULL) ? 0
 				: strlen((const char *) dtd->SystemID),
@@ -1189,8 +1239,8 @@
 
 	/* Create doctype */
 	err = dom_implementation_create_document_type(parser->impl,
-			qname, public_id, system_id, &doctype,
-			(dom_alloc) parser->alloc, parser->pw);
+			qname, public_id, system_id, 
+			parser->alloc, parser->pw, parser->ctx, &doctype);
 	if (err != DOM_NO_ERR) {
 		dom_string_unref(system_id);
 		dom_string_unref(public_id);
@@ -1231,9 +1281,8 @@
 	dom_node_unref((struct dom_node *) doctype);
 }
 
-/*                                                                         */
 /* ------------------------------------------------------------------------*/
-/*                                                                         */
+
 void xml_parser_internal_subset(void *ctx, const xmlChar *name,
 		const xmlChar *ExternalID, const xmlChar *SystemID)
 {
Index: bindings/hubbub/parser.h
===================================================================
--- bindings/hubbub/parser.h	(revision 9058)
+++ bindings/hubbub/parser.h	(working copy)
@@ -16,6 +16,7 @@
 #include "errors.h"
 
 struct dom_document;
+struct lwc_context_s;
 
 typedef struct dom_hubbub_parser dom_hubbub_parser;
 
@@ -50,7 +51,8 @@
 /* Create a Hubbub parser instance */
 dom_hubbub_parser *dom_hubbub_parser_create(const char *aliases,
 		const char *enc, bool fix_enc, 
-		dom_alloc alloc, void *pw, dom_msg msg, void *mctx);
+		dom_alloc alloc, void *pw, dom_msg msg, void *mctx, 
+        struct lwc_context_s *ctx);
 
 /* Destroy a Hubbub parser instance */
 void dom_hubbub_parser_destroy(dom_hubbub_parser *parser);
Index: bindings/hubbub/parser.c
===================================================================
--- bindings/hubbub/parser.c	(revision 9058)
+++ bindings/hubbub/parser.c	(working copy)
@@ -7,6 +7,7 @@
  */
 
 #include <stdio.h>
+#include <string.h>
 
 #include <hubbub/errors.h>
 #include <hubbub/hubbub.h>
@@ -17,6 +18,10 @@
 #include "parser.h"
 #include "utils.h"
 
+#include "core/document.h"
+
+#include <libwapcaplet/libwapcaplet.h>
+
 /**
  * libdom Hubbub parser context
  */
@@ -40,6 +45,8 @@
 
 	dom_msg msg;			/**< Informational messaging function */
 	void *mctx;			/**< Pointer to client data */
+
+    struct lwc_context_s *ctx;  /**< The string intern context */
 };
 
 
@@ -47,8 +54,7 @@
 		void **result);
 static hubbub_error create_doctype(void *parser, const hubbub_doctype *doctype,
 		void **result);
-static hubbub_error create_element(void *parser, const hubbub_tag *tag, 
-		void **result);
+static hubbub_error create_element(void *parser, const hubbub_tag *tag, void **result);
 static hubbub_error create_text(void *parser, const hubbub_string *data, 
 		void **result);
 static hubbub_error ref_node(void *parser, void *node);
@@ -59,10 +65,8 @@
 		void *ref_child, void **result);
 static hubbub_error remove_child(void *parser, void *parent, void *child, 
 		void **result);
-static hubbub_error clone_node(void *parser, void *node, bool deep, 
-		void **result);
-static hubbub_error reparent_children(void *parser, void *node, 
-		void *new_parent);
+static hubbub_error clone_node(void *parser, void *node, bool deep, void **result);
+static hubbub_error reparent_children(void *parser, void *node, void *new_parent);
 static hubbub_error get_parent(void *parser, void *node, bool element_only,
 		void **result);
 static hubbub_error has_children(void *parser, void *node, bool *result);
@@ -109,7 +113,7 @@
  */
 dom_hubbub_parser *dom_hubbub_parser_create(const char *aliases, 
 		const char *enc, bool fix_enc,
-		dom_alloc alloc, void *pw, dom_msg msg, void *mctx)
+		dom_alloc alloc, void *pw, dom_msg msg, void *mctx, lwc_context *ctx)
 {
 	dom_hubbub_parser *parser;
 	hubbub_parser_optparams params;
@@ -118,7 +122,7 @@
 	struct dom_string *features;
 
 	if (__initialised == false) {
-		error = hubbub_initialise(aliases, alloc, pw);
+		error = hubbub_initialise(aliases, (hubbub_allocator_fn) alloc, pw);
 		if (error != HUBBUB_OK) {
 			msg(DOM_MSG_ERROR, mctx,
 					"Failed initialising hubbub");
@@ -147,6 +151,7 @@
 	parser->pw = pw;
 	parser->msg = msg;
 	parser->mctx = mctx;
+    parser->ctx = ctx;
 
 	error = hubbub_parser_create(enc, fix_enc, alloc, pw, &parser->parser);
 	if (error != HUBBUB_OK)	 {
@@ -168,7 +173,7 @@
 
  	/* Now, try to get an appropriate implementation from the registry */
 	err = dom_implregistry_get_dom_implementation(features,
-			&parser->impl, alloc, pw);
+			&parser->impl);
 	if (err != DOM_NO_ERR) {
 		dom_string_unref(features);
 		hubbub_parser_destroy(parser->parser);
@@ -181,7 +186,7 @@
 	dom_string_unref(features);
 
 	err = dom_implementation_create_document(parser->impl, NULL, NULL, NULL,
-			&parser->doc, alloc, pw);
+			alloc, pw, ctx, &parser->doc);
 	if (err != DOM_NO_ERR) {
 		hubbub_parser_destroy(parser->parser);
 		alloc(parser, 0, pw);
@@ -234,6 +239,8 @@
 dom_hubbub_error dom_hubbub_parser_completed(dom_hubbub_parser *parser)
 {
 	hubbub_error err;
+	lwc_string *name = NULL;
+	lwc_error lerr;
 
 	err = hubbub_parser_completed(parser->parser);
 	if (err != DOM_HUBBUB_OK) {
@@ -244,6 +251,13 @@
 
 	parser->complete = true;
 
+	lerr = lwc_context_intern(parser->ctx, "id", strlen("id"), &name);
+	if (lerr != lwc_error_ok)
+		return HUBBUB_UNKNOWN;
+	
+	_dom_document_set_id_name(parser->doc, name);
+	lwc_context_string_unref(parser->ctx, name);
+
 	return DOM_HUBBUB_OK;
 }
 
@@ -269,7 +283,7 @@
 }
 
 /* The callbacks definitions */
-hubbub_error create_comment(void *parser, const hubbub_string *data, 
+static hubbub_error create_comment(void *parser, const hubbub_string *data, 
 		void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
@@ -284,7 +298,7 @@
 	if (err != DOM_NO_ERR) {
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't create comment node text");
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 
 	err = dom_document_create_comment(dom_parser->doc, str, &comment);
@@ -293,7 +307,7 @@
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't create comment node with text '%.*s'",
 				data->len, data->ptr);
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 
 	*result = comment;
@@ -303,7 +317,7 @@
 	return HUBBUB_OK;
 }
 
-hubbub_error create_doctype(void *parser, const hubbub_doctype *doctype,
+static hubbub_error create_doctype(void *parser, const hubbub_doctype *doctype,
 		void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
@@ -350,8 +364,8 @@
 	}
 
 	err = dom_implementation_create_document_type(dom_parser->impl, qname,
-			public_id, system_id, &dtype, dom_parser->alloc, 
-			dom_parser->pw);
+			public_id, system_id, dom_parser->alloc, 
+			dom_parser->pw, dom_parser->ctx, &dtype);
 	if (err != DOM_NO_ERR) {
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't create the document type");
@@ -371,17 +385,18 @@
 
 fail:
 	if (*result == NULL)
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	else
 		return HUBBUB_OK;
 }
 
-hubbub_error create_element(void *parser, const hubbub_tag *tag, void **result)
+static hubbub_error create_element(void *parser, const hubbub_tag *tag, void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
 	struct dom_string *name;
 	struct dom_element *element = NULL;
+	hubbub_error herr;
 
 	*result = NULL;
 
@@ -412,17 +427,26 @@
 	}
 
 	*result = element;
+	if (element != NULL) {
+		if (tag->n_attributes != 0) {
+			herr = add_attributes(parser, element, tag->attributes,
+					tag->n_attributes);
+			if (herr != HUBBUB_OK)
+				return herr;
+		}
+	}
+
 clean1:
 	dom_string_unref(name);
 
 fail:
 	if (*result == NULL)
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	else
 		return HUBBUB_OK;
 }
 
-hubbub_error create_text(void *parser, const hubbub_string *data, void **result)
+static hubbub_error create_text(void *parser, const hubbub_string *data, void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
@@ -453,13 +477,13 @@
 
 fail:
 	if (*result == NULL)
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	else
 		return HUBBUB_OK;
 
 }
 
-hubbub_error ref_node(void *parser, void *node)
+static hubbub_error ref_node(void *parser, void *node)
 {
 	struct dom_node *dnode = (struct dom_node *) node;
 
@@ -470,7 +494,7 @@
 	return HUBBUB_OK;
 }
 
-hubbub_error unref_node(void *parser, void *node)
+static hubbub_error unref_node(void *parser, void *node)
 {
 	struct dom_node *dnode = (struct dom_node *) node;
 
@@ -481,7 +505,7 @@
 	return HUBBUB_OK;
 }
 
-hubbub_error append_child(void *parser, void *parent, void *child, void **result)
+static hubbub_error append_child(void *parser, void *parent, void *child, void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
@@ -493,13 +517,13 @@
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't append child '%p' for parent '%p'",
 				child, parent);
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 
 	return HUBBUB_OK;
 }
 
-hubbub_error insert_before(void *parser, void *parent, void *child, 
+static hubbub_error insert_before(void *parser, void *parent, void *child, 
 		void *ref_child, void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
@@ -513,13 +537,13 @@
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't insert node '%p' before node '%p'",
 				child, ref_child);
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 
 	return HUBBUB_OK;
 }
 
-hubbub_error remove_child(void *parser, void *parent, void *child, void **result)
+static hubbub_error remove_child(void *parser, void *parent, void *child, void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
@@ -530,13 +554,13 @@
 	if (err != DOM_NO_ERR) {
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't remove child '%p'", child);
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 
 	return HUBBUB_OK;
 }
 
-hubbub_error clone_node(void *parser, void *node, bool deep, void **result)
+static hubbub_error clone_node(void *parser, void *node, bool deep, void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
@@ -546,13 +570,13 @@
 	if (err != DOM_NO_ERR) {
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Can't clone node '%p'", node);
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 
 	return HUBBUB_OK;
 }
 
-hubbub_error reparent_children(void *parser, void *node, void *new_parent)
+static hubbub_error reparent_children(void *parser, void *node, void *new_parent)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
@@ -564,7 +588,7 @@
 		if (err != DOM_NO_ERR) {
 			dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 					"Error in dom_note_get_first_child");
-			return HUBBUB_NOMEM;
+			return HUBBUB_UNKNOWN;
 		}
 		if (child == NULL)
 			break;
@@ -592,10 +616,10 @@
 
 fail:
 	dom_node_unref(child);
-	return HUBBUB_NOMEM;
+	return HUBBUB_UNKNOWN;
 }
 
-hubbub_error get_parent(void *parser, void *node, bool element_only, 
+static hubbub_error get_parent(void *parser, void *node, bool element_only, 
 		void **result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
@@ -608,7 +632,7 @@
 	if (err != DOM_NO_ERR) {
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Error in dom_node_get_parent");
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
 	if (element_only == false) {
 		*result = parent;
@@ -623,18 +647,20 @@
 	}
 	if (type == DOM_ELEMENT_NODE) {
 		*result = parent;
+		return HUBBUB_OK;
 	} else {
 		*result = NULL;
 		dom_node_unref(parent);
+		return HUBBUB_OK;
 	}
 
 	return HUBBUB_OK;
 fail:
 	dom_node_unref(parent);
-	return HUBBUB_NOMEM;
+	return HUBBUB_UNKNOWN;
 }
 
-hubbub_error has_children(void *parser, void *node, bool *result)
+static hubbub_error has_children(void *parser, void *node, bool *result)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	dom_exception err;
@@ -645,13 +671,12 @@
 	if (err != DOM_NO_ERR) {
 		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
 				"Error in dom_node_has_child_nodes");
-		return HUBBUB_NOMEM;
+		return HUBBUB_UNKNOWN;
 	}
-
 	return HUBBUB_OK;
 }
 
-hubbub_error form_associate(void *parser, void *form, void *node)
+static hubbub_error form_associate(void *parser, void *form, void *node)
 {
 	UNUSED(parser);
 	UNUSED(form);
@@ -660,7 +685,7 @@
 	return HUBBUB_OK;
 }
 
-hubbub_error add_attributes(void *parser, void *node,
+static hubbub_error add_attributes(void *parser, void *node,
 		const hubbub_attribute *attributes, uint32_t n_attributes)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
@@ -719,10 +744,10 @@
 	return HUBBUB_OK;
 
 fail:
-	return HUBBUB_NOMEM;
+	return HUBBUB_UNKNOWN;
 }
 
-hubbub_error set_quirks_mode(void *parser, hubbub_quirks_mode mode)
+static hubbub_error set_quirks_mode(void *parser, hubbub_quirks_mode mode)
 {
 	UNUSED(parser);
 	UNUSED(mode);
@@ -730,7 +755,7 @@
 	return HUBBUB_OK;
 }
 
-hubbub_error change_encoding(void *parser, const char *charset)
+static hubbub_error change_encoding(void *parser, const char *charset)
 {
 	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
 	uint32_t source;
Index: Makefile
===================================================================
--- Makefile	(revision 9058)
+++ Makefile	(working copy)
@@ -47,7 +47,8 @@
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/implementation.h;$(Is)/impllist.h
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/namednodemap.h;$(Is)/node.h
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/nodelist.h;$(Is)/string.h
-INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/text.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/text.h;$(Is)/typeinfo.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/comment.h
 
 INSTALL_ITEMS := $(INSTALL_ITEMS) /lib/pkgconfig:lib$(COMPONENT).pc.in
 INSTALL_ITEMS := $(INSTALL_ITEMS) /lib:$(OUTPUT)


Conflicted files




Removed files


test/testutils.h
test/binding.c
test/xml
test/xml/tests
test/xml/tests/dom1.dtd
test/lib
test/lib/comparators.h
test/lib/list.h
test/lib/utils.c
test/lib/testassert.c
test/lib/utils.h
test/lib/exceptions.h
test/lib/testassert.h
test/lib/testobject.c
test/lib/comparators.c
test/lib/list.c
test/lib/testobject.h
test/INDEX
test/test-list.c
test/data/binding
test/data/binding/Aliases
test/data/binding/staff.xml
test/data/binding/sample.html
test/transform
test/transform/dom1-interfaces.xml
test/transform/test-to-c.xsl
test/transform/ctypes.xml
test/transform/string.xsl
bindings/xml/xmlbinding.h
bindings/xml/xmlbinding.c



More information about the netsurf-dev mailing list