diff --git a/sefht.geany b/sefht.geany
index 40265944b6ab0c835a98c6774fd97d45973bd514..f6203e0b09db541fb6a81a47e79449af330b834e 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -28,38 +28,43 @@ long_line_behaviour=1
 long_line_column=72
 
 [files]
-current_page=27
+current_page=31
 FILE_NAME_0=923;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8
 FILE_NAME_1=73;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2FMakefile.am;0;8
 FILE_NAME_2=1143;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmain.c;0;8
-FILE_NAME_3=1260;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
+FILE_NAME_3=747;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
 FILE_NAME_4=1593;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.c;0;8
 FILE_NAME_5=901;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.h;0;8
 FILE_NAME_6=2921;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8
 FILE_NAME_7=904;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.h;0;8
-FILE_NAME_8=1185;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.c;0;8
-FILE_NAME_9=916;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.h;0;8
-FILE_NAME_10=1975;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_data.c;0;8
-FILE_NAME_11=2173;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_class.c;0;8
-FILE_NAME_12=6499;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8
-FILE_NAME_13=2517;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.h;0;8
-FILE_NAME_14=25820;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.c;0;8
-FILE_NAME_15=904;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.h;0;8
-FILE_NAME_16=1779;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
-FILE_NAME_17=919;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8
-FILE_NAME_18=14237;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8
-FILE_NAME_19=859;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8
-FILE_NAME_20=4608;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
-FILE_NAME_21=901;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4
-FILE_NAME_22=907;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8
-FILE_NAME_23=1078;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8
-FILE_NAME_24=290;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8
-FILE_NAME_25=1085;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
-FILE_NAME_26=3283;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
-FILE_NAME_27=8518;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
-FILE_NAME_28=11068;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
-FILE_NAME_29=5744;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
-FILE_NAME_30=165;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
+FILE_NAME_8=1550;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.c;0;8
+FILE_NAME_9=1562;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.h;0;8
+FILE_NAME_10=2022;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_data.c;0;8
+FILE_NAME_11=2558;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_class.c;0;8
+FILE_NAME_12=20283;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8
+FILE_NAME_13=6032;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.h;0;8
+FILE_NAME_14=5204;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fattr.c;0;8
+FILE_NAME_15=3030;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fattr.h;0;8
+FILE_NAME_16=3046;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fattr_static.c;0;8
+FILE_NAME_17=1116;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fattr_data.h;0;8
+FILE_NAME_18=25820;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.c;0;8
+FILE_NAME_19=904;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.h;0;8
+FILE_NAME_20=1779;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
+FILE_NAME_21=919;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8
+FILE_NAME_22=14237;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8
+FILE_NAME_23=859;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8
+FILE_NAME_24=4735;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
+FILE_NAME_25=901;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4
+FILE_NAME_26=907;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8
+FILE_NAME_27=1078;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8
+FILE_NAME_28=1044;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8
+FILE_NAME_29=1085;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
+FILE_NAME_30=3283;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
+FILE_NAME_31=63675;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
+FILE_NAME_32=15195;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
+FILE_NAME_33=11068;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
+FILE_NAME_34=5744;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
+FILE_NAME_35=165;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
 
 [VTE]
 last_dir=/home/jonathan/Documents/projects/prgm/internet/web/SeFHT/tests
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 38a43da3fcc74c31cb77038637ad7ba63fcdee93..5f0ad8ba98f668165eb3101eb0814cd161541bc8 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-AM_CFLAGS = -Wall -Wextra -Wno-nonnull
+AM_CFLAGS = -Wall -Wextra -Wno-nonnull -flto
 
 lib_LTLIBRARIES = libsefht.la
 
@@ -9,6 +9,7 @@ libsefht_la_SOURCES += sefht/sefht.h
 libsefht_la_SOURCES += sefht/macro.h
 libsefht_la_SOURCES += sefht/log.h
 libsefht_la_SOURCES += sefht/status.h
+libsefht_la_SOURCES += sefht/attr.c sefht/attr.h
 libsefht_la_SOURCES += sefht/cms.c sefht/cms.h
 libsefht_la_SOURCES += sefht/data.c sefht/data.h
 libsefht_la_SOURCES += sefht/fragment.c sefht/fragment.h
@@ -17,6 +18,7 @@ libsefht_la_SOURCES += sefht/text.c sefht/text.h
 libsefht_la_SOURCES += sefht/validator.c sefht/validator.h
 
 EXTRA_DIST =
+EXTRA_DIST += sefht/attr_static.c sefht/attr_data.h
 EXTRA_DIST += sefht/fragment_class.c
 EXTRA_DIST += sefht/fragment_data.c
 EXTRA_DIST += sefht/validator_tag.c
@@ -26,6 +28,7 @@ nobase_include_HEADERS += sefht/sefht.h
 nobase_include_HEADERS += sefht/macro.h
 nobase_include_HEADERS += sefht/log.h
 nobase_include_HEADERS += sefht/status.h
+nobase_include_HEADERS += sefht/attr.h
 nobase_include_HEADERS += sefht/cms.h
 nobase_include_HEADERS += sefht/data.h
 nobase_include_HEADERS += sefht/fragment.h
diff --git a/src/lib/sefht/attr.c b/src/lib/sefht/attr.c
new file mode 100644
index 0000000000000000000000000000000000000000..db9cad23acf7c7f359aadb0f852f22230a865cbd
--- /dev/null
+++ b/src/lib/sefht/attr.c
@@ -0,0 +1,274 @@
+/*
+ * attr.c
+ *
+ * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include "macro.h"
+#include "log.h"
+#include "status.h"
+
+#include "attr.h"
+
+
+#include "attr_static.c"
+
+
+/*@null@*/
+/*@only@*/
+struct SH_Attr *
+SH_Attr_new (const char * name,
+             /*@null@*/ const char * value,
+             /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	struct SH_Attr * attr;
+
+	attr = malloc (sizeof (struct SH_Attr));
+	if (attr == NULL)
+	{
+		set_status (status, E_ALLOC, 4, "malloc failed");
+		return NULL;
+	}
+
+	if (!Attr_init (attr, name, value, status))
+	{
+		free (attr);
+		return NULL;
+	}
+
+	set_success (status);
+	return attr;
+}
+
+/*@null@*/
+/*@only@*/
+struct SH_Attr *
+SH_Attr_raw_new (/*@only@*/ char * name,
+                 /*@null@*/ /*@only@*/ char * value,
+                 /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	struct SH_Attr * attr;
+
+	attr = malloc (sizeof (struct SH_Attr));
+	if (attr == NULL)
+	{
+		set_status (status, E_ALLOC, 4, "malloc failed");
+		return NULL;
+	}
+
+	Attr_raw_init (attr, name, value);
+
+	set_success (status);
+	return attr;
+}
+
+/*@null@*/
+/*@only@*/
+struct SH_Attr *
+SH_Attr_copy (const struct SH_Attr * attr,
+             /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	struct SH_Attr * copy;
+
+	copy = malloc (sizeof (struct SH_Attr));
+	if (copy == NULL)
+	{
+		set_status (status, E_ALLOC, 4, "malloc failed");
+		return NULL;
+	}
+
+	if (!Attr_copy (copy, attr, status))
+	{
+		free (copy);
+		return NULL;
+	}
+
+	set_success (status);
+	return copy;
+}
+
+void
+SH_Attr_free (/*@only@*/ struct SH_Attr * attr)
+	/*@modifies attr->name@*/
+	/*@modifies attr->value@*/
+	/*@modifies attr@*/
+	/*@releases attr@*/
+{
+	Attr_free (attr);
+	free (attr);
+	return;
+}
+
+/*@null@*/
+/*@only@*/
+char *
+SH_Attr_get_name (const struct SH_Attr * attr,
+                  /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@*/
+{
+	char * name;
+
+	name = strdup (Attr_get_name (attr));
+	if (NULL == name)
+	{
+		set_status (status, E_ALLOC, 3, "strdup failed");
+		return NULL;
+	}
+
+	set_success (status);
+	return name;
+}
+
+bool
+SH_Attr_set_name (struct SH_Attr * attr,
+                  const char * name,
+                  /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@modifies attr->name@*/
+{
+	char * name_copy;
+
+	name_copy = strdup (name);
+	if (NULL == name_copy)
+	{
+		set_status (status, E_ALLOC, 3, "strdup failed");
+		return FALSE;
+	}
+
+	Attr_set_name (attr, name_copy);
+
+	set_success (status);
+	return TRUE;
+}
+
+/*@observer@*/
+const char *
+SH_Attr_raw_get_name (const struct SH_Attr * attr)
+	/*@*/
+{
+	return Attr_get_name (attr);
+}
+
+void
+SH_Attr_raw_set_name (struct SH_Attr * attr, /*@only@*/ char * name)
+	/*@modifies attr->name@*/
+{
+	Attr_set_name (attr, name);
+	return;
+}
+
+/*@null@*/
+/*@only@*/
+char *
+SH_Attr_get_value (const struct SH_Attr * attr,
+                   /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@*/
+{
+	char * value;
+
+	if (NULL == Attr_get_value (attr))
+	{
+		set_success (status);
+		return NULL;
+	}
+
+	value = strdup (Attr_get_value (attr));
+	if (NULL == value)
+	{
+		set_status (status, E_ALLOC, 3, "strdup failed");
+		return NULL;
+	}
+
+	set_success (status);
+	return value;
+}
+
+bool
+SH_Attr_set_value (struct SH_Attr * attr,
+                   /*@null@*/ const char * value,
+                   /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@modifies attr->value@*/
+{
+	char * value_copy;
+
+	if (NULL == value)
+	{
+		value_copy = NULL;
+	}
+	else
+	{
+		value_copy = strdup (value);
+		if (NULL == value_copy)
+		{
+			set_status (status, E_ALLOC, 3, "strdup failed");
+			return FALSE;
+		}
+	}
+
+	Attr_set_value (attr, value_copy);
+
+	set_success (status);
+	return TRUE;
+}
+
+/*@null@*/
+/*@observer@*/
+char *
+SH_Attr_raw_get_value (const struct SH_Attr * attr)
+	/*@*/
+{
+	return Attr_get_value (attr);
+}
+
+void
+SH_Attr_raw_set_value (struct SH_Attr * attr,
+                       /*@null@*/ /*@only@*/ char * value)
+	/*@modifies attr->value@*/
+{
+	Attr_set_value (attr, value);
+	return;
+}
+
+bool
+SH_Attr_is_equal (const struct SH_Attr * attr1,
+                  const struct SH_Attr * attr2)
+	/*@*/
+{
+	return Attr_is_equal (attr1, attr2);
+}
+
+bool
+SH_Attr_is_equal_name (const struct SH_Attr * attr1,
+                       const struct SH_Attr * attr2)
+	/*@*/
+{
+	return Attr_is_equal_name (attr1, attr2);
+}
diff --git a/src/lib/sefht/attr.h b/src/lib/sefht/attr.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5dabc64549c6a618ade89c19f709a6d65e88258
--- /dev/null
+++ b/src/lib/sefht/attr.h
@@ -0,0 +1,128 @@
+/*
+ * attr.h
+ *
+ * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+
+#ifndef SEFHT_ATTR_H
+#define SEFHT_ATTR_H
+
+#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION)
+#error "Only <sefht/sefht.h> can be included directly."
+#endif
+
+#include "status.h"
+
+#include "data.h"
+
+
+typedef /*@abstract@*/ struct SH_Attr SH_Attr;
+
+
+/*@null@*/
+/*@only@*/
+struct SH_Attr *
+SH_Attr_new (const char * name,
+             /*@null@*/ const char * value,
+             /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+/*@null@*/
+/*@only@*/
+struct SH_Attr *
+SH_Attr_raw_new (/*@only@*/ char * name,
+                 /*@null@*/ /*@only@*/ char * value,
+                 /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+/*@null@*/
+/*@only@*/
+struct SH_Attr *
+SH_Attr_copy (const struct SH_Attr * attr,
+             /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+void
+SH_Attr_free (/*@only@*/ SH_Attr * attr)
+	/*@modifies attr@*/
+	/*@releases attr@*/;
+
+/*@null@*/
+/*@only@*/
+char *
+SH_Attr_get_name (const SH_Attr * attr,
+                  /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@*/;
+
+bool
+SH_Attr_set_name (SH_Attr * attr,
+                  const char * name,
+                  /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@modifies attr@*/;
+
+/*@observer@*/
+const char *
+SH_Attr_raw_get_name (const SH_Attr * attr)
+	/*@*/;
+
+void
+SH_Attr_raw_set_name (SH_Attr * attr, /*@only@*/ char * name)
+	/*@modifies attr@*/;
+
+/*@null@*/
+/*@only@*/
+char *
+SH_Attr_get_value (const SH_Attr * attr,
+                   /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@*/;
+
+bool
+SH_Attr_set_value (SH_Attr * attr,
+                   const char * value,
+                   /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@modifies attr@*/;
+
+/*@null@*/
+/*@observer@*/
+char *
+SH_Attr_raw_get_value (const SH_Attr * attr)
+	/*@*/;
+
+void
+SH_Attr_raw_set_value (SH_Attr * attr,
+                       /*@null@*/ /*@only@*/ char * value)
+	/*@modifies attr@*/;
+
+bool
+SH_Attr_is_equal (const SH_Attr * attr1, const SH_Attr * attr2)
+	/*@*/;
+
+bool
+SH_Attr_is_equal_name (const SH_Attr * attr1, const SH_Attr * attr2)
+	/*@*/;
+
+#endif /* SEFHT_ATTR_H */
diff --git a/src/lib/sefht/attr_data.h b/src/lib/sefht/attr_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..7870295f90475b6ee680a23fe2c0c60d5ae2f797
--- /dev/null
+++ b/src/lib/sefht/attr_data.h
@@ -0,0 +1,38 @@
+/*
+ * attr_data.h
+ *
+ * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+
+#ifndef SEFHT_ATTR_DATA_H
+#define SEFHT_ATTR_DATA_H
+
+#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION)
+#error "Only <sefht/sefht.h> can be included directly."
+#endif
+
+struct SH_Attr
+{
+	/*@only@*/ char * name;
+	/*@null@*/ /*@only@*/ char * value;
+};
+
+#endif /* SEFHT_ATTR_DATA_H */
diff --git a/src/lib/sefht/attr_static.c b/src/lib/sefht/attr_static.c
new file mode 100644
index 0000000000000000000000000000000000000000..d160c8479ed8dccbe2bcd07d8a2bc796ed5fb41b
--- /dev/null
+++ b/src/lib/sefht/attr_static.c
@@ -0,0 +1,211 @@
+/*
+ * attr_static.c
+ *
+ * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+
+#ifndef SEFHT_ATTR_STATIC_C
+#define SEFHT_ATTR_STATIC_C
+
+#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION)
+#error "Only <sefht/sefht.h> can be included directly."
+#endif
+
+#include "attr_data.h"
+
+
+static inline
+bool
+Attr_init (struct SH_Attr * attr,
+           const char * name,
+           /*@null@*/ const char * value,
+           /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	attr->name = strdup (name);
+	if (NULL == attr->name)
+	{
+		set_status (status, E_ALLOC, 2, "strdup failed");
+		return FALSE;
+	}
+
+	if (NULL == value)
+	{
+		attr->value = NULL;
+	}
+	else
+	{
+		attr->value = strdup (value);
+		if (NULL == attr->value)
+		{
+			set_status (status, E_ALLOC, 2,
+			            "strdup failed");
+			free (attr->name);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static inline
+void
+Attr_raw_init (struct SH_Attr * attr,
+               /*@only@*/ char * name,
+               /*@null@*/ /*@only@*/ char * value)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	attr->name = name;
+	attr->value = value;
+	return;
+}
+
+static inline
+bool
+Attr_copy (struct SH_Attr * copy,
+           const struct SH_Attr * attr,
+           /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+
+	copy->name = strdup (attr->name);
+	if (NULL == copy->name)
+	{
+		set_status (status, E_ALLOC, 2, "strdup failed");
+		return FALSE;
+	}
+
+	if (NULL == attr->value)
+	{
+		copy->value = NULL;
+	}
+	else
+	{
+		copy->value = strdup (attr->value);
+		if (NULL == copy->value)
+		{
+			set_status (status, E_ALLOC, 2,
+			            "strdup failed");
+			free (copy->name);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static inline
+void
+Attr_free (struct SH_Attr * attr)
+	/*@modifies attr->name@*/
+	/*@modifies attr->value@*/
+	/*@releases attr->name@*/
+	/*@releases attr->value@*/
+{
+	free (attr->name);
+	if (NULL != attr->value) free (attr->value);
+	return;
+}
+
+static inline
+void
+Attr_move (struct SH_Attr * dest,
+           struct SH_Attr * src)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+
+	dest->name = src->name;
+	dest->value = src->value;
+	free (src);
+	return;
+}
+
+static inline
+/*@observer@*/
+char *
+Attr_get_name (const struct SH_Attr * attr)
+	/*@*/
+{
+	return attr->name;
+}
+
+static inline
+void
+Attr_set_name (struct SH_Attr * attr, char * name)
+	/*@modifies attr->name@*/
+{
+	free (attr->name);
+	attr->name = name;
+	return;
+}
+
+static inline
+/*@null@*/
+/*@observer@*/
+char *
+Attr_get_value (const struct SH_Attr * attr)
+{
+	return attr->value;
+}
+
+static inline
+void
+Attr_set_value (struct SH_Attr * attr, /*@null@*/ /*@only@*/ char * value)
+{
+	if (NULL != attr->value)
+	{
+		free (attr->value);
+	}
+
+	attr->value = value;
+	return;
+}
+
+static inline
+bool
+Attr_is_equal (const struct SH_Attr * attr1,
+               const struct SH_Attr * attr2)
+	/*@*/
+{
+	if (0 != strcmp (attr1->name, attr2->name)) return FALSE;
+	if (NULL == attr1->value) return (NULL == attr2->value);
+	if (NULL == attr2->value) return FALSE;
+	return (0 == strcmp (attr1->value, attr2->value));
+}
+
+static inline
+bool
+Attr_is_equal_name (const struct SH_Attr * attr1,
+                    const struct SH_Attr * attr2)
+	/*@*/
+{
+	return (0 == strcmp (attr1->name, attr2->name));
+}
+
+#endif /* SEFHT_ATTR_STATIC_C */
diff --git a/src/lib/sefht/fragment.c b/src/lib/sefht/fragment.c
index 6a306bd388983053c8d14ed6a0d5fd9f9de15a57..72d4707f6988aff1cd2058cdc3cc2993fa42f257 100644
--- a/src/lib/sefht/fragment.c
+++ b/src/lib/sefht/fragment.c
@@ -27,11 +27,12 @@
 #include "status.h"
 
 #include "text.h"
+#include "node_fragment.h"
 
 #include "fragment.h"
 
 
-#include "fragment_data.c"
+#include "fragment_class.c"
 
 /*@null@*/
 /*@only@*/
@@ -54,6 +55,13 @@ SH_Fragment_free (/*@only@*/ struct SH_Fragment * fragment)
 	return;
 }
 
+bool
+SH_Fragment_is_orphan (const struct SH_Fragment * fragment)
+	/*@*/
+{
+	return get_parent (fragment) == NULL;
+}
+
 /*@null@*/
 /*@only@*/
 SH_Text *
diff --git a/src/lib/sefht/fragment.h b/src/lib/sefht/fragment.h
index f2602e810ed359ed3ab32df60a59dab440952aa0..b55542c1b508536d0f7c30c5a401b52e8dbf1306 100644
--- a/src/lib/sefht/fragment.h
+++ b/src/lib/sefht/fragment.h
@@ -58,6 +58,10 @@ SH_Fragment_free (/*@only@*/ SH_Fragment * fragment)
 	/*@modifies fragment@*/
 	/*@releases fragment@*/;
 
+bool
+SH_Fragment_is_orphan (const SH_Fragment * fragment)
+	/*@*/;
+
 /*@null@*/
 /*@only@*/
 SH_Text *
diff --git a/src/lib/sefht/fragment_class.c b/src/lib/sefht/fragment_class.c
index 3a478d1f017f5d57b0554c92f921e7dc0b6eaeeb..8fd9a412c2790cf2c2e6f1c409eb40287e6732ec 100644
--- a/src/lib/sefht/fragment_class.c
+++ b/src/lib/sefht/fragment_class.c
@@ -41,18 +41,24 @@
 static inline
 void
 init_fragment (/*@out@*/ struct SH_Fragment * fragment,
-               /*@dependent@*/ SH_Data * data,
                const enum SH_FRAGMENT_TYPE type,
                /*@shared@*/
-               const struct fragment_methods * const methods)
-	/*@modifies fragment->data@*/
+               const struct fragment_methods * const methods,
+               /*@dependent@*/ SH_Data * data,
+               /*@null@*/ /*@dependent@*/
+               struct SH_NodeFragment * parent)
 	/*@modifies fragment->type@*/
 	/*@modifies fragment->methods@*/
+	/*@modifies fragment->data@*/
+	/*@modifies fragment->parent@*/
 {
-	fragment->data = data;
 	fragment->type = type;
 	fragment->methods = methods;
 
+	fragment->data = data;
+
+	fragment->parent = parent;
+
 	return;
 }
 
@@ -70,14 +76,18 @@ static inline
 void
 copy_fragment (/*@out@*/ struct SH_Fragment * copy,
                const struct SH_Fragment * fragment)
-	/*@modifies copy->data@*/
 	/*@modifies copy->type@*/
 	/*@modifies copy->methods@*/
+	/*@modifies copy->data@*/
+	/*@modifies copy->parent@*/
 {
-	copy->data = fragment->data;
 	copy->type = fragment->type;
 	copy->methods = fragment->methods;
 
+	copy->data = fragment->data;
+
+	copy->parent = NULL;
+
 	return;
 }
 
@@ -89,5 +99,24 @@ get_type (const struct SH_Fragment * fragment)
 	return fragment->type;
 }
 
+static inline
+/*@null@*/
+/*@dependent@*/
+struct SH_NodeFragment *
+get_parent (const struct SH_Fragment * fragment)
+{
+	return fragment->parent;
+}
+
+static inline
+void
+set_parent (struct SH_Fragment * fragment,
+            /*@null@*/ /*@dependent@*/ struct SH_NodeFragment * parent)
+	/*@modifies fragment->parent@*/
+{
+	fragment->parent = parent;
+	return;
+}
+
 #endif /* SEFHT_COMPILATION */
 #endif /* SEFHT_FRAGMENT_CLASS_C */
diff --git a/src/lib/sefht/fragment_data.c b/src/lib/sefht/fragment_data.c
index f55a71c764e29281f9b748ea258d97aab6b7aa31..617f62990e75c5386956fdf888c100734c2debfb 100644
--- a/src/lib/sefht/fragment_data.c
+++ b/src/lib/sefht/fragment_data.c
@@ -76,10 +76,12 @@ struct fragment_methods
 
 struct SH_Fragment
 {
-	/*@dependent@*/ SH_Data * data;
-
 	enum SH_FRAGMENT_TYPE type;
 	/*@shared@*/ const struct fragment_methods * methods;
+
+	/*@dependent@*/ SH_Data * data;
+
+	/*@null@*/ /*@dependent@*/ struct SH_NodeFragment * parent;
 };
 
 #endif /* SEFHT_COMPILATION */
diff --git a/src/lib/sefht/node_fragment.c b/src/lib/sefht/node_fragment.c
index fdf5c788f7fb8f6989b33bccada71a6bc347c5e0..be8777156ebedb14dd1d6caff8759a92bcd8fcdd 100644
--- a/src/lib/sefht/node_fragment.c
+++ b/src/lib/sefht/node_fragment.c
@@ -31,6 +31,7 @@
 #include "log.h"
 #include "status.h"
 
+#include "attr_static.c"
 #include "data.h"
 #include "text.h"
 #include "validator.h"
@@ -42,14 +43,23 @@
 
 #include "fragment_class.c"
 
+#define CHILD_CHUNK 5
+#define ATTR_CHUNK 5
+
+
 struct SH_NodeFragment
 {
 	struct SH_Fragment base;
 
-	char * tag;
+	/*@only@*/ char * tag;
+
+	size_t attr_s; /* allocated size */
+	size_t attr_n; /* real size */
+	/*@only@*/ struct SH_Attr * attrs;
 
-	size_t child_n;
-	struct SH_Fragment ** childs;
+	size_t child_s; /* allocated size */
+	size_t child_n; /* real size */
+	/*@only@*/ struct SH_Fragment ** childs;
 };
 
 #define OPEN_TAG_BEGIN "<"
@@ -77,6 +87,53 @@ static const struct fragment_methods methods = {
 };
 
 
+static inline
+size_t
+get_child_alloc_size (size_t size)
+	/*@*/
+{
+	/* underflow */
+	if (size == 0)
+	{
+		return 0;
+	}
+	/* overflow */
+	else if (((SIZE_MAX / CHILD_CHUNK) - 1)
+	       < ((size - 1) / CHILD_CHUNK))
+	{
+		return SIZE_MAX;
+	}
+	/* calculate the number of needed chunks */
+	else
+	{
+		return CHILD_CHUNK * (((size - 1) / CHILD_CHUNK) + 1);
+	}
+}
+
+static inline
+size_t
+get_attr_alloc_size (size_t size)
+	/*@*/
+{
+	/* underflow */
+	if (size == 0)
+	{
+		return 0;
+	}
+	/* overflow */
+	else if (((SIZE_MAX / ATTR_CHUNK) - 1)
+	       < ((size - 1) / ATTR_CHUNK))
+	{
+		return SIZE_MAX;
+	}
+	/* calculate the number of needed chunks */
+	else
+	{
+		return ATTR_CHUNK * (((size - 1) / ATTR_CHUNK) + 1);
+	}
+}
+
+
 /*@null@*/
 /*@only@*/
 struct SH_Fragment /*@alt struct SH_NodeFragment@*/ *
@@ -100,7 +157,7 @@ SH_NodeFragment_new (const char * tag,
 		return NULL;
 	}
 
-	init_fragment (&(fragment->base), data, NODE, &methods);
+	init_fragment (&(fragment->base), NODE, &methods, data, NULL);
 
 	fragment->tag = strdup (tag);
 	if (fragment->tag == NULL)
@@ -115,6 +172,51 @@ SH_NodeFragment_new (const char * tag,
 	}
 
 
+	fragment->attr_s = 0;
+	fragment->attr_n = 0;
+	fragment->attrs = malloc (0);
+
+	fragment->child_s = 0;
+	fragment->child_n = 0;
+	fragment->childs = malloc (0);
+
+	set_success (status);
+
+	return (struct SH_Fragment *) fragment;
+}
+
+/*@null@*/
+/*@only@*/
+struct SH_Fragment /*@alt struct SH_NodeFragment@*/ *
+SH_NodeFragment_raw_new (/*@only@*/ char * tag,
+                         /*@dependent@*/ SH_Data * data,
+                         /*@out@*/ /*@null@*/ struct SH_Status * status)
+	/*@globals NODE,
+	           fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	struct SH_NodeFragment * fragment;
+
+	fragment = malloc (sizeof (struct SH_NodeFragment));
+	if (fragment == NULL)
+	{
+		set_status (status, E_ALLOC, 3,
+		            "Memory allocation for "
+		            "SH_NodeFragment failed.\n");
+
+		return NULL;
+	}
+
+	init_fragment (&(fragment->base), NODE, &methods, data, NULL);
+
+	fragment->tag = tag;
+
+	fragment->attr_s = 0;
+	fragment->attr_n = 0;
+	fragment->attrs = malloc (0);
+
+	fragment->child_s = 0;
 	fragment->child_n = 0;
 	fragment->childs = malloc (0);
 
@@ -132,6 +234,12 @@ SH_NodeFragment_free (/*@only@*/ struct SH_NodeFragment * fragment)
 
 	free (fragment->tag);
 
+	for (index = 0; index < fragment->attr_n; index++)
+	{
+		Attr_free (&fragment->attrs[index]);
+	}
+	free (fragment->attrs);
+
 	for (index = 0; index < fragment->child_n; index++)
 	{
 		SH_Fragment_free (fragment->childs[index]);
@@ -155,6 +263,7 @@ SH_NodeFragment_copy (const struct SH_NodeFragment * fragment,
 	/*@modifies status@*/
 {
 	struct SH_NodeFragment * copy;
+	size_t index;
 
 	copy = malloc (sizeof (struct SH_NodeFragment));
 	if (copy == NULL)
@@ -168,6 +277,7 @@ SH_NodeFragment_copy (const struct SH_NodeFragment * fragment,
 
 	copy_fragment (&(copy->base), &(fragment->base));
 
+	/* copy tag */
 	copy->tag = strdup (fragment->tag);
 	if (copy->tag == NULL)
 	{
@@ -180,7 +290,44 @@ SH_NodeFragment_copy (const struct SH_NodeFragment * fragment,
 		return NULL;
 	}
 
+	/* copy attributes */
+	copy->attr_n = fragment->attr_n;
+	copy->attr_s = get_attr_alloc_size (fragment->attr_n);
+	copy->attrs = malloc (copy->attr_s * sizeof (*copy->attrs));
+
+	if (copy->attr_s != 0 && copy->attrs == NULL)
+	{
+		set_status (status, E_ALLOC, 5, "malloc failed\n");
+
+		free (copy->tag);
+/* dangerous call to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+		free (copy->attrs);
+#endif
+		free (copy);
+
+		return NULL;
+	}
+
+	for (index = 0; index < fragment->attr_n; index++)
+	{
+		if (!Attr_copy (&copy->attrs[index],
+		                &fragment->attrs[index],
+		                status))
+		{
+			while (index > 0)
+			{
+				index--;
+				Attr_free (&copy->attrs[index]);
+			}
+
+			free (copy);
+			return NULL;
+		}
+	}
 
+	/* don't copy childs */
+	copy->child_s = 0;
 	copy->child_n = 0;
 	copy->childs = malloc (0);
 
@@ -215,6 +362,7 @@ SH_NodeFragment_deepcopy (const struct SH_NodeFragment * fragment,
 
 	copy_fragment (&(copy->base), &(fragment->base));
 
+	/* copy tag */
 	copy->tag = strdup (fragment->tag);
 	if (copy->tag == NULL)
 	{
@@ -227,12 +375,48 @@ SH_NodeFragment_deepcopy (const struct SH_NodeFragment * fragment,
 		return NULL;
 	}
 
+	/* copy attributes */
+	copy->attr_n = fragment->attr_n;
+	copy->attr_s = get_attr_alloc_size (fragment->attr_n);
+	copy->attrs = malloc (copy->attr_s * sizeof (*copy->attrs));
+
+	if (copy->attr_s != 0 && copy->attrs == NULL)
+	{
+		set_status (status, E_ALLOC, 5, "malloc failed\n");
+
+		free (copy->tag);
+/* dangerous call to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+		free (copy->attrs);
+#endif
+		free (copy);
+
+		return NULL;
+	}
+
+	for (index = 0; index < fragment->attr_n; index++)
+	{
+		if (!Attr_copy (&copy->attrs[index],
+		                &fragment->attrs[index],
+		                status))
+		{
+			while (index > 0)
+			{
+				index--;
+				Attr_free (&copy->attrs[index]);
+			}
+
+			free (copy);
+			return NULL;
+		}
+	}
 
+	/* copy childs */
 	copy->child_n = fragment->child_n;
-	copy->childs = malloc (sizeof (struct SH_NodeFragment *)
-	                       * fragment->child_n);
+	copy->child_s = get_child_alloc_size (fragment->child_n);
+	copy->childs = malloc (copy->child_s * sizeof (*copy->childs));
 
-	if (copy->child_n != 0 && copy->childs == NULL)
+	if (copy->child_s != 0 && copy->childs == NULL)
 	{
 		set_status (status, E_ALLOC, 5,
 		            "Memory allocation for "
@@ -262,6 +446,7 @@ SH_NodeFragment_deepcopy (const struct SH_NodeFragment * fragment,
 		}
 
 		copy->childs[index] = child;
+		child->parent = copy;
 	}
 
 	set_success (status);
@@ -276,6 +461,15 @@ SH_Fragment_is_NodeFragment (const struct SH_Fragment * fragment)
 	return get_type (fragment) == NODE;
 }
 
+static inline
+/*@observer@*/
+char *
+get_tag (const struct SH_NodeFragment * fragment)
+	/*@*/
+{
+	return fragment->tag;
+}
+
 /*@null@*/
 /*@only@*/
 char *
@@ -287,7 +481,7 @@ SH_NodeFragment_get_tag (const struct SH_NodeFragment * fragment,
 {
 	char * tag;
 
-	tag = strdup (fragment->tag);
+	tag = strdup (get_tag (fragment));
 
 	if (tag == NULL)
 	{
@@ -303,109 +497,892 @@ SH_NodeFragment_get_tag (const struct SH_NodeFragment * fragment,
 	return tag;
 }
 
+/*@observer@*/
+char *
+SH_NodeFragment_raw_get_tag (const struct SH_NodeFragment * fragment)
+{
+	return get_tag (fragment);
+}
+
+/*@null@*/
+/*@dependent@*/
+struct SH_NodeFragment *
+SH_Fragment_get_parent (const struct SH_Fragment * fragment)
+	/*@*/
+{
+	return get_parent (fragment);
+}
+
+size_t
+SH_NodeFragment_count_attrs (const struct SH_NodeFragment * fragment)
+	/*@*/
+{
+	return fragment->attr_n;
+}
+
 /*@null@*/
 /*@observer@*/
-const struct SH_Fragment *
-SH_NodeFragment_get_child (const struct SH_NodeFragment * fragment,
-                           size_t index,
-                           /*@out@*/ /*@null@*/
-                           struct SH_Status * status)
+const SH_Attr *
+SH_NodeFragment_get_attr (const struct SH_NodeFragment * fragment,
+                          size_t index,
+                          /*@out@*/ /*@null@*/
+                          struct SH_Status * status)
 	/*@globals fileSystem@*/
 	/*@modifies fileSystem@*/
 	/*@modifies status@*/
 {
-	if (index >= fragment->child_n)
+	if (index >= fragment->attr_n)
 	{
 		set_status (status, E_VALUE, 2,
-		            "Fragment: Child index out of range.\n");
+		            "Fragment: Attr index out of range.\n");
 
 		return NULL;
 	}
 
 	set_success (status);
 
-	return fragment->childs[index];
+	return &(fragment->attrs[index]);
 }
 
+static inline
 bool
-SH_NodeFragment_is_child (const struct SH_NodeFragment * fragment,
-                          const struct SH_Fragment * child)
-	/*@*/
+insert_attr (struct SH_NodeFragment * fragment,
+             /*@only@*/ SH_Attr * attr,
+             size_t position,
+             /*@out@*/ /*@null@*/ struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@modifies attr@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
 {
+	size_t new_size;
 	size_t index;
+	typeof (fragment->attrs) new_attrs;
 
-	for (index = 0; index < fragment->child_n; index++)
+	new_size = get_attr_alloc_size (fragment->attr_n + 1);
+	if (new_size > fragment->attr_s)
 	{
-		if (fragment->childs[index] == child)
+		if ((SIZE_MAX / sizeof (*new_attrs)) < new_size)
 		{
-			return TRUE;
+			set_status (status, E_DOMAIN, -6,
+			            "maximum number of "
+			            "attrs reached.\n");
+			return FALSE;
+		}
+
+		new_attrs = realloc (fragment->attrs, new_size
+		                      * sizeof (*new_attrs));
+
+		if (new_attrs == NULL)
+		{
+			set_status (status, E_ALLOC, 5,
+			            "malloc failed\n");
+
+/* bad code to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+			fragment->attrs = (void *) 0x12345;
+#endif
+			return FALSE;
 		}
+
+		fragment->attrs = new_attrs;
+		fragment->attr_s = new_size;
 	}
-	return FALSE;
+
+	for (index = fragment->attr_n; index > position; index--)
+	{
+		fragment->attrs[index] = fragment->attrs[index-1];
+	}
+	Attr_move (&(fragment->attrs[position]), attr);
+	fragment->attr_n++;
+
+	set_success (status);
+
+	return TRUE;
 }
 
+static inline
 bool
-SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment,
-                          const struct SH_Fragment * child)
-	/*@*/
+insert_attr_new (struct SH_NodeFragment * fragment,
+                 /*@only@*/ char * name,
+                 /*@null@*/ /*@only@*/ char * value,
+                 size_t position,
+                 /*@out@*/ /*@null@*/ struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@modifies name@*/
+	/*@modifies value@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
 {
+	size_t new_size;
 	size_t index;
+	typeof (fragment->attrs) new_attrs;
 
-	for (index = 0; index < fragment->child_n; index++)
+	new_size = get_attr_alloc_size (fragment->attr_n + 1);
+	if (new_size > fragment->attr_s)
 	{
-		if (fragment->childs[index] == child
-		|| (SH_Fragment_is_NodeFragment (child)
-		    && SH_NodeFragment_is_descendant (
-		                        (struct SH_NodeFragment *)
-		                        fragment->childs[index],
-		                        child)))
+		if ((SIZE_MAX / sizeof (*new_attrs)) < new_size)
 		{
-			return TRUE;
+			set_status (status, E_DOMAIN, -6,
+			            "maximum number of "
+			            "attrs reached.\n");
+			return FALSE;
+		}
+
+		new_attrs = realloc (fragment->attrs, new_size
+		                      * sizeof (*new_attrs));
+
+		if (new_attrs == NULL)
+		{
+			set_status (status, E_ALLOC, 5,
+			            "malloc failed\n");
+
+/* bad code to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+			fragment->attrs = (void *) 0x12345;
+#endif
+			return FALSE;
 		}
+
+		fragment->attrs = new_attrs;
+		fragment->attr_s = new_size;
 	}
-	return FALSE;
+
+	for (index = fragment->attr_n; index > position; index--)
+	{
+		fragment->attrs[index] = fragment->attrs[index-1];
+	}
+	Attr_raw_init (&(fragment->attrs[position]), name, value);
+	fragment->attr_n++;
+
+	set_success (status);
+
+	return TRUE;
 }
 
+static inline
 bool
-SH_NodeFragment_append_child (struct SH_NodeFragment * fragment,
-                              /*@only@*/ struct SH_Fragment * child,
-                              /*@out@*/ /*@null@*/
-                              struct SH_Status * status)
-	/*@modifies fragment->childs@*/
-	/*@modifies fragment->child_n@*/
+insert_attr_copy (struct SH_NodeFragment * fragment,
+                  const SH_Attr * attr,
+                  size_t position,
+                  /*@out@*/ /*@null@*/ struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
 	/*@globals fileSystem@*/
 	/*@modifies fileSystem@*/
 	/*@modifies status@*/
 {
-	struct SH_Fragment ** new_childs;
-
-	new_childs = realloc (fragment->childs,
-	                      sizeof (struct SH_Fragment *)
-	                      * (fragment->child_n + 1));
+	size_t new_size;
+	size_t index;
+	typeof (fragment->attrs) new_attrs;
 
-	if (new_childs == NULL)
+	new_size = get_attr_alloc_size (fragment->attr_n + 1);
+	if (new_size > fragment->attr_s)
 	{
-		set_status (status, E_ALLOC, 6,
-		            "Memory allocation for "
-		            "fragment child failed.\n");
+		if ((SIZE_MAX / sizeof (*new_attrs)) < new_size)
+		{
+			set_status (status, E_DOMAIN, -6,
+			            "maximum number of "
+			            "attrs reached.\n");
+			return FALSE;
+		}
+
+		new_attrs = realloc (fragment->attrs, new_size
+		                      * sizeof (*new_attrs));
+
+		if (new_attrs == NULL)
+		{
+			set_status (status, E_ALLOC, 5,
+			            "malloc failed\n");
 
 /* bad code to silence splint, should never be executed. */
 #ifdef S_SPLINT_S
-				fragment->childs = (void *) 0x12345;
+			fragment->attrs = (void *) 0x12345;
 #endif
-		return FALSE;
+			return FALSE;
+		}
+
+		fragment->attrs = new_attrs;
+		fragment->attr_s = new_size;
 	}
 
-	new_childs[fragment->child_n] = child;
+	for (index = fragment->attr_n; index > position; index--)
+	{
+		fragment->attrs[index] = fragment->attrs[index-1];
+	}
 
-	fragment->childs = new_childs;
-	fragment->child_n++;
+	if (!Attr_copy (&(fragment->attrs[position]), attr, status))
+	{
+		for (index = position; index < fragment->attr_n; index++)
+		{
+			fragment->attrs[index] = fragment->attrs[index+1];
+		}
+		return FALSE;
+	}
+
+	fragment->attr_n++;
 
 	set_success (status);
 
 	return TRUE;
 }
 
+bool
+SH_NodeFragment_insert_attr (struct SH_NodeFragment * fragment,
+                             /*@only@*/ SH_Attr * attr,
+                             size_t position,
+                             /*@out@*/ /*@null@*/
+                             struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	if (position > fragment->attr_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	return insert_attr (fragment, attr, position, status);
+}
+
+bool
+SH_NodeFragment_insert_attr_new (struct SH_NodeFragment * fragment,
+                                 /*@only@*/ char * name,
+                                 /*@null@*/ /*@only@*/ char * value,
+                                 size_t position,
+                                 /*@out@*/ /*@null@*/
+                                 struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	if (position > fragment->attr_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	return insert_attr_new (fragment, name, value, position, status);
+}
+
+bool
+SH_NodeFragment_insert_attr_copy (struct SH_NodeFragment * fragment,
+                                  const SH_Attr * attr,
+                                  size_t position,
+                                  /*@out@*/ /*@null@*/
+                                  struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	if (position > fragment->attr_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	return insert_attr_copy (fragment, attr, position, status);
+}
+
+bool
+SH_NodeFragment_prepend_attr (struct SH_NodeFragment * fragment,
+                              /*@only@*/ SH_Attr * attr,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_attr (fragment, attr, 0, status);
+}
+
+bool
+SH_NodeFragment_prepend_attr_new (struct SH_NodeFragment * fragment,
+                                  /*@only@*/ char * name,
+                                  /*@null@*/ /*@only@*/ char * value,
+                                  /*@out@*/ /*@null@*/
+                                  struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_attr_new (fragment, name, value, 0, status);
+}
+
+bool
+SH_NodeFragment_prepend_attr_copy (struct SH_NodeFragment * fragment,
+                                   const SH_Attr * attr,
+                                   /*@out@*/ /*@null@*/
+                                   struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_attr_copy (fragment, attr, 0, status);
+}
+
+bool
+SH_NodeFragment_append_attr (struct SH_NodeFragment * fragment,
+                             /*@only@*/ SH_Attr * attr,
+                             /*@out@*/ /*@null@*/
+                             struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_attr (fragment, attr, fragment->attr_n, status);
+}
+
+bool
+SH_NodeFragment_append_attr_new (struct SH_NodeFragment * fragment,
+                                 /*@only@*/ char * name,
+                                 /*@null@*/ /*@only@*/ char * value,
+                                 /*@out@*/ /*@null@*/
+                                 struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_attr_new (fragment, name, value,
+	                        fragment->attr_n, status);
+}
+
+bool
+SH_NodeFragment_append_attr_copy (struct SH_NodeFragment * fragment,
+                                  const SH_Attr * attr,
+                                  /*@out@*/ /*@null@*/
+                                  struct SH_Status * status)
+	/*@modifies fragment->attrs@*/
+	/*@modifies fragment->attr_s@*/
+	/*@modifies fragment->attr_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_attr_copy (fragment, attr, fragment->attr_n,
+	                         status);
+}
+
+size_t
+SH_NodeFragment_count_childs (const struct SH_NodeFragment * fragment)
+	/*@*/
+{
+	return fragment->child_n;
+}
+
+/*@null@*/
+/*@observer@*/
+const struct SH_Fragment *
+SH_NodeFragment_get_child (const struct SH_NodeFragment * fragment,
+                           size_t index,
+                           /*@out@*/ /*@null@*/
+                           struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	if (index >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "Fragment: Child index out of range.\n");
+
+		return NULL;
+	}
+
+	set_success (status);
+
+	return fragment->childs[index];
+}
+
+bool
+SH_NodeFragment_is_child (const struct SH_NodeFragment * fragment,
+                          const struct SH_Fragment * child)
+	/*@*/
+{
+	size_t index;
+
+	for (index = 0; index < fragment->child_n; index++)
+	{
+		if (fragment->childs[index] == child)
+		{
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+bool
+SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment,
+                          const struct SH_Fragment * child)
+	/*@*/
+{
+	size_t index;
+
+	for (index = 0; index < fragment->child_n; index++)
+	{
+		if (fragment->childs[index] == child
+		|| (SH_Fragment_is_NodeFragment (child)
+		    && SH_NodeFragment_is_descendant (
+		                        (struct SH_NodeFragment *)
+		                        fragment->childs[index],
+		                        child)))
+		{
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+bool
+SH_NodeFragment_is_parent (const struct SH_Fragment * fragment,
+                           const struct SH_NodeFragment * parent)
+	/*@*/
+{
+	if (parent == get_parent (fragment))
+	{
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+bool
+SH_NodeFragment_is_ancestor (const struct SH_Fragment * fragment,
+                             const struct SH_NodeFragment * ancestor)
+	/*@*/
+{
+	if ((NULL != get_parent (fragment))
+	&& ((ancestor == get_parent (fragment))
+	   || (SH_NodeFragment_is_ancestor ((const struct SH_Fragment *)
+	                                    get_parent (fragment),
+	                                    ancestor))))
+	{
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static inline
+bool
+insert_child (struct SH_NodeFragment * fragment,
+              /*@only@*/ struct SH_Fragment * child,
+              size_t position,
+              /*@out@*/ /*@null@*/ struct SH_Status * status)
+	/*@modifies fragment->childs@*/
+	/*@modifies fragment->child_s@*/
+	/*@modifies fragment->child_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t new_size;
+	size_t index;
+	struct SH_Fragment ** new_childs;
+
+	if (!SH_Fragment_is_orphan (child))
+	{
+		set_status (status, E_STATE, 2,
+		            "child is already linked; "
+		            "please unlink first or link a copy.\n");
+		return FALSE;
+	}
+
+	if (SH_Fragment_is_NodeFragment (child)
+	&& SH_NodeFragment_is_ancestor ((struct SH_Fragment *)fragment,
+	                                (struct SH_NodeFragment *)child))
+	{
+		set_status (status, E_STATE, 2,
+		            "refusing to make a tree cyclic.\n");
+		return FALSE;
+	}
+
+	new_size = get_child_alloc_size (fragment->child_n + 1);
+	if (new_size > fragment->child_s)
+	{
+		if ((SIZE_MAX / sizeof (*new_childs)) < new_size)
+		{
+			set_status (status, E_DOMAIN, -6,
+			            "maximum number of "
+			            "childs reached.\n");
+			return FALSE;
+		}
+
+		new_childs = realloc (fragment->childs, new_size
+		                      * sizeof (*new_childs));
+
+		if (new_childs == NULL)
+		{
+			set_status (status, E_ALLOC, 5,
+				    "Memory allocation for "
+				    "fragment child failed.\n");
+
+/* bad code to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+			fragment->childs = (void *) 0x12345;
+#endif
+			return FALSE;
+		}
+
+		fragment->childs = new_childs;
+		fragment->child_s = new_size;
+	}
+
+	for (index = fragment->child_n; index > position; index--)
+	{
+		fragment->childs[index] = fragment->childs[index-1];
+	}
+	fragment->childs[position] = child;
+	fragment->child_n++;
+	child->parent = fragment;
+
+	set_success (status);
+
+	return TRUE;
+}
+
+bool
+SH_NodeFragment_insert_child (struct SH_NodeFragment * fragment,
+                              /*@only@*/ struct SH_Fragment * child,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment->childs@*/
+	/*@modifies fragment->child_s@*/
+	/*@modifies fragment->child_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	if (position > fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	return insert_child (fragment, child, position, status);
+}
+
+bool
+SH_NodeFragment_prepend_child (struct SH_NodeFragment * fragment,
+                              /*@only@*/ struct SH_Fragment * child,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment->childs@*/
+	/*@modifies fragment->child_s@*/
+	/*@modifies fragment->child_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_child (fragment, child, 0, status);
+}
+
+bool
+SH_NodeFragment_append_child (struct SH_NodeFragment * fragment,
+                              /*@only@*/ struct SH_Fragment * child,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment->childs@*/
+	/*@modifies fragment->child_s@*/
+	/*@modifies fragment->child_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	return insert_child (fragment, child, fragment->child_n, status);
+}
+
+bool
+SH_NodeFragment_insert_child_before (struct SH_Fragment * fragment,
+                                     /*@only@*/
+                                     struct SH_Fragment * child,
+                                     /*@out@*/ /*@null@*/
+                                     struct SH_Status * status)
+	/*@modifies fragment->childs@*/
+	/*@modifies fragment->child_s@*/
+	/*@modifies fragment->child_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t index;
+
+	#define parent get_parent (fragment)
+	if (NULL == parent)
+	{
+		set_status (status, E_STATE, 2,
+		            "child is not linked, "
+		            "can't insert before.\n");
+		return FALSE;
+	}
+
+	for (index = 0; index < parent->child_n; index++)
+	{
+		if (parent->childs[index] == fragment)
+		{
+			return insert_child (parent, child,
+			                     index, status);
+		}
+	}
+	#undef parent
+
+	set_status (status, E_BUG, 10,
+	            "fragment is both child and not child.\n");
+	return FALSE;
+}
+
+bool
+SH_NodeFragment_insert_child_after (struct SH_Fragment * fragment,
+                                    /*@only@*/
+                                    struct SH_Fragment * child,
+                                    /*@out@*/ /*@null@*/
+                                    struct SH_Status * status)
+	/*@modifies fragment->childs@*/
+	/*@modifies fragment->child_s@*/
+	/*@modifies fragment->child_n@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t index;
+
+	#define parent get_parent (fragment)
+	if (NULL == parent)
+	{
+		set_status (status, E_STATE, 2,
+		            "child is not linked, "
+		            "can't insert before.\n");
+		return FALSE;
+	}
+
+	for (index = 0; index < parent->child_n; index++)
+	{
+		if (parent->childs[index] == fragment)
+		{
+			return insert_child (parent, child,
+			                     index+1, status);
+		}
+	}
+	#undef parent
+
+	set_status (status, E_BUG, 10,
+	            "fragment is both child and not child.\n");
+	return FALSE;
+}
+
+static inline
+/*@null@*/
+/*@only@*/
+struct SH_Fragment *
+remove_child (struct SH_NodeFragment * fragment, size_t position,
+              /*@out@*/ /*@null@*/ struct SH_Status * status)
+{
+	size_t index;
+	size_t new_size;
+	typeof (fragment->childs) new_childs;
+	struct SH_Fragment * child;
+
+	child = fragment->childs[position];
+
+	for (index = position+1; index < fragment->child_n; index++)
+	{
+		fragment->childs[index-1] = fragment->childs[index];
+	}
+
+	new_size = get_child_alloc_size (fragment->child_n - 1);
+	if (new_size < fragment->child_s)
+	{
+		new_childs = realloc (fragment->childs, new_size
+		                      * sizeof (*new_childs));
+		if ((0 != new_size) && (NULL == new_childs))
+		{
+			for (index = fragment->child_n-1;
+			     index > position;
+			     index--)
+			{
+				fragment->childs[index] =
+				fragment->childs[index-1];
+			}
+			fragment->childs[position] = child;
+
+			set_status (status, E_ALLOC, 4,
+			            "realloc failed.\n");
+			return NULL;
+		}
+
+		fragment->childs = new_childs;
+		fragment->child_s = new_size;
+	}
+
+	fragment->child_n--;
+	child->parent = NULL;
+
+	set_success (status);
+
+	return child;
+}
+
+bool
+SH_Fragment_remove (struct SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status)
+{
+	size_t index;
+
+	#define parent get_parent (fragment)
+	if (NULL == parent)
+	{
+		set_status (status, E_STATE, 2,
+		            "fragment not linked, "
+		            "can't remove it from parent");
+		return FALSE;
+	}
+
+	for (index = 0; index < parent->child_n; index++)
+	{
+		if (fragment == parent->childs[index])
+		{
+			return NULL != remove_child (parent, index,
+			                             status);
+		}
+	}
+	#undef parent
+
+	set_status (status, E_BUG, 10,
+	            "fragment is both child and not child.\n");
+	return FALSE;
+}
+
+bool
+SH_Fragment_delete (/*@only@*/ struct SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status)
+{
+	size_t index;
+
+	#define parent get_parent (fragment)
+	if (NULL == parent)
+	{
+		set_status (status, E_STATE, 2,
+		            "fragment not linked, "
+		            "can't remove it from parent");
+		return FALSE;
+	}
+
+	for (index = 0; index < parent->child_n; index++)
+	{
+		if (fragment == parent->childs[index])
+		{
+			if (NULL == remove_child (parent, index, status))
+			{
+				return FALSE;
+			}
+
+			SH_Fragment_free (fragment);
+			return TRUE;
+		}
+	}
+	#undef parent
+
+	set_status (status, E_BUG, 10,
+	            "fragment is both child and not child.\n");
+	return FALSE;
+}
+
+bool
+SH_NodeFragment_remove_child (struct SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+{
+	if (position >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	return NULL != remove_child (fragment, position, status);
+}
+
+bool
+SH_NodeFragment_delete_child (struct SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+{
+	struct SH_Fragment * child;
+
+	if (position >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	child = remove_child (fragment, position, status);
+	if (NULL == child)
+	{
+		return FALSE;
+	}
+
+	SH_Fragment_free (child);
+	return TRUE;
+}
+
+/*@null@*/
+/*@only@*/
+struct SH_Fragment *
+SH_NodeFragment_pop_child (struct SH_NodeFragment * fragment,
+                           size_t position,
+                           /*@out@*/ /*@null@*/
+                           struct SH_Status * status)
+{
+	if (position >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return NULL;
+	}
+
+	return remove_child (fragment, position, status);
+}
+
 /*@null@*/
 /*@only@*/
 struct SH_Text *
diff --git a/src/lib/sefht/node_fragment.h b/src/lib/sefht/node_fragment.h
index d9c540486fa3201a690e1432e9e58f81569a886b..eb07c6e711f93f152fa50e9b02fdf2ac51da3aa7 100644
--- a/src/lib/sefht/node_fragment.h
+++ b/src/lib/sefht/node_fragment.h
@@ -31,6 +31,7 @@
 
 #include "status.h"
 
+#include "attr.h"
 #include "data.h"
 #include "text.h"
 
@@ -80,6 +81,122 @@ bool
 SH_Fragment_is_NodeFragment (const SH_Fragment * fragment)
 	/*@*/;
 
+/*@null@*/
+/*@dependent@*/
+SH_NodeFragment *
+SH_Fragment_get_parent (const SH_Fragment * fragment)
+	/*@*/;
+
+size_t
+SH_NodeFragment_count_attrs (const SH_NodeFragment * fragment)
+	/*@*/;
+
+/*@null@*/
+/*@observer@*/
+const SH_Attr *
+SH_NodeFragment_get_attr (const SH_NodeFragment * fragment,
+                          size_t index,
+                          /*@out@*/ /*@null@*/
+                          struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_insert_attr (SH_NodeFragment * fragment,
+                             /*@only@*/ SH_Attr * attr,
+                             size_t position,
+                             /*@out@*/ /*@null@*/
+                             struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_insert_attr_new (SH_NodeFragment * fragment,
+                                 /*@only@*/ char * name,
+                                 /*@null@*/ /*@only@*/ char * value,
+                                 size_t position,
+                                 /*@out@*/ /*@null@*/
+                                 struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_insert_attr_copy (SH_NodeFragment * fragment,
+                                  const SH_Attr * attr,
+                                  size_t position,
+                                  /*@out@*/ /*@null@*/
+                                  struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_prepend_attr (SH_NodeFragment * fragment,
+                              /*@only@*/ SH_Attr * attr,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_prepend_attr_new (SH_NodeFragment * fragment,
+                                  /*@only@*/ char * name,
+                                  /*@null@*/ /*@only@*/ char * value,
+                                  /*@out@*/ /*@null@*/
+                                  struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_prepend_attr_copy (SH_NodeFragment * fragment,
+                                   const SH_Attr * attr,
+                                   /*@out@*/ /*@null@*/
+                                   struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_append_attr (SH_NodeFragment * fragment,
+                             /*@only@*/ SH_Attr * attr,
+                             /*@out@*/ /*@null@*/
+                             struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_append_attr_new (SH_NodeFragment * fragment,
+                                 /*@only@*/ char * name,
+                                 /*@null@*/ /*@only@*/ char * value,
+                                 /*@out@*/ /*@null@*/
+                                 struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+bool
+SH_NodeFragment_append_attr_copy (SH_NodeFragment * fragment,
+                                  const SH_Attr * attr,
+                                  /*@out@*/ /*@null@*/
+                                  struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
 /*@null@*/
 /*@only@*/
 char *
@@ -106,13 +223,44 @@ SH_NodeFragment_is_child (const SH_NodeFragment * fragment,
 	/*@*/;
 
 bool
-SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment,
-                          const struct SH_Fragment * child)
+SH_NodeFragment_is_descendant (const SH_NodeFragment * fragment,
+                          const SH_Fragment * child)
 	/*@*/;
 
 bool
-SH_NodeFragment_append_child (struct SH_NodeFragment * fragment,
-                              /*@only@*/ struct SH_Fragment * child,
+SH_NodeFragment_is_parent (const SH_Fragment * fragment,
+                           const SH_NodeFragment * parent)
+	/*@*/;
+
+bool
+SH_NodeFragment_is_ancestor (const SH_Fragment * fragment,
+                             const SH_NodeFragment * ancestor)
+	/*@*/;
+
+bool
+SH_NodeFragment_insert_child (SH_NodeFragment * fragment,
+                              /*@only@*/ SH_Fragment * child,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_prepend_child (SH_NodeFragment * fragment,
+                              /*@only@*/ SH_Fragment * child,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_append_child (SH_NodeFragment * fragment,
+                              /*@only@*/ SH_Fragment * child,
                               /*@out@*/ /*@null@*/
                               struct SH_Status * status)
 	/*@modifies fragment@*/
@@ -120,6 +268,54 @@ SH_NodeFragment_append_child (struct SH_NodeFragment * fragment,
 	/*@modifies fileSystem@*/
 	/*@modifies status@*/;
 
+bool
+SH_NodeFragment_insert_child_before (SH_Fragment * fragment,
+                                     /*@only@*/ SH_Fragment * child,
+                                     /*@out@*/ /*@null@*/
+                                     struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_NodeFragment_insert_child_after (SH_Fragment * fragment,
+                                    /*@only@*/ SH_Fragment * child,
+                                    /*@out@*/ /*@null@*/
+                                    struct SH_Status * status)
+	/*@modifies fragment@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_Fragment_remove (SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status);
+
+bool
+SH_Fragment_delete (/*@only@*/ SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status);
+
+bool
+SH_NodeFragment_remove_child (SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status);
+
+bool
+SH_NodeFragment_delete_child (SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status);
+
+/*@null@*/
+/*@only@*/
+SH_Fragment *
+SH_NodeFragment_pop_child (SH_NodeFragment * fragment,
+                           size_t position,
+                           /*@out@*/ /*@null@*/
+                           struct SH_Status * status);
+
 /*@null@*/
 /*@only@*/
 SH_Text *
diff --git a/src/lib/sefht/status.h b/src/lib/sefht/status.h
index 4b4b479ee2b7fb623f650127ab686e3b939f49ae..8ee1a364449c950c09bde844073b6ddbd8d69d90 100644
--- a/src/lib/sefht/status.h
+++ b/src/lib/sefht/status.h
@@ -112,7 +112,9 @@ struct SH_Status
 		SUCCESS,
 		E_ALLOC,
 		E_DOMAIN,
-		E_VALUE
+		E_VALUE,
+		E_STATE,
+		E_BUG
 	} status;
 
 	int errno_;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3053a22bd19ee3328a38ac7e9d429706061654b2..9c28186773ea6669c96f9261eaf5971394e6bb1d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,6 +3,7 @@
 AM_CFLAGS = -Wall -Wextra -Wno-nonnull $(CHECK_CFLAGS)
 
 TESTS =
+TESTS += sefht_attr_test
 TESTS += sefht_cms_test
 TESTS += sefht_data_test
 TESTS += sefht_node_fragment_test
@@ -18,6 +19,10 @@ LDADD = $(CHECK_LIBS)
 
 OBJECT_PREFIX = $(top_builddir)/src/lib/sefht/libsefht_la-
 
+sefht_attr_test_SOURCES = test_attr.c
+sefht_attr_test_LDADD =
+sefht_attr_test_LDADD += $(LDADD)
+
 sefht_cms_test_SOURCES = test_cms.c
 sefht_cms_test_LDADD =
 sefht_cms_test_LDADD += $(OBJECT_PREFIX)data.o
@@ -31,6 +36,7 @@ sefht_data_test_LDADD += $(LDADD)
 
 sefht_node_fragment_test_SOURCES = test_node_fragment.c
 sefht_node_fragment_test_LDADD =
+sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)attr.o
 sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)data.o
 sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)fragment.o
 sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)text.o
diff --git a/tests/test_attr.c b/tests/test_attr.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4d20bad2e31d0ace2281c18fabf1dacf3dc07da
--- /dev/null
+++ b/tests/test_attr.c
@@ -0,0 +1,634 @@
+/*
+ * test_attr.c
+ *
+ * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+
+#include <check.h>
+#include <stdlib.h>
+
+#include "status.h"
+
+#include "attr.c"
+
+
+START_TEST(test_attr1_no_status)
+{
+	struct SH_Attr * attr;
+	const char * name = "name";
+
+	attr = SH_Attr_new (name, NULL, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_ne (name, attr->name);
+	ck_assert_str_eq (name, attr->name);
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr1_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	const char * name = "name";
+
+	_status_preinit (status);
+	attr = SH_Attr_new (name, NULL, &status);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (name, attr->name);
+	ck_assert_str_eq (name, attr->name);
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr2_no_status)
+{
+	struct SH_Attr * attr;
+	const char * name = "name";
+	const char * value = "value";
+
+	attr = SH_Attr_new (name, value, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_ne (name, attr->name);
+	ck_assert_str_eq (name, attr->name);
+	ck_assert_ptr_ne (value, attr->value);
+	ck_assert_str_eq (value, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr2_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	const char * name = "name";
+	const char * value = "value";
+
+	_status_preinit (status);
+	attr = SH_Attr_new (name, value, &status);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (name, attr->name);
+	ck_assert_str_eq (name, attr->name);
+	ck_assert_ptr_ne (value, attr->value);
+	ck_assert_str_eq (value, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_raw1_no_status)
+{
+	struct SH_Attr * attr;
+	char * name = strdup ("name");
+
+	attr = SH_Attr_raw_new (name, NULL, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_eq (name, attr->name);
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_raw1_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	char * name = strdup ("name");
+
+	_status_preinit (status);
+	attr = SH_Attr_raw_new (name, NULL, &status);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_eq (name, attr->name);
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_raw2_no_status)
+{
+	struct SH_Attr * attr;
+	char * name = strdup ("name");
+	char * value = strdup ("value");
+
+	attr = SH_Attr_raw_new (name, value, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_eq (name, attr->name);
+	ck_assert_ptr_eq (value, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_raw2_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	char * name = strdup ("name");
+	char * value = strdup ("value");
+
+	_status_preinit (status);
+	attr = SH_Attr_raw_new (name, value, &status);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_eq (name, attr->name);
+	ck_assert_ptr_eq (value, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_copy1_no_status)
+{
+	struct SH_Attr * attr;
+	struct SH_Attr * copy;
+	const char * name = "name";
+
+	attr = SH_Attr_new (name, NULL, NULL);
+
+	copy = SH_Attr_copy (attr, NULL);
+	ck_assert_ptr_ne (NULL, copy);
+	ck_assert_ptr_ne (attr->name, copy->name);
+	ck_assert_str_eq (attr->name, copy->name);
+	ck_assert_ptr_eq (NULL, copy->value);
+
+	SH_Attr_free (attr);
+	SH_Attr_free (copy);
+}
+END_TEST
+
+START_TEST(test_attr_copy1_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	struct SH_Attr * copy;
+	const char * name = "name";
+
+	attr = SH_Attr_new (name, NULL, NULL);
+
+	_status_preinit (status);
+	copy = SH_Attr_copy (attr, &status);
+	ck_assert_ptr_ne (NULL, copy);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (attr->name, copy->name);
+	ck_assert_str_eq (attr->name, copy->name);
+	ck_assert_ptr_eq (NULL, copy->value);
+
+	SH_Attr_free (attr);
+	SH_Attr_free (copy);
+}
+END_TEST
+
+START_TEST(test_attr_copy2_no_status)
+{
+	struct SH_Attr * attr;
+	struct SH_Attr * copy;
+	const char * name = "name";
+	const char * value = "value";
+
+	attr = SH_Attr_new (name, value, NULL);
+
+	copy = SH_Attr_copy (attr, NULL);
+	ck_assert_ptr_ne (NULL, copy);
+	ck_assert_ptr_ne (attr->name, copy->name);
+	ck_assert_str_eq (attr->name, copy->name);
+	ck_assert_ptr_ne (attr->value, copy->value);
+	ck_assert_str_eq (attr->value, copy->value);
+
+	SH_Attr_free (attr);
+	SH_Attr_free (copy);
+}
+END_TEST
+
+START_TEST(test_attr_copy2_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	struct SH_Attr * copy;
+	const char * name = "name";
+	const char * value = "value";
+
+	attr = SH_Attr_new (name, value, NULL);
+
+	_status_preinit (status);
+	copy = SH_Attr_copy (attr, &status);
+	ck_assert_ptr_ne (NULL, copy);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (attr->name, copy->name);
+	ck_assert_str_eq (attr->name, copy->name);
+	ck_assert_ptr_ne (attr->value, copy->value);
+	ck_assert_str_eq (attr->value, copy->value);
+
+	SH_Attr_free (attr);
+	SH_Attr_free (copy);
+}
+END_TEST
+
+START_TEST(test_attr_name_no_status)
+{
+	struct SH_Attr * attr;
+	const char * name1 = "name1";
+	const char * name2 = "name2";
+	char * name;
+	bool result;
+
+	attr = SH_Attr_new (name1, NULL, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_ne (name1, attr->name);
+	ck_assert_str_eq (name1, attr->name);
+
+	name = SH_Attr_get_name (attr, NULL);
+	ck_assert_ptr_ne (NULL, name);
+	ck_assert_ptr_ne (name1, name);
+	ck_assert_str_eq (name1, name);
+	free (name);
+
+	result = SH_Attr_set_name (attr, name2, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_ptr_ne (name2, attr->name);
+	ck_assert_str_eq (name2, attr->name);
+
+	name = SH_Attr_get_name (attr, NULL);
+	ck_assert_ptr_ne (NULL, name);
+	ck_assert_ptr_ne (name2, name);
+	ck_assert_str_eq (name2, name);
+	free (name);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_name_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	const char * name1 = "name1";
+	const char * name2 = "name2";
+	char * name;
+	bool result;
+
+	_status_preinit (status);
+	attr = SH_Attr_new (name1, NULL, &status);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (name1, attr->name);
+	ck_assert_str_eq (name1, attr->name);
+
+	_status_preinit (status);
+	name = SH_Attr_get_name (attr, &status);
+	ck_assert_ptr_ne (NULL, name);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (name1, name);
+	ck_assert_str_eq (name1, name);
+	free (name);
+
+	_status_preinit (status);
+	result = SH_Attr_set_name (attr, name2, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (name2, attr->name);
+	ck_assert_str_eq (name2, attr->name);
+
+	_status_preinit (status);
+	name = SH_Attr_get_name (attr, &status);
+	ck_assert_ptr_ne (NULL, name);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (name2, name);
+	ck_assert_str_eq (name2, name);
+	free (name);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_name_raw)
+{
+	struct SH_Attr * attr;
+	char * name1 = strdup ("name1");
+	char * name2 = strdup ("name2");
+	const char * name;
+
+	attr = SH_Attr_raw_new (name1, NULL, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_eq (name1, attr->name);
+
+	name = SH_Attr_raw_get_name (attr);
+	ck_assert_ptr_ne (NULL, name);
+	ck_assert_ptr_eq (name1, name);
+
+	SH_Attr_raw_set_name (attr, name2);
+	ck_assert_ptr_eq (name2, attr->name);
+
+	name = SH_Attr_raw_get_name (attr);
+	ck_assert_ptr_ne (NULL, name);
+	ck_assert_ptr_eq (name2, name);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_value_no_status)
+{
+	struct SH_Attr * attr;
+	const char * name = "name";
+	const char * value1 = "value1";
+	const char * value2 = "value2";
+	char * value;
+	bool result;
+
+	attr = SH_Attr_new (name, NULL, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	value = SH_Attr_get_value (attr, NULL);
+	ck_assert_ptr_eq (NULL, value);
+
+	result = SH_Attr_set_value (attr, value1, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_ptr_ne (value1, attr->value);
+	ck_assert_str_eq (value1, attr->value);
+
+	value = SH_Attr_get_value (attr, NULL);
+	ck_assert_ptr_ne (NULL, value);
+	ck_assert_ptr_ne (value1, value);
+	ck_assert_str_eq (value1, value);
+	free (value);
+
+	result = SH_Attr_set_value (attr, value2, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_ptr_ne (value2, attr->value);
+	ck_assert_str_eq (value2, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_value_with_status)
+{
+	struct SH_Status status;
+	struct SH_Attr * attr;
+	const char * name = "name";
+	const char * value1 = "value1";
+	const char * value2 = "value2";
+	char * value;
+	bool result;
+
+	_status_preinit (status);
+	attr = SH_Attr_new (name, NULL, &status);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	_status_preinit (status);
+	value = SH_Attr_get_value (attr, &status);
+	ck_assert_ptr_eq (NULL, value);
+	ck_assert (succeed (&status));
+
+	_status_preinit (status);
+	result = SH_Attr_set_value (attr, value1, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (value1, attr->value);
+	ck_assert_str_eq (value1, attr->value);
+
+	_status_preinit (status);
+	value = SH_Attr_get_value (attr, &status);
+	ck_assert_ptr_ne (NULL, value);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (value1, value);
+	ck_assert_str_eq (value1, value);
+	free (value);
+
+	_status_preinit (status);
+	result = SH_Attr_set_value (attr, value2, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+	ck_assert_ptr_ne (value2, attr->value);
+	ck_assert_str_eq (value2, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_value_raw)
+{
+	struct SH_Attr * attr;
+	char * name = strdup ("name");
+	char * value1 = strdup ("value1");
+	char * value2 = strdup ("value2");
+	const char * value;
+
+	attr = SH_Attr_raw_new (name, NULL, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+	ck_assert_ptr_eq (NULL, attr->value);
+
+	value = SH_Attr_raw_get_value (attr);
+	ck_assert_ptr_eq (NULL, value);
+
+	SH_Attr_raw_set_value (attr, value1);
+	ck_assert_ptr_eq (value1, attr->value);
+
+	value = SH_Attr_raw_get_value (attr);
+	ck_assert_ptr_ne (NULL, value);
+	ck_assert_ptr_eq (value1, value);
+
+	SH_Attr_raw_set_value (attr, value2);
+	ck_assert_ptr_eq (value2, attr->value);
+
+	SH_Attr_free (attr);
+}
+END_TEST
+
+START_TEST(test_attr_equal)
+{
+	struct
+	{
+		struct
+		{
+			char * name;
+			char * value;
+		} _[2];
+		bool result;
+	} tests[] =
+	{
+		{{{"name", NULL}, {"name", NULL}}, TRUE},
+		{{{"name", "value"}, {"name", NULL}}, FALSE},
+		{{{"name", "value"}, {"name", "value"}}, TRUE},
+		{{{"name", "value1"}, {"name", "value2"}}, FALSE},
+		{{{"name1", NULL}, {"name2", NULL}}, FALSE},
+		{{{"name1", "value"}, {"name2", NULL}}, FALSE},
+		{{{"name1", "value"}, {"name2", "value"}}, FALSE},
+		{{{"name1", "value1"}, {"name2", "value2"}}, FALSE}
+	};
+	const size_t size = sizeof (tests) / sizeof (tests[0]);
+	size_t index;
+
+	for (index = 0; index < size; index++)
+	{
+		struct SH_Attr * attr1;
+		struct SH_Attr * attr2;
+		bool result;
+
+		attr1 = SH_Attr_new (tests[index]._[0].name,
+		                     tests[index]._[0].value, NULL);
+		ck_assert_ptr_ne (NULL, attr1);
+
+		attr2 = SH_Attr_new (tests[index]._[1].name,
+		                     tests[index]._[1].value, NULL);
+		ck_assert_ptr_ne (NULL, attr2);
+
+		result = SH_Attr_is_equal (attr1, attr2);
+		ck_assert_int_eq (result, tests[index].result);
+
+		result = SH_Attr_is_equal (attr2, attr1);
+		ck_assert_int_eq (result, tests[index].result);
+
+		result = Attr_is_equal (attr1, attr2);
+		ck_assert_int_eq (result, tests[index].result);
+
+		result = Attr_is_equal (attr2, attr1);
+		ck_assert_int_eq (result, tests[index].result);
+
+		SH_Attr_free (attr1);
+		SH_Attr_free (attr2);
+	}
+}
+
+START_TEST(test_attr_equal_name)
+{
+	struct
+	{
+		struct
+		{
+			char * name;
+			char * value;
+		} _[2];
+		bool result;
+	} tests[] =
+	{
+		{{{"name", NULL}, {"name", NULL}}, TRUE},
+		{{{"name", "value"}, {"name", NULL}}, TRUE},
+		{{{"name", "value"}, {"name", "value"}}, TRUE},
+		{{{"name", "value1"}, {"name", "value2"}}, TRUE},
+		{{{"name1", NULL}, {"name2", NULL}}, FALSE},
+		{{{"name1", "value"}, {"name2", NULL}}, FALSE},
+		{{{"name1", "value"}, {"name2", "value"}}, FALSE},
+		{{{"name1", "value1"}, {"name2", "value2"}}, FALSE}
+	};
+	const size_t size = sizeof (tests) / sizeof (tests[0]);
+	size_t index;
+
+	for (index = 0; index < size; index++)
+	{
+		struct SH_Attr * attr1;
+		struct SH_Attr * attr2;
+		bool result;
+
+		attr1 = SH_Attr_new (tests[index]._[0].name,
+		                     tests[index]._[0].value, NULL);
+		ck_assert_ptr_ne (NULL, attr1);
+
+		attr2 = SH_Attr_new (tests[index]._[1].name,
+		                     tests[index]._[1].value, NULL);
+		ck_assert_ptr_ne (NULL, attr2);
+
+		result = SH_Attr_is_equal_name (attr1, attr2);
+		ck_assert_int_eq (result, tests[index].result);
+
+		result = SH_Attr_is_equal_name (attr2, attr1);
+		ck_assert_int_eq (result, tests[index].result);
+
+		result = Attr_is_equal_name (attr1, attr2);
+		ck_assert_int_eq (result, tests[index].result);
+
+		result = Attr_is_equal_name (attr2, attr1);
+		ck_assert_int_eq (result, tests[index].result);
+
+		SH_Attr_free (attr1);
+		SH_Attr_free (attr2);
+	}
+}
+
+Suite * test_suite (void)
+{
+	Suite *s;
+	TCase *tc_core;
+
+	s = suite_create ("Testsuite SeFHT Attr");
+
+	/* Core test case */
+	tc_core = tcase_create ("Core");
+
+	tcase_add_test (tc_core, test_attr1_no_status);
+	tcase_add_test (tc_core, test_attr1_with_status);
+	tcase_add_test (tc_core, test_attr2_no_status);
+	tcase_add_test (tc_core, test_attr2_with_status);
+
+	tcase_add_test (tc_core, test_attr_raw1_no_status);
+	tcase_add_test (tc_core, test_attr_raw1_with_status);
+	tcase_add_test (tc_core, test_attr_raw2_no_status);
+	tcase_add_test (tc_core, test_attr_raw2_with_status);
+
+	tcase_add_test (tc_core, test_attr_copy1_no_status);
+	tcase_add_test (tc_core, test_attr_copy1_with_status);
+	tcase_add_test (tc_core, test_attr_copy2_no_status);
+	tcase_add_test (tc_core, test_attr_copy2_with_status);
+
+	tcase_add_test (tc_core, test_attr_name_no_status);
+	tcase_add_test (tc_core, test_attr_name_with_status);
+	tcase_add_test (tc_core, test_attr_name_raw);
+
+	tcase_add_test (tc_core, test_attr_value_no_status);
+	tcase_add_test (tc_core, test_attr_value_with_status);
+	tcase_add_test (tc_core, test_attr_value_raw);
+
+	tcase_add_test (tc_core, test_attr_equal);
+	tcase_add_test (tc_core, test_attr_equal_name);
+
+	suite_add_tcase (s, tc_core);
+
+	return s;
+}
+
+int main (void)
+{
+	int number_failed;
+	Suite *s;
+	SRunner *sr;
+
+	s = test_suite ();
+	sr = srunner_create (s);
+
+	srunner_run_all (sr, CK_NORMAL);
+	number_failed = srunner_ntests_failed (sr);
+	srunner_free (sr);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c
index 95ce707330f77fa8c9622d9b19ab370715e9373d..43fd79f7f5ab5110c10e88009f83671e4c4ea931 100644
--- a/tests/test_node_fragment.c
+++ b/tests/test_node_fragment.c
@@ -32,213 +32,367 @@
 #include "node_fragment.c"
 
 
-START_TEST(test_node_fragment)
+START_TEST(test_node_fragment_no_status)
 {
-	struct SH_Status status;
-	struct SH_Fragment * fragment;
-	struct SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	SH_Data * data;
 	const char * tag = "tag";
 
 	data = SH_Data_new (NULL);
 
-	/* valid tag - no error */
-	fragment = SH_NodeFragment_new (tag, data, NULL);
-	ck_assert_int_ne ((long int) fragment, (long int) NULL);
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_new (tag, data, NULL);
 
-	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag, tag);
+	ck_assert_ptr_ne (NULL, fragment);
 
-	SH_Fragment_free (fragment);
+	ck_assert_ptr_eq (NULL, fragment->base.parent);
+	ck_assert_str_eq (fragment->tag, tag);
+
+	ck_assert_int_eq (0, fragment->attr_n);
+	ck_assert_int_eq (0, fragment->attr_s);
+
+	ck_assert_int_eq (0, fragment->child_n);
+	ck_assert_int_eq (0, fragment->child_s);
+
+	SH_NodeFragment_free (fragment);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * fragment;
+	SH_Data * data;
+	const char * tag = "tag";
+
+	data = SH_Data_new (NULL);
 
-	/* valid tag - error */
 	_status_preinit (status);
-	fragment = SH_NodeFragment_new (tag, data, &status);
-	ck_assert_int_ne ((long int) fragment, (long int) NULL);
-	ck_assert_int_eq (status.status, SUCCESS);
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_new (tag, data, &status);
 
-	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag, tag);
+	ck_assert_ptr_ne (NULL, fragment);
+	ck_assert (succeed (&status));
 
-	SH_Fragment_free (fragment);
+	ck_assert_ptr_eq (NULL, fragment->base.parent);
+	ck_assert_str_eq (fragment->tag, tag);
+
+	ck_assert_int_eq (0, fragment->attr_n);
+	ck_assert_int_eq (0, fragment->attr_s);
+
+	ck_assert_int_eq (0, fragment->child_n);
+	ck_assert_int_eq (0, fragment->child_s);
+
+	SH_NodeFragment_free (fragment);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_raw_no_status)
+{
+	struct SH_NodeFragment * fragment;
+	SH_Data * data;
+	char * tag = strdup ("tag");
+
+	data = SH_Data_new (NULL);
+
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_raw_new (tag, data, NULL);
+
+	ck_assert_ptr_ne (NULL, fragment);
+
+	ck_assert_ptr_eq (NULL, fragment->base.parent);
+	ck_assert_ptr_eq (fragment->tag, tag);
+
+	ck_assert_int_eq (0, fragment->attr_n);
+	ck_assert_int_eq (0, fragment->attr_s);
+
+	ck_assert_int_eq (0, fragment->child_n);
+	ck_assert_int_eq (0, fragment->child_s);
+
+	SH_NodeFragment_free (fragment);
 
 	SH_Data_free (data);
 }
 END_TEST
 
-START_TEST(test_node_fragment_copy)
+START_TEST(test_node_fragment_raw_with_status)
 {
 	struct SH_Status status;
-	struct SH_Fragment * fragment;
-	struct SH_Fragment * copy;
-	struct SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	SH_Data * data;
+	char * tag = strdup ("tag");
 
 	data = SH_Data_new (NULL);
 
-	fragment = SH_NodeFragment_new ("html", data, NULL);
+	_status_preinit (status);
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_raw_new (tag, data, &status);
 
-	/* without error */
-	copy = SH_NodeFragment_copy (((struct SH_NodeFragment *) fragment),
-				     NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+	ck_assert (succeed (&status));
+
+	ck_assert_ptr_eq (NULL, fragment->base.parent);
+	ck_assert_ptr_eq (fragment->tag, tag);
+
+	ck_assert_int_eq (0, fragment->attr_n);
+	ck_assert_int_eq (0, fragment->attr_s);
+
+	ck_assert_int_eq (0, fragment->child_n);
+	ck_assert_int_eq (0, fragment->child_s);
+
+	SH_NodeFragment_free (fragment);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_copy_no_status)
+{
+	struct SH_NodeFragment * fragment;
+	struct SH_NodeFragment * copy;
+	SH_Data * data;
+
+	data = SH_Data_new (NULL);
+
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_new ("html", data, NULL);
+
+	copy = (struct SH_NodeFragment *)
+	       SH_NodeFragment_copy (fragment, NULL);
 
 	ck_assert_ptr_ne (copy, NULL);
 	ck_assert_ptr_ne (fragment, copy);
-	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
-			  ((struct SH_NodeFragment *) copy)->tag);
-	ck_assert_int_eq (((struct SH_NodeFragment *) copy)->child_n, 0);
-	ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment)->childs,
-			  ((struct SH_NodeFragment *) copy)->childs);
+	ck_assert_ptr_eq (NULL, copy->base.parent);
+	ck_assert_str_eq (fragment->tag, copy->tag);
+	ck_assert_int_eq (0, copy->attr_n);
+	ck_assert_int_eq (0, copy->attr_s);
+	ck_assert_int_eq (0, copy->child_n);
+	ck_assert_int_eq (0, copy->child_s);
+	ck_assert_ptr_ne (NULL, copy->childs);
 
-	SH_Fragment_free (copy);
+	SH_NodeFragment_free (fragment);
+	SH_NodeFragment_free (copy);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_copy_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * fragment;
+	struct SH_NodeFragment * copy;
+	SH_Data * data;
+
+	data = SH_Data_new (NULL);
+
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_new ("html", data, NULL);
 
-	/* with error */
 	_status_preinit (status);
-	copy = SH_NodeFragment_copy (((struct SH_NodeFragment *) fragment),
-				     &status);
-	ck_assert_int_eq (status.status, SUCCESS);
+	copy = (struct SH_NodeFragment *)
+	       SH_NodeFragment_copy (fragment, &status);
+	ck_assert (succeed (&status));
 
 	ck_assert_ptr_ne (copy, NULL);
 	ck_assert_ptr_ne (fragment, copy);
-	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
-			  ((struct SH_NodeFragment *) copy)->tag);
-	ck_assert_int_eq (((struct SH_NodeFragment *) copy)->child_n, 0);
-	ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment)->childs,
-			  ((struct SH_NodeFragment *) copy)->childs);
+	ck_assert_ptr_eq (NULL, copy->base.parent);
+	ck_assert_str_eq (fragment->tag, copy->tag);
+	ck_assert_int_eq (0, copy->attr_n);
+	ck_assert_int_eq (0, copy->attr_s);
+	ck_assert_int_eq (0, copy->child_n);
+	ck_assert_int_eq (0, copy->child_s);
+	ck_assert_ptr_ne (NULL, copy->childs);
 
-	SH_Fragment_free (fragment);
-	SH_Fragment_free (copy);
+	SH_NodeFragment_free (fragment);
+	SH_NodeFragment_free (copy);
 
 	SH_Data_free (data);
 }
 END_TEST
 
 static void
-check_childs (struct SH_NodeFragment * fragment, struct SH_NodeFragment * copy)
+check_childs (struct SH_NodeFragment * fragment,
+              struct SH_NodeFragment * copy)
 {
 	size_t index;
 
+	ck_assert_str_eq (fragment->tag, copy->tag);
+	ck_assert_int_eq (fragment->attr_n, copy->attr_n);
+	ck_assert_int_eq (fragment->attr_s, copy->attr_s);
+	ck_assert_int_eq (fragment->child_n, copy->child_n);
+	ck_assert_int_eq (fragment->child_s, copy->child_s);
+	ck_assert_ptr_ne (fragment->childs, copy->childs);
+
 	for (index = 0; index < copy->child_n; index++)
 	{
-		ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment->childs[index]),
-				  ((struct SH_NodeFragment *) copy->childs[index]));
-		ck_assert_str_eq (((struct SH_NodeFragment *) fragment->childs[index])->tag,
-				  ((struct SH_NodeFragment *) copy->childs[index])->tag);
-		ck_assert_int_eq (((struct SH_NodeFragment *) fragment->childs[index])->child_n,
-				  ((struct SH_NodeFragment *) copy->childs[index])->child_n);
-
-		check_childs (((struct SH_NodeFragment *) fragment->childs[index]),
-			      ((struct SH_NodeFragment *) copy->childs[index]));
+		ck_assert_ptr_ne (fragment->childs[index],
+				  copy->childs[index]);
+		ck_assert_ptr_eq (copy, get_parent (copy->childs[index]));
+
+		check_childs (((struct SH_NodeFragment *)
+		              fragment->childs[index]),
+			      ((struct SH_NodeFragment *)
+			      copy->childs[index]));
 	}
 
 	return;
 }
 
-START_TEST(test_node_fragment_deepcopy)
+START_TEST(test_node_fragment_deepcopy_no_status)
 {
-	struct SH_Status status;
-	struct SH_Fragment * fragment;
+	struct SH_NodeFragment * fragment;
+	struct SH_NodeFragment * copy;
 	struct SH_Fragment * child1;
 	struct SH_Fragment * child2;
-	struct SH_Fragment * copy;
-	struct SH_Data * data;
+	SH_Data * data;
 
 	data = SH_Data_new (NULL);
 
-	fragment = SH_NodeFragment_new ("html", data, NULL);
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_new ("html", data, NULL);
 
 	child1 = SH_NodeFragment_new ("head", data, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) fragment),
-				      child1, NULL);
+	SH_NodeFragment_append_child (fragment, child1, NULL);
 
 	child2 = SH_NodeFragment_new ("title", data, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
-				      child2, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
 
 
 	child1 = SH_NodeFragment_new ("body", data, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) fragment),
-				      child1, NULL);
+	SH_NodeFragment_append_child (fragment, child1, NULL);
 
 	child2 = SH_NodeFragment_new ("header", data, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
-				      child2, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
 
 	child2 = SH_NodeFragment_new ("main", data, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
-				      child2, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
 
 	child2 = SH_NodeFragment_new ("footer", data, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
-				      child2, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
 
 
-	/* without error */
-	copy = SH_Fragment_copy (fragment, NULL);
+	copy = (struct SH_NodeFragment *)
+	       SH_NodeFragment_deepcopy (fragment, NULL);
 
-	ck_assert_ptr_ne (copy, NULL);
+	ck_assert_ptr_ne (NULL, copy);
 	ck_assert_ptr_ne (fragment, copy);
-	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
-			  ((struct SH_NodeFragment *) copy)->tag);
-	ck_assert_int_eq (((struct SH_NodeFragment *) fragment)->child_n,
-			  ((struct SH_NodeFragment *) copy)->child_n);
-	ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment)->childs,
-			  ((struct SH_NodeFragment *) copy)->childs);
+	ck_assert_ptr_eq (NULL, copy->base.parent);
 
-	check_childs (((struct SH_NodeFragment *) fragment),
-		      ((struct SH_NodeFragment *) copy));
+	check_childs (fragment, copy);
+
+	SH_NodeFragment_free (fragment);
+	SH_NodeFragment_free (copy);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_deepcopy_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * fragment;
+	struct SH_NodeFragment * copy;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	SH_Data * data;
+
+	data = SH_Data_new (NULL);
+
+	fragment = (struct SH_NodeFragment *)
+	           SH_NodeFragment_new ("html", data, NULL);
+
+	child1 = SH_NodeFragment_new ("head", data, NULL);
+	SH_NodeFragment_append_child (fragment, child1, NULL);
+
+	child2 = SH_NodeFragment_new ("title", data, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
+
+
+	child1 = SH_NodeFragment_new ("body", data, NULL);
+	SH_NodeFragment_append_child (fragment, child1, NULL);
+
+	child2 = SH_NodeFragment_new ("header", data, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
+
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
+
+	child2 = SH_NodeFragment_new ("footer", data, NULL);
+	SH_NodeFragment_append_child ((struct SH_NodeFragment *)child1,
+	                              child2, NULL);
 
-	SH_Fragment_free (copy);
 
-	/* with error */
 	_status_preinit (status);
-	copy = SH_Fragment_copy (fragment, &status);
-	ck_assert_int_eq (status.status, SUCCESS);
+	copy = (struct SH_NodeFragment *)
+	       SH_NodeFragment_deepcopy (fragment, &status);
+	ck_assert (succeed (&status));
 
-	ck_assert_ptr_ne (copy, NULL);
+	ck_assert_ptr_ne (NULL, copy);
 	ck_assert_ptr_ne (fragment, copy);
-	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
-			  ((struct SH_NodeFragment *) copy)->tag);
-	ck_assert_int_eq (((struct SH_NodeFragment *) fragment)->child_n,
-			  ((struct SH_NodeFragment *) copy)->child_n);
-	ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment)->childs,
-			  ((struct SH_NodeFragment *) copy)->childs);
+	ck_assert_ptr_eq (NULL, copy->base.parent);
 
-	check_childs (((struct SH_NodeFragment *) fragment),
-		      ((struct SH_NodeFragment *) copy));
+	check_childs (fragment, copy);
 
-	SH_Fragment_free (fragment);
-	SH_Fragment_free (copy);
+	SH_NodeFragment_free (fragment);
+	SH_NodeFragment_free (copy);
 
 	SH_Data_free (data);
 }
 END_TEST
 
-START_TEST(test_node_fragment_tag)
+START_TEST(test_node_fragment_tag_no_status)
 {
-	struct SH_Status status;
 	struct SH_Fragment * fragment;
-	struct SH_Data * data;
+	SH_Data * data;
 	char * tag;
 	const char * tag1 = "html";
-	const char * tag2 = "body";
 
 	data = SH_Data_new (NULL);
 
 	/* no error */
 	fragment = SH_NodeFragment_new (tag1, data, NULL);
 
-	tag = SH_NodeFragment_get_tag (((struct SH_NodeFragment *) fragment),
-				       NULL);
+	tag = SH_NodeFragment_get_tag ((struct SH_NodeFragment *)
+	                               fragment,
+	                               NULL);
 	ck_assert_str_eq (tag, tag1);
 	free (tag);
 
 	SH_Fragment_free (fragment);
+	SH_Data_free (data);
+}
+END_TEST
 
-	/* error */
-	fragment = SH_NodeFragment_new (tag2, data, NULL);
+START_TEST(test_node_fragment_tag_with_status)
+{
+	struct SH_Status status;
+	struct SH_Fragment * fragment;
+	SH_Data * data;
+	char * tag;
+	const char * tag1 = "html";
+
+	data = SH_Data_new (NULL);
+
+	fragment = SH_NodeFragment_new (tag1, data, NULL);
 
 	_status_preinit (status);
-	tag = SH_NodeFragment_get_tag (((struct SH_NodeFragment *) fragment),
-				       &status);
-	ck_assert_str_eq (tag, tag2);
-	ck_assert_int_eq (status.status, SUCCESS);
+	tag = SH_NodeFragment_get_tag ((struct SH_NodeFragment *)
+	                               fragment,
+	                               &status);
+	ck_assert_str_eq (tag, tag1);
+	ck_assert (succeed (&status));
 	free (tag);
 
 	SH_Fragment_free (fragment);
@@ -246,178 +400,2375 @@ START_TEST(test_node_fragment_tag)
 }
 END_TEST
 
-START_TEST(test_node_fragment_child)
+START_TEST(test_node_fragment_tag_raw)
 {
-	struct SH_Status status;
-	struct SH_Fragment * parent;
-	struct SH_Fragment * child1;
-	struct SH_Fragment * child2;
-	struct SH_Data * data;
-	bool boolean;
+	struct SH_Fragment * fragment;
+	SH_Data * data;
+	char * tag;
+	const char * tag1 = "html";
 
 	data = SH_Data_new (NULL);
 
-	parent = SH_NodeFragment_new ("html", data, NULL);
-	child1 = SH_NodeFragment_new ("head", data, NULL);
-	child2 = SH_NodeFragment_new ("body", data, NULL);
-
-	/* no error */
-	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 0);
-
-	boolean = SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
-						child1, NULL);
-	ck_assert_int_eq (boolean, TRUE);
-	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n,
-			  1);
-	ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[0],
-			  child1);
-
-	/* with error */
-	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 1);
-
-	_status_preinit (status);
-	boolean = SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
-						child2, &status);
-	ck_assert_int_eq (boolean, TRUE);
-	ck_assert_int_eq (status.status, SUCCESS);
-	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n,
-			  2);
-	ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[1],
-			  child2);
+	fragment = SH_NodeFragment_new (tag1, data, NULL);
 
-	SH_Fragment_free (parent);
+	tag = SH_NodeFragment_raw_get_tag (((struct SH_NodeFragment *)
+	                                   fragment));
+	ck_assert_str_eq (tag, tag1);
 
+	SH_Fragment_free (fragment);
 	SH_Data_free (data);
 }
 END_TEST
 
-START_TEST(test_node_fragment_get_child)
+START_TEST(test_node_fragment_attr_alloc)
 {
-	struct SH_Status status;
-	struct SH_Fragment * parent;
-	struct SH_Fragment * child1;
-	const struct SH_Fragment * child2;
-	struct SH_Data * data;
+	#define alloc_size get_attr_alloc_size
+	ck_assert_int_eq (0, alloc_size (0));
+	ck_assert_int_eq (CHILD_CHUNK, alloc_size (1));
+	ck_assert_int_eq (CHILD_CHUNK, alloc_size (CHILD_CHUNK));
+	ck_assert_int_eq (2*CHILD_CHUNK, alloc_size (CHILD_CHUNK+1));
+	ck_assert_int_eq (SIZE_MAX, alloc_size (SIZE_MAX));
+	for (size_t i = 0; i < CHILD_CHUNK; i++)
+	{
+		ck_assert_int_le (SIZE_MAX-i, alloc_size (SIZE_MAX-i));
+	}
+	#undef alloc_size
+}
+END_TEST
 
-	data = SH_Data_new (NULL);
+START_TEST(test_node_fragment_attr_get_no_status)
+{
+	SH_Attr * attr1;
+	const SH_Attr * attr2;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
 
-	parent = SH_NodeFragment_new ("html", data, NULL);
-	child1 = SH_NodeFragment_new ("body", data, NULL);
+	/* setup */
+	attr1 = SH_Attr_new ("name", "value", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
 
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
-				      child1, NULL);
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
 
-	/* without error */
-	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
-					    0, NULL);
-	ck_assert_ptr_eq (child1, child2);
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
 
-	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
-					    1, NULL);
-	ck_assert_ptr_eq (NULL, child2);
+	result = SH_NodeFragment_append_attr_copy (fragment, attr1, NULL);
+	ck_assert_int_eq (TRUE, result);
 
-	/* with error */
-	_status_preinit (status);
-	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
-					    0, &status);
-	ck_assert_ptr_eq (child1, child2);
-	ck_assert_int_eq (status.status, SUCCESS);
+	/* test - success */
+	attr2 = SH_NodeFragment_get_attr (fragment, 0, NULL);
+	ck_assert_ptr_ne (NULL, attr2);
 
-	_status_preinit (status);
-	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
-					    1, &status);
-	ck_assert_ptr_eq (NULL, child2);
-	ck_assert_int_eq (status.status, E_VALUE);
+	ck_assert (Attr_is_equal (attr1, attr2));
 
-	SH_Fragment_free (parent);
+	/* test - fail */
+	attr2 = SH_NodeFragment_get_attr (fragment, 1, NULL);
+	ck_assert_ptr_eq (NULL, attr2);
 
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
 	SH_Data_free (data);
+	SH_Attr_free (attr1);
 }
 END_TEST
 
-START_TEST(test_node_fragment_is_child)
+START_TEST(test_node_fragment_attr_get_with_status)
 {
-	struct SH_Fragment * parent;
-	struct SH_Fragment * child1;
-	struct SH_Fragment * child2;
-	struct SH_Data * data;
-	bool boolean;
+	struct SH_Status status;
+	SH_Attr * attr1;
+	const SH_Attr * attr2;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
 
-	data = SH_Data_new (NULL);
+	/* setup */
+	attr1 = SH_Attr_new ("name", "value", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
 
-	parent = SH_NodeFragment_new ("html", data, NULL);
-	child1 = SH_NodeFragment_new ("head", data, NULL);
-	child2 = SH_NodeFragment_new ("title", data, NULL);
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
 
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
-				      child1, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
-				      child2, NULL);
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
 
-	boolean = SH_NodeFragment_is_child (((struct SH_NodeFragment *) parent),
-					    child1);
-	ck_assert_int_eq (boolean, TRUE);
+	result = SH_NodeFragment_append_attr_copy (fragment, attr1, NULL);
+	ck_assert_int_eq (TRUE, result);
 
-	boolean = SH_NodeFragment_is_child (((struct SH_NodeFragment *) parent),
-					    child2);
-	ck_assert_int_eq (boolean, FALSE);
+	/* test - success */
+	_status_preinit (status);
+	attr2 = SH_NodeFragment_get_attr (fragment, 0, &status);
+	ck_assert_ptr_ne (NULL, attr2);
+	ck_assert_int_eq (SUCCESS, status.status);
 
-	boolean = SH_NodeFragment_is_child (((struct SH_NodeFragment *) child1),
-					    child2);
-	ck_assert_int_eq (boolean, TRUE);
+	ck_assert (Attr_is_equal (attr1, attr2));
 
-	SH_Fragment_free (parent);
+	/* test - fail */
+	_status_preinit (status);
+	attr2 = SH_NodeFragment_get_attr (fragment, 1, &status);
+	ck_assert_ptr_eq (NULL, attr2);
+	ck_assert_int_eq (E_VALUE, status.status);
 
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
 	SH_Data_free (data);
+	SH_Attr_free (attr1);
 }
 END_TEST
 
-START_TEST(test_node_fragment_is_descendant)
+START_TEST(test_node_fragment_attr_insert_no_status)
 {
-	struct SH_Fragment * parent;
-	struct SH_Fragment * child1;
-	struct SH_Fragment * child2;
-	struct SH_Fragment * child3;
-	struct SH_Data * data;
-	bool boolean;
+	char * name;
+	char * value;
+	SH_Attr * attr;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
 
 	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
 
-	parent = SH_NodeFragment_new ("html", data, NULL);
-	child1 = SH_NodeFragment_new ("head", data, NULL);
-	child2 = SH_NodeFragment_new ("body", data, NULL);
-	child3 = SH_NodeFragment_new ("title", data, NULL);
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
 
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
-				       child1, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
-				       child2, NULL);
-	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
-				       child3, NULL);
+	/* test insert - success */
+	attr = SH_Attr_copy (attr1, NULL);
+	ck_assert_ptr_ne (NULL, attr);
 
-	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) parent),
-						  child1);
-	ck_assert_int_eq (boolean, TRUE);
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
 
-	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) parent),
+	result = insert_attr (fragment, attr, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (1, fragment->attr_n);
+	ck_assert_int_le (1, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[0].value);
+
+	/* test insert before - success */
+	attr = SH_Attr_copy (attr2, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = insert_attr (fragment, attr, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (2, fragment->attr_n);
+	ck_assert_int_le (2, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	/* test insert after - success */
+	attr = SH_Attr_copy (attr3, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = insert_attr (fragment, attr, 2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert_int_le (3, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (value, fragment->attrs[2].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	ck_assert_str_eq (attr3->name, fragment->attrs[2].name);
+	ck_assert_str_eq (attr3->value, fragment->attrs[2].value);
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_with_status)
+{
+	struct SH_Status status;
+	char * name;
+	char * value;
+	SH_Attr * attr;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test insert - success */
+	attr = SH_Attr_copy (attr1, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = insert_attr (fragment, attr, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (1, fragment->attr_n);
+	ck_assert_int_le (1, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[0].value);
+
+	/* test insert before - success */
+	attr = SH_Attr_copy (attr2, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = insert_attr (fragment, attr, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (2, fragment->attr_n);
+	ck_assert_int_le (2, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	/* test insert after - success */
+	attr = SH_Attr_copy (attr3, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = insert_attr (fragment, attr, 2, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert_int_le (3, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (value, fragment->attrs[2].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	ck_assert_str_eq (attr3->name, fragment->attrs[2].name);
+	ck_assert_str_eq (attr3->value, fragment->attrs[2].value);
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_new_no_status)
+{
+	char * name;
+	char * value;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test insert - success */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	result = insert_attr_new (fragment, name, value, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (1, fragment->attr_n);
+	ck_assert_int_le (1, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (attr1->name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (attr1->value, fragment->attrs[0].value);
+
+	/* test insert before - success */
+	name = Attr_get_name (attr2);
+	value = Attr_get_value (attr2);
+
+	result = insert_attr_new (fragment, name, value, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (2, fragment->attr_n);
+	ck_assert_int_le (2, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_ptr_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_ptr_eq (attr1->value, fragment->attrs[1].value);
+
+	/* test insert after - success */
+	name = Attr_get_name (attr3);
+	value = Attr_get_value (attr3);
+
+	result = insert_attr_new (fragment, name, value, 2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert_int_le (3, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_ptr_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_ptr_eq (attr1->value, fragment->attrs[1].value);
+
+	ck_assert_ptr_eq (attr3->name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (attr3->value, fragment->attrs[2].value);
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	free (attr1);
+	free (attr2);
+	free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_new_with_status)
+{
+	struct SH_Status status;
+	char * name;
+	char * value;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test insert - success */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	_status_preinit (status);
+	result = insert_attr_new (fragment, name, value, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (1, fragment->attr_n);
+	ck_assert_int_le (1, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (attr1->name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (attr1->value, fragment->attrs[0].value);
+
+	/* test insert before - success */
+	name = Attr_get_name (attr2);
+	value = Attr_get_value (attr2);
+
+	_status_preinit (status);
+	result = insert_attr_new (fragment, name, value, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (2, fragment->attr_n);
+	ck_assert_int_le (2, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_ptr_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_ptr_eq (attr1->value, fragment->attrs[1].value);
+
+	/* test insert after - success */
+	name = Attr_get_name (attr3);
+	value = Attr_get_value (attr3);
+
+	_status_preinit (status);
+	result = insert_attr_new (fragment, name, value, 2, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert_int_le (3, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_ptr_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_ptr_eq (attr1->value, fragment->attrs[1].value);
+
+	ck_assert_ptr_eq (attr3->name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (attr3->value, fragment->attrs[2].value);
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	free (attr1);
+	free (attr2);
+	free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_copy_no_status)
+{
+	char * name;
+	char * value;
+	SH_Attr * attr;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test insert - success */
+	attr = SH_Attr_copy (attr1, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = insert_attr_copy (fragment, attr, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (1, fragment->attr_n);
+	ck_assert_int_le (1, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[0].value);
+
+	/* test insert before - success */
+	attr = SH_Attr_copy (attr2, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = insert_attr_copy (fragment, attr, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (2, fragment->attr_n);
+	ck_assert_int_le (2, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	/* test insert after - success */
+	attr = SH_Attr_copy (attr3, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = insert_attr_copy (fragment, attr, 2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert_int_le (3, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_ne (name, fragment->attrs[2].name);
+	ck_assert_ptr_ne (value, fragment->attrs[2].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	ck_assert_str_eq (attr3->name, fragment->attrs[2].name);
+	ck_assert_str_eq (attr3->value, fragment->attrs[2].value);
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_copy_with_status)
+{
+	struct SH_Status status;
+	char * name;
+	char * value;
+	SH_Attr * attr;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	struct SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test insert - success */
+	attr = SH_Attr_copy (attr1, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = insert_attr_copy (fragment, attr, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (1, fragment->attr_n);
+	ck_assert_int_le (1, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[0].value);
+
+	/* test insert before - success */
+	attr = SH_Attr_copy (attr2, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = insert_attr_copy (fragment, attr, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (2, fragment->attr_n);
+	ck_assert_int_le (2, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	/* test insert after - success */
+	attr = SH_Attr_copy (attr3, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = insert_attr_copy (fragment, attr, 2, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert_int_le (3, fragment->attr_s);
+	ck_assert_int_eq (ATTR_CHUNK, fragment->attr_s);
+
+	ck_assert_ptr_ne (name, fragment->attrs[2].name);
+	ck_assert_ptr_ne (value, fragment->attrs[2].value);
+
+	ck_assert_str_eq (attr2->name, fragment->attrs[0].name);
+	ck_assert_str_eq (attr2->value, fragment->attrs[0].value);
+
+	ck_assert_str_eq (attr1->name, fragment->attrs[1].name);
+	ck_assert_str_eq (attr1->value, fragment->attrs[1].value);
+
+	ck_assert_str_eq (attr3->name, fragment->attrs[2].name);
+	ck_assert_str_eq (attr3->value, fragment->attrs[2].value);
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_insert_no_status)
+{
+	char * name;
+	char * value;
+	SH_Attr * attr;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test - out of bounds */
+	result = SH_NodeFragment_insert_attr (fragment, attr1, 1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test */
+	attr = SH_Attr_copy (attr2, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = SH_NodeFragment_insert_attr (fragment, attr, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert before */
+	attr = SH_Attr_copy (attr1, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = SH_NodeFragment_prepend_attr (fragment, attr, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert after */
+	attr = SH_Attr_copy (attr3, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	result = SH_NodeFragment_append_attr (fragment, attr, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_eq (name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (value, fragment->attrs[2].value);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert (Attr_is_equal (attr1, &fragment->attrs[0]));
+	ck_assert (Attr_is_equal (attr2, &fragment->attrs[1]));
+	ck_assert (Attr_is_equal (attr3, &fragment->attrs[2]));
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_insert_with_status)
+{
+	struct SH_Status status;
+	char * name;
+	char * value;
+	SH_Attr * attr;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test - out of bounds */
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_attr (fragment, attr1, 1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	/* test */
+	attr = SH_Attr_copy (attr2, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_attr (fragment, attr, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert before */
+	attr = SH_Attr_copy (attr1, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_prepend_attr (fragment, attr, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert after */
+	attr = SH_Attr_copy (attr3, NULL);
+	ck_assert_ptr_ne (NULL, attr);
+
+	name = Attr_get_name (attr);
+	value = Attr_get_value (attr);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_append_attr (fragment, attr, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_eq (name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (value, fragment->attrs[2].value);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert (Attr_is_equal (attr1, &fragment->attrs[0]));
+	ck_assert (Attr_is_equal (attr2, &fragment->attrs[1]));
+	ck_assert (Attr_is_equal (attr3, &fragment->attrs[2]));
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_insert_new_no_status)
+{
+	char * name;
+	char * value;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test - out of bounds */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	result = SH_NodeFragment_insert_attr_new (fragment, name, value,
+	                                          1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test */
+	name = Attr_get_name (attr2);
+	value = Attr_get_value (attr2);
+
+	result = SH_NodeFragment_insert_attr_new (fragment, name, value,
+	                                          0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert before */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	result = SH_NodeFragment_prepend_attr_new (fragment, name, value,
+	                                           NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert after */
+	name = Attr_get_name (attr3);
+	value = Attr_get_value (attr3);
+
+	result = SH_NodeFragment_append_attr_new (fragment, name, value,
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_eq (name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (value, fragment->attrs[2].value);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert (Attr_is_equal (attr1, &fragment->attrs[0]));
+	ck_assert (Attr_is_equal (attr2, &fragment->attrs[1]));
+	ck_assert (Attr_is_equal (attr3, &fragment->attrs[2]));
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	free (attr1);
+	free (attr2);
+	free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_insert_new_with_status)
+{
+	struct SH_Status status;
+	char * name;
+	char * value;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test - out of bounds */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_attr_new (fragment, name, value,
+	                                          1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	/* test */
+	name = Attr_get_name (attr2);
+	value = Attr_get_value (attr2);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_attr_new (fragment, name, value,
+	                                          0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert before */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_prepend_attr_new (fragment, name, value,
+	                                           &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_eq (name, fragment->attrs[0].name);
+	ck_assert_ptr_eq (value, fragment->attrs[0].value);
+
+	/* test - insert after */
+	name = Attr_get_name (attr3);
+	value = Attr_get_value (attr3);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_append_attr_new (fragment, name, value,
+	                                          &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_eq (name, fragment->attrs[2].name);
+	ck_assert_ptr_eq (value, fragment->attrs[2].value);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert (Attr_is_equal (attr1, &fragment->attrs[0]));
+	ck_assert (Attr_is_equal (attr2, &fragment->attrs[1]));
+	ck_assert (Attr_is_equal (attr3, &fragment->attrs[2]));
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	free (attr1);
+	free (attr2);
+	free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_insert_copy_no_status)
+{
+	char * name;
+	char * value;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test - out of bounds */
+	result = SH_NodeFragment_insert_attr_copy (fragment, attr1, 1,
+	                                           NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test */
+	name = Attr_get_name (attr2);
+	value = Attr_get_value (attr2);
+
+	result = SH_NodeFragment_insert_attr_copy (fragment, attr2, 0,
+	                                           NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	/* test - insert before */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	result = SH_NodeFragment_prepend_attr_copy (fragment, attr1,
+	                                           NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	/* test - insert after */
+	name = Attr_get_name (attr3);
+	value = Attr_get_value (attr3);
+
+	result = SH_NodeFragment_append_attr_copy (fragment, attr3,
+	                                           NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_ptr_ne (name, fragment->attrs[2].name);
+	ck_assert_ptr_ne (value, fragment->attrs[2].value);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert (Attr_is_equal (attr1, &fragment->attrs[0]));
+	ck_assert (Attr_is_equal (attr2, &fragment->attrs[1]));
+	ck_assert (Attr_is_equal (attr3, &fragment->attrs[2]));
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_attr_insert_insert_copy_with_status)
+{
+	struct SH_Status status;
+	char * name;
+	char * value;
+	SH_Attr * attr1;
+	SH_Attr * attr2;
+	SH_Attr * attr3;
+	SH_Data * data;
+	SH_NodeFragment * fragment;
+	bool result;
+
+	/* setup */
+	attr1 = SH_Attr_new ("name1", "value1", NULL);
+	ck_assert_ptr_ne (NULL, attr1);
+
+	attr2 = SH_Attr_new ("name2", "value2", NULL);
+	ck_assert_ptr_ne (NULL, attr2);
+
+	attr3 = SH_Attr_new ("name3", "value3", NULL);
+	ck_assert_ptr_ne (NULL, attr3);
+
+	data = SH_Data_new (NULL);
+	ck_assert_ptr_ne (NULL, data);
+
+	fragment = (SH_NodeFragment *)SH_NodeFragment_new ("html", data,
+	                                                   NULL);
+	ck_assert_ptr_ne (NULL, fragment);
+
+	/* test - out of bounds */
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_attr_copy (fragment, attr1, 1,
+	                                           &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	/* test */
+	name = Attr_get_name (attr2);
+	value = Attr_get_value (attr2);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_attr_copy (fragment, attr2, 0,
+	                                           &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	/* test - insert before */
+	name = Attr_get_name (attr1);
+	value = Attr_get_value (attr1);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_prepend_attr_copy (fragment, attr1,
+	                                           &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_ne (name, fragment->attrs[0].name);
+	ck_assert_ptr_ne (value, fragment->attrs[0].value);
+
+	/* test - insert after */
+	name = Attr_get_name (attr3);
+	value = Attr_get_value (attr3);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_append_attr_copy (fragment, attr3,
+	                                           &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_ne (name, fragment->attrs[2].name);
+	ck_assert_ptr_ne (value, fragment->attrs[2].value);
+
+	ck_assert_int_eq (3, fragment->attr_n);
+	ck_assert (Attr_is_equal (attr1, &fragment->attrs[0]));
+	ck_assert (Attr_is_equal (attr2, &fragment->attrs[1]));
+	ck_assert (Attr_is_equal (attr3, &fragment->attrs[2]));
+
+	/* cleanup */
+	SH_NodeFragment_free (fragment);
+	SH_Data_free (data);
+	SH_Attr_free (attr1);
+	SH_Attr_free (attr2);
+	SH_Attr_free (attr3);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_alloc)
+{
+	#define alloc_size get_child_alloc_size
+	ck_assert_int_eq (0, alloc_size (0));
+	ck_assert_int_eq (CHILD_CHUNK, alloc_size (1));
+	ck_assert_int_eq (CHILD_CHUNK, alloc_size (CHILD_CHUNK));
+	ck_assert_int_eq (2*CHILD_CHUNK, alloc_size (CHILD_CHUNK+1));
+	ck_assert_int_eq (SIZE_MAX, alloc_size (SIZE_MAX));
+	for (size_t i = 0; i < CHILD_CHUNK; i++)
+	{
+		ck_assert_int_le (SIZE_MAX-i, alloc_size (SIZE_MAX-i));
+	}
+	#undef alloc_size
+}
+END_TEST
+
+START_TEST(test_node_fragment_child)
+{
+	struct SH_Status status;
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Data * data;
+	bool boolean;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child1 = SH_NodeFragment_new ("head", data, NULL);
+	child2 = SH_NodeFragment_new ("body", data, NULL);
+
+	/* no error */
+	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 0);
+
+	boolean = SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+						child1, NULL);
+	ck_assert_int_eq (boolean, TRUE);
+	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n,
+			  1);
+	ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[0],
+			  child1);
+
+	ck_assert_ptr_eq (parent, get_parent (child1));
+
+	/* with error */
+	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 1);
+
+	_status_preinit (status);
+	boolean = SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+						child2, &status);
+	ck_assert_int_eq (boolean, TRUE);
+	ck_assert_int_eq (status.status, SUCCESS);
+	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n,
+			  2);
+	ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[1],
+			  child2);
+
+	ck_assert_ptr_eq (parent, get_parent (child2));
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_get_child)
+{
+	struct SH_Status status;
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child1;
+	const struct SH_Fragment * child2;
+	struct SH_Data * data;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child1 = SH_NodeFragment_new ("body", data, NULL);
+
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+				      child1, NULL);
+
+	/* without error */
+	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
+					    0, NULL);
+	ck_assert_ptr_eq (child1, child2);
+
+	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
+					    1, NULL);
+	ck_assert_ptr_eq (NULL, child2);
+
+	/* with error */
+	_status_preinit (status);
+	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
+					    0, &status);
+	ck_assert_ptr_eq (child1, child2);
+	ck_assert_int_eq (status.status, SUCCESS);
+
+	_status_preinit (status);
+	child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent),
+					    1, &status);
+	ck_assert_ptr_eq (NULL, child2);
+	ck_assert_int_eq (status.status, E_VALUE);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_is_child)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Data * data;
+	bool boolean;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child1 = SH_NodeFragment_new ("head", data, NULL);
+	child2 = SH_NodeFragment_new ("title", data, NULL);
+
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+				      child1, NULL);
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
+				      child2, NULL);
+
+	boolean = SH_NodeFragment_is_child (((struct SH_NodeFragment *) parent),
+					    child1);
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_child (((struct SH_NodeFragment *) parent),
+					    child2);
+	ck_assert_int_eq (boolean, FALSE);
+
+	boolean = SH_NodeFragment_is_child (((struct SH_NodeFragment *) child1),
+					    child2);
+	ck_assert_int_eq (boolean, TRUE);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_is_descendant)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	struct SH_Data * data;
+	bool boolean;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child1 = SH_NodeFragment_new ("head", data, NULL);
+	child2 = SH_NodeFragment_new ("body", data, NULL);
+	child3 = SH_NodeFragment_new ("title", data, NULL);
+
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+				       child1, NULL);
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+				       child2, NULL);
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
+				       child3, NULL);
+
+	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) parent),
+						  child1);
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) parent),
+						  child2);
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) parent),
+						  child3);
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) child1),
 						  child2);
+	ck_assert_int_eq (boolean, FALSE);
+
+	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) child1),
+						  child3);
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) child2),
+						  child3);
+	ck_assert_int_eq (boolean, FALSE);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_is_parent)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Data * data;
+	bool boolean;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child1 = SH_NodeFragment_new ("head", data, NULL);
+	child2 = SH_NodeFragment_new ("title", data, NULL);
+
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent),
+				      child1, NULL);
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1),
+				      child2, NULL);
+
+	boolean = SH_NodeFragment_is_parent (child1,
+	                                     (struct SH_NodeFragment *)
+	                                     parent);
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_parent (child2,
+	                                     (struct SH_NodeFragment *)
+	                                     parent);
+	ck_assert_int_eq (boolean, FALSE);
+
+	boolean = SH_NodeFragment_is_parent (child2,
+	                                     (struct SH_NodeFragment *)
+	                                     child1);
+	ck_assert_int_eq (boolean, TRUE);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_is_ancestor)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	struct SH_Data * data;
+	bool boolean;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child1 = SH_NodeFragment_new ("head", data, NULL);
+	child2 = SH_NodeFragment_new ("body", data, NULL);
+	child3 = SH_NodeFragment_new ("title", data, NULL);
+
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *)parent),
+				       child1, NULL);
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *)parent),
+				       child2, NULL);
+	SH_NodeFragment_append_child (((struct SH_NodeFragment *)child1),
+				       child3, NULL);
+
+	boolean = SH_NodeFragment_is_ancestor (child1,
+	                                       ((struct SH_NodeFragment *)
+	                                       parent));
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_ancestor (child2,
+	                                       ((struct SH_NodeFragment *)
+	                                       parent));
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_ancestor (child3,
+	                                       ((struct SH_NodeFragment *)
+	                                       parent));
+	ck_assert_int_eq (boolean, TRUE);
+
+	boolean = SH_NodeFragment_is_ancestor (child2,
+	                                       ((struct SH_NodeFragment *)
+	                                       child1));
+	ck_assert_int_eq (boolean, FALSE);
+
+	boolean = SH_NodeFragment_is_ancestor (child3,
+	                                       ((struct SH_NodeFragment *)
+	                                       child1));
 	ck_assert_int_eq (boolean, TRUE);
 
-	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) parent),
-						  child3);
-	ck_assert_int_eq (boolean, TRUE);
+	boolean = SH_NodeFragment_is_ancestor (child3,
+	                                       ((struct SH_NodeFragment *)
+	                                       child2));
+	ck_assert_int_eq (boolean, FALSE);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_insert_no_status)
+{
+	SH_Data * data;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)
+	         SH_NodeFragment_new ("body", data, NULL);
+	child1 = SH_NodeFragment_new ("header", data, NULL);
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	child3 = SH_NodeFragment_new ("footer", data, NULL);
+
+	/* insert - success */
+	result = insert_child (parent, child1, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (1, parent->child_n);
+	ck_assert_int_le (1, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+	ck_assert_ptr_eq (parent, child1->parent);
+
+	/* reinsert - failing */
+	result = insert_child (parent, child1, 0, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* insert copy - success */
+	child = SH_Fragment_copy (child1, NULL);
+	result = insert_child (parent, child, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (2, parent->child_n);
+	ck_assert_int_le (2, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child, parent->childs[0]);
+	ck_assert_ptr_eq (child1, parent->childs[1]);
+	ck_assert_ptr_eq (parent, child->parent);
+	ck_assert_ptr_eq (parent, child1->parent);
+
+	/* insert parent into child - failing */
+	result = insert_child ((struct SH_NodeFragment *)child1,
+	                       (struct SH_Fragment *)parent,
+	                       0, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* insert inbetween */
+	result = insert_child (parent, child2, 1, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_int_le (3, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child, parent->childs[0]);
+	ck_assert_ptr_eq (child1, parent->childs[2]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (parent, child->parent);
+	ck_assert_ptr_eq (parent, child1->parent);
+	ck_assert_ptr_eq (parent, child2->parent);
+
+	/* insert after */
+	result = insert_child (parent, child3, 3, NULL);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (4, parent->child_n);
+	ck_assert_int_le (4, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child, parent->childs[0]);
+	ck_assert_ptr_eq (child1, parent->childs[2]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (child3, parent->childs[3]);
+	ck_assert_ptr_eq (parent, child->parent);
+	ck_assert_ptr_eq (parent, child1->parent);
+	ck_assert_ptr_eq (parent, child2->parent);
+	ck_assert_ptr_eq (parent, child3->parent);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_insert_with_status)
+{
+	struct SH_Status status;
+	SH_Data * data;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)
+	         SH_NodeFragment_new ("body", data, NULL);
+	child1 = SH_NodeFragment_new ("header", data, NULL);
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	child3 = SH_NodeFragment_new ("footer", data, NULL);
+
+	/* insert - success */
+	_status_preinit (status);
+	result = insert_child (parent, child1, 0, &status);
+	ck_assert (succeed (&status));
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (1, parent->child_n);
+	ck_assert_int_le (1, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+	ck_assert_ptr_eq (parent, child1->parent);
+
+	/* reinsert - failing */
+	_status_preinit (status);
+	result = insert_child (parent, child1, 0, &status);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_STATE, status.status);
+
+	/* insert copy - success */
+	child = SH_Fragment_copy (child1, NULL);
+	_status_preinit (status);
+	result = insert_child (parent, child, 0, &status);
+	ck_assert (succeed (&status));
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (2, parent->child_n);
+	ck_assert_int_le (2, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child, parent->childs[0]);
+	ck_assert_ptr_eq (child1, parent->childs[1]);
+	ck_assert_ptr_eq (parent, child->parent);
+	ck_assert_ptr_eq (parent, child1->parent);
+
+	/* insert parent into child - failing */
+	_status_preinit (status);
+	result = insert_child ((struct SH_NodeFragment *)child1,
+	                       (struct SH_Fragment *)parent,
+	                       0, &status);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_STATE, status.status);
+
+	/* insert inbetween */
+	_status_preinit (status);
+	result = insert_child (parent, child2, 1, &status);
+	ck_assert (succeed (&status));
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_int_le (3, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child, parent->childs[0]);
+	ck_assert_ptr_eq (child1, parent->childs[2]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (parent, child->parent);
+	ck_assert_ptr_eq (parent, child1->parent);
+	ck_assert_ptr_eq (parent, child2->parent);
+
+	/* insert after */
+	_status_preinit (status);
+	result = insert_child (parent, child3, 3, &status);
+	ck_assert (succeed (&status));
+	ck_assert_int_eq (TRUE, result);
+	ck_assert_int_eq (4, parent->child_n);
+	ck_assert_int_le (4, parent->child_s);
+	ck_assert_int_eq (CHILD_CHUNK, parent->child_s);
+	ck_assert_ptr_eq (child, parent->childs[0]);
+	ck_assert_ptr_eq (child1, parent->childs[2]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (child3, parent->childs[3]);
+	ck_assert_ptr_eq (parent, child->parent);
+	ck_assert_ptr_eq (parent, child1->parent);
+	ck_assert_ptr_eq (parent, child2->parent);
+	ck_assert_ptr_eq (parent, child3->parent);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_insert_insert_no_status)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("header", data, NULL);
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	child3 = SH_NodeFragment_new ("footer", data, NULL);
+
+	/* out of range - fail */
+	result = SH_NodeFragment_insert_child (parent, child1, 1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* insert - success */
+	result = SH_NodeFragment_insert_child (parent, child2, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* insert before - success */
+	result = SH_NodeFragment_prepend_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* insert after - success */
+	result = SH_NodeFragment_append_child (parent, child3, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (child3, parent->childs[2]);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_insert_insert_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("header", data, NULL);
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	child3 = SH_NodeFragment_new ("footer", data, NULL);
+
+	/* out of range - fail */
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child (parent, child1, 1,
+	                                       &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_VALUE, status.status);
+	ck_assert (failed (&status));
+
+	/* insert - success */
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child (parent, child2, 0,
+	                                       &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	/* insert before - success */
+	_status_preinit (status);
+	result = SH_NodeFragment_prepend_child (parent, child1,
+	                                        &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	/* insert after - success */
+	_status_preinit (status);
+	result = SH_NodeFragment_append_child (parent, child3,
+	                                       &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (child3, parent->childs[2]);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_insert_relative_no_status)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("header", data, NULL);
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	child3 = SH_NodeFragment_new ("footer", data, NULL);
+
+	/* test erroneous call */
+	result = SH_NodeFragment_insert_child_before (child2, child1,
+	                                              NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	result = SH_NodeFragment_insert_child_after (child2, child3,
+	                                             NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test bug check */
+	child2->parent = parent;
+
+	result = SH_NodeFragment_insert_child_before (child2, child1,
+	                                              NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	result = SH_NodeFragment_insert_child_after (child2, child3,
+	                                             NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	child2->parent = NULL;
+
+	/* test real */
+	result = SH_NodeFragment_insert_child (parent, child2, 0,
+	                                       NULL);
+	ck_assert_int_eq (TRUE, result);
 
-	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) child1),
-						  child2);
-	ck_assert_int_eq (boolean, FALSE);
+	result = SH_NodeFragment_insert_child_before (child2, child1,
+	                                              NULL);
+	ck_assert_int_eq (TRUE, result);
 
-	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) child1),
-						  child3);
-	ck_assert_int_eq (boolean, TRUE);
+	result = SH_NodeFragment_insert_child_after (child2, child3,
+	                                             NULL);
+	ck_assert_int_eq (TRUE, result);
 
-	boolean = SH_NodeFragment_is_descendant (((struct SH_NodeFragment *) child2),
-						  child3);
-	ck_assert_int_eq (boolean, FALSE);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (child3, parent->childs[2]);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_insert_relative_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("header", data, NULL);
+	child2 = SH_NodeFragment_new ("main", data, NULL);
+	child3 = SH_NodeFragment_new ("footer", data, NULL);
+
+	/* test erroneous call */
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child_before (child2, child1,
+	                                              &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_STATE, status.status);
+	ck_assert (failed (&status));
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child_after (child2, child3,
+	                                             &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_STATE, status.status);
+	ck_assert (failed (&status));
+
+	/* test bug check */
+	child2->parent = parent;
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child_before (child2, child1,
+	                                              &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_BUG, status.status);
+	ck_assert (failed (&status));
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child_after (child2, child3,
+	                                             &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_BUG, status.status);
+	ck_assert (failed (&status));
+
+	child2->parent = NULL;
+
+	/* test real */
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child (parent, child2, 0,
+	                                       &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child_before (child2, child1,
+	                                              &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	_status_preinit (status);
+	result = SH_NodeFragment_insert_child_after (child2, child3,
+	                                             &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+	ck_assert_ptr_eq (child2, parent->childs[1]);
+	ck_assert_ptr_eq (child3, parent->childs[2]);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_no_status)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	struct SH_Fragment * child4;
+	struct SH_Fragment * child5;
+	struct SH_Fragment * child6;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("p", data, NULL);
+	child2 = SH_NodeFragment_new ("p", data, NULL);
+	child3 = SH_NodeFragment_new ("p", data, NULL);
+	child4 = SH_NodeFragment_new ("p", data, NULL);
+	child5 = SH_NodeFragment_new ("p", data, NULL);
+	child6 = SH_NodeFragment_new ("p", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child3, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child4, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child5, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child6, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+
+	ck_assert_int_eq (10, parent->child_s);
+	ck_assert_int_eq (6, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child1);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child1);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (5, parent->child_n);
+	ck_assert_ptr_eq (child2, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child2);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child2);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (4, parent->child_n);
+	ck_assert_ptr_eq (child3, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child3);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child3);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child4, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child4);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child4);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (2, parent->child_n);
+	ck_assert_ptr_eq (child5, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child5);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child5);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (1, parent->child_n);
+	ck_assert_ptr_eq (child6, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child6);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child6);
+	ck_assert_int_eq (0, parent->child_s);
+	ck_assert_int_eq (0, parent->child_n);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	struct SH_Fragment * child4;
+	struct SH_Fragment * child5;
+	struct SH_Fragment * child6;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("p", data, NULL);
+	child2 = SH_NodeFragment_new ("p", data, NULL);
+	child3 = SH_NodeFragment_new ("p", data, NULL);
+	child4 = SH_NodeFragment_new ("p", data, NULL);
+	child5 = SH_NodeFragment_new ("p", data, NULL);
+	child6 = SH_NodeFragment_new ("p", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child3, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child4, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child5, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child6, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+
+	ck_assert_int_eq (10, parent->child_s);
+	ck_assert_int_eq (6, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child1);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child1);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (5, parent->child_n);
+	ck_assert_ptr_eq (child2, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child2);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child2);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (4, parent->child_n);
+	ck_assert_ptr_eq (child3, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child3);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child3);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child4, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child4);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child4);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (2, parent->child_n);
+	ck_assert_ptr_eq (child5, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child5);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child5);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (1, parent->child_n);
+	ck_assert_ptr_eq (child6, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child6);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child6);
+	ck_assert_int_eq (0, parent->child_s);
+	ck_assert_int_eq (0, parent->child_n);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_self_no_status)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test erroneous call */
+	result = SH_Fragment_remove (parent, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test real */
+	result = SH_Fragment_remove (child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	result = SH_Fragment_remove (child, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	SH_Fragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_self_with_status)
+{
+	struct SH_Status status;
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test erroneous call */
+	_status_preinit (status);
+	result = SH_Fragment_remove (parent, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_STATE, status.status);
+
+	/* test real */
+	_status_preinit (status);
+	result = SH_Fragment_remove (child, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	_status_preinit (status);
+	result = SH_Fragment_remove (child, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_BUG, status.status);
+
+	SH_Fragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_self_no_status)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	/* test erroneous call */
+	result = SH_Fragment_delete (parent, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	result = SH_Fragment_delete (child, NULL);
+	ck_assert_int_eq (FALSE, result);
+	child->parent = NULL;
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test real */
+	result = SH_Fragment_delete (child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_self_with_status)
+{
+	struct SH_Status status;
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	/* test erroneous call */
+	_status_preinit (status);
+	result = SH_Fragment_remove (parent, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_STATE, status.status);
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	_status_preinit (status);
+	result = SH_Fragment_delete (child, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_BUG, status.status);
+	child->parent = NULL;
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test real */
+	_status_preinit (status);
+	result = SH_Fragment_delete (child, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
 
 	SH_Fragment_free (parent);
 
@@ -425,6 +2776,204 @@ START_TEST(test_node_fragment_is_descendant)
 }
 END_TEST
 
+START_TEST(test_node_fragment_child_remove_remove_no_status)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_remove_child (parent, 1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	result = SH_NodeFragment_remove_child (parent, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_remove_child (parent, 1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_remove_child (parent, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_no_status)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_delete_child (parent, 1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	result = SH_NodeFragment_delete_child (parent, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_delete_child (parent, 1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_delete_child (parent, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_pop_no_status)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	child = SH_NodeFragment_pop_child (parent, 1, NULL);
+	ck_assert_ptr_eq (NULL, child);
+
+	child = SH_NodeFragment_pop_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child1);
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_pop_with_status)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	_status_preinit (status);
+	child = SH_NodeFragment_pop_child (parent, 1, &status);
+	ck_assert_ptr_eq (NULL, child);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	_status_preinit (status);
+	child = SH_NodeFragment_pop_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child1);
+	ck_assert (succeed (&status));
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
 START_TEST(test_node_fragment_html)
 {
 	struct SH_Status status;
@@ -448,6 +2997,7 @@ START_TEST(test_node_fragment_html)
 	string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL);
 	ck_assert_str_eq (string, "<html><body></body></html>");
 	free (string);
+	SH_Text_free (text);
 
 	text = SH_Fragment_to_html (fragment1, WRAP, 0, 1, INDENT_TEXT,
 				    NULL);
@@ -455,6 +3005,7 @@ START_TEST(test_node_fragment_html)
 	ck_assert_str_eq (string,
 			  "<html>\n\t<body>\n\t</body>\n</html>\n");
 	free (string);
+	SH_Text_free (text);
 
 	SH_Fragment_free (fragment1);
 
@@ -470,6 +3021,7 @@ START_TEST(test_node_fragment_html)
 	string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL);
 	ck_assert_str_eq (string, "<html><body></body></html>");
 	free (string);
+	SH_Text_free (text);
 	ck_assert_int_eq (status.status, SUCCESS);
 
 	_status_preinit (status);
@@ -479,6 +3031,7 @@ START_TEST(test_node_fragment_html)
 	ck_assert_str_eq (string,
 			  "<html>\n\t<body>\n\t</body>\n</html>\n");
 	free (string);
+	SH_Text_free (text);
 	ck_assert_int_eq (status.status, SUCCESS);
 
 	SH_Fragment_free (fragment1);
@@ -496,14 +3049,57 @@ Suite * fragment_suite (void)
 	/* Core test case */
 	tc_core = tcase_create ("Core");
 
-	tcase_add_test (tc_core, test_node_fragment);
-	tcase_add_test (tc_core, test_node_fragment_copy);
-	tcase_add_test (tc_core, test_node_fragment_deepcopy);
-	tcase_add_test (tc_core, test_node_fragment_tag);
+	tcase_add_test (tc_core, test_node_fragment_no_status);
+	tcase_add_test (tc_core, test_node_fragment_with_status);
+	tcase_add_test (tc_core, test_node_fragment_raw_no_status);
+	tcase_add_test (tc_core, test_node_fragment_raw_with_status);
+	tcase_add_test (tc_core, test_node_fragment_copy_no_status);
+	tcase_add_test (tc_core, test_node_fragment_copy_with_status);
+	tcase_add_test (tc_core, test_node_fragment_deepcopy_no_status);
+	tcase_add_test (tc_core, test_node_fragment_deepcopy_with_status);
+	tcase_add_test (tc_core, test_node_fragment_tag_no_status);
+	tcase_add_test (tc_core, test_node_fragment_tag_with_status);
+	tcase_add_test (tc_core, test_node_fragment_tag_raw);
+	tcase_add_test (tc_core, test_node_fragment_attr_alloc);
+	tcase_add_test (tc_core, test_node_fragment_attr_get_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_get_with_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_with_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_new_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_new_with_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_copy_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_copy_with_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_insert_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_insert_with_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_insert_new_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_insert_new_with_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_insert_copy_no_status);
+	tcase_add_test (tc_core, test_node_fragment_attr_insert_insert_copy_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_alloc);
 	tcase_add_test (tc_core, test_node_fragment_child);
 	tcase_add_test (tc_core, test_node_fragment_get_child);
 	tcase_add_test (tc_core, test_node_fragment_is_child);
 	tcase_add_test (tc_core, test_node_fragment_is_descendant);
+	tcase_add_test (tc_core, test_node_fragment_is_parent);
+	tcase_add_test (tc_core, test_node_fragment_is_ancestor);
+	tcase_add_test (tc_core, test_node_fragment_child_insert_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_insert_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_insert_insert_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_insert_insert_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_insert_relative_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_insert_relative_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_self_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_self_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_self_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_self_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_with_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_pop_no_status);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_pop_with_status);
 	tcase_add_test (tc_core, test_node_fragment_html);
 	suite_add_tcase (s, tc_core);