diff --git a/sefht.geany b/sefht.geany
index 1637e24d5eae078172045a5061cffc285408c516..fde96c7ad786a08014fd666f1ac603bfd3255c2d 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -28,13 +28,13 @@ long_line_behaviour=1
 long_line_column=72
 
 [files]
-current_page=5
+current_page=32
 FILE_NAME_0=139;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2FREADME;0;8
 FILE_NAME_1=134;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitignore;0;8
 FILE_NAME_2=1737;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8
 FILE_NAME_3=73;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2FMakefile.am;0;8
 FILE_NAME_4=19;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmain.c;0;8
-FILE_NAME_5=1131;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
+FILE_NAME_5=1091;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
 FILE_NAME_6=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.c;0;8
 FILE_NAME_7=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.h;0;8
 FILE_NAME_8=19;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8
@@ -58,30 +58,31 @@ FILE_NAME_25=8479;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp
 FILE_NAME_26=1083;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_segment.h;0;8
 FILE_NAME_27=900;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_segment_mark.c;0;8
 FILE_NAME_28=1867;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_mark_static.c;0;8
-FILE_NAME_29=977;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
+FILE_NAME_29=1005;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
 FILE_NAME_30=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8
-FILE_NAME_31=995;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_32=1148;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_33=1124;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag_data.h;0;8
-FILE_NAME_34=924;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
-FILE_NAME_35=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4
-FILE_NAME_36=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8
-FILE_NAME_37=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8
-FILE_NAME_38=2902;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8
-FILE_NAME_39=218;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Fno_test.sh.in;0;8
-FILE_NAME_40=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
-FILE_NAME_41=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
-FILE_NAME_42=8232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_fragment.c;0;8
-FILE_NAME_43=33;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
-FILE_NAME_44=5714;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_fragment.c;0;8
-FILE_NAME_45=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
-FILE_NAME_46=4221;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
-FILE_NAME_47=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_mark.c;0;8
-FILE_NAME_48=3101;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
-FILE_NAME_49=536;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
-FILE_NAME_50=201;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitlab-ci.yml;0;4
-FILE_NAME_51=71;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Fupload.sh.in;0;8
-FILE_NAME_52=806;Sh;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Frelease.sh.in;0;4
+FILE_NAME_31=1111;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_html.h;0;8
+FILE_NAME_32=5802;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_33=1148;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_34=1124;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag_data.h;0;8
+FILE_NAME_35=924;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
+FILE_NAME_36=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4
+FILE_NAME_37=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8
+FILE_NAME_38=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8
+FILE_NAME_39=2902;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8
+FILE_NAME_40=218;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Fno_test.sh.in;0;8
+FILE_NAME_41=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
+FILE_NAME_42=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
+FILE_NAME_43=8232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_fragment.c;0;8
+FILE_NAME_44=33;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
+FILE_NAME_45=5714;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_fragment.c;0;8
+FILE_NAME_46=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
+FILE_NAME_47=4221;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
+FILE_NAME_48=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_mark.c;0;8
+FILE_NAME_49=10556;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
+FILE_NAME_50=536;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
+FILE_NAME_51=201;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitlab-ci.yml;0;4
+FILE_NAME_52=71;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Fupload.sh.in;0;8
+FILE_NAME_53=806;Sh;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Frelease.sh.in;0;4
 
 [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 32a2ec7a198cd1989d517e34957ce0c189e220bb..f976962e7fba584222ded5cef0ccbcbdfdc7bc7b 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -26,6 +26,7 @@ EXTRA_DIST += sefht/text_data.h
 EXTRA_DIST += sefht/text_mark_static.c
 EXTRA_DIST += sefht/text_segment.c sefht/text_segment.h
 EXTRA_DIST += sefht/text_segment_mark.c
+EXTRA_DIST += sefht/validator_html.h
 EXTRA_DIST += sefht/validator_tag.c
 EXTRA_DIST += sefht/validator_tag_data.h
 
diff --git a/src/lib/sefht/validator.c b/src/lib/sefht/validator.c
index 956b7df6b238028b0d7fab322c67a6a2240d6916..4700bb2764a41ef2c08bcc1f0651cb8b1ab89468 100644
--- a/src/lib/sefht/validator.c
+++ b/src/lib/sefht/validator.c
@@ -68,6 +68,33 @@ SH_Validator_new (/*@null@*/ /*@out@*/ struct SH_Status * status)
 	return validator;
 }
 
+/*@null@*/
+/*@only@*/
+struct SH_Validator *
+SH_Validator_new_html5 (/*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	struct SH_Validator * validator;
+
+	validator = malloc (sizeof (struct SH_Validator));
+	if (NULL == validator)
+	{
+		set_status (status, E_ALLOC, 4, "malloc failed");
+		return NULL;
+	}
+
+	if (!init_tags_spec_html5 (validator, status))
+	{
+		free (validator);
+		return NULL;
+	}
+
+	set_success (status);
+	return validator;
+}
+
 /*@null@*/
 /*@only@*/
 struct SH_Validator *
diff --git a/src/lib/sefht/validator_html.h b/src/lib/sefht/validator_html.h
new file mode 100644
index 0000000000000000000000000000000000000000..6beae2e560e9a9343c25a9dd76256f6bbe7597bd
--- /dev/null
+++ b/src/lib/sefht/validator_html.h
@@ -0,0 +1,40 @@
+/*
+ * validator_html.h
+ *
+ * Copyright 2023 Jonathan Schöbel <jonathan@xn--schbel-yxa.info>
+ *
+ * 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_VALIDATOR_HTML_H
+#define SEFHT_VALIDATOR_HTML_H
+
+#if !defined (SEFHT_COMPILATION)
+#error "Only <sefht/sefht.h> can be included directly."
+#endif
+
+struct HTML_TAG_DEFINITION
+{
+	/*@observer@*/ const char * tag;
+};
+
+const struct HTML_TAG_DEFINITION HTML5[] = {
+};
+
+#endif /* SEFHT_VALIDATOR_HTML_H */
diff --git a/src/lib/sefht/validator_tag.c b/src/lib/sefht/validator_tag.c
index 41884417bc8fbefe929339a7bd1c3376679dcc3c..ab7f28e9110f18cac524a957354462f5ca942190 100644
--- a/src/lib/sefht/validator_tag.c
+++ b/src/lib/sefht/validator_tag.c
@@ -33,6 +33,8 @@
 
 #include "validator_tag.h"
 
+#include "validator_html.h"
+
 
 static inline
 void
@@ -44,6 +46,36 @@ init_tags (/*@special@*/ struct SH_Validator * validator)
 	/*@modifies validator->tag_n@*/
 	/*@modifies validator->last_tag@*/;
 
+static inline
+bool
+init_tags_from_spec (/*@special@*/ struct SH_Validator * validator,
+                     const struct HTML_TAG_DEFINITION * tags,
+                     const size_t size,
+                     /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines validator->tags,
+	           validator->tag_n,
+	           validator->last_tag@*/
+	/*@modifies validator->tags@*/
+	/*@modifies validator->tag_n@*/
+	/*@modifies validator->last_tag@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+static inline
+bool
+init_tags_spec_html5 (/*@special@*/ struct SH_Validator * validator,
+                      /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines validator->tags,
+	           validator->tag_n,
+	           validator->last_tag@*/
+	/*@modifies validator->tags@*/
+	/*@modifies validator->tag_n@*/
+	/*@modifies validator->last_tag@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
 static inline
 bool
 copy_tags (/*@special@*/ struct SH_Validator * copy,
@@ -142,6 +174,110 @@ init_tags (/*@special@*/ struct SH_Validator * validator)
 	return;
 }
 
+static inline
+bool
+init_tags_spec_html5 (/*@special@*/ struct SH_Validator * validator,
+                      /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines validator->tags,
+	           validator->tag_n,
+	           validator->last_tag@*/
+	/*@modifies validator->tags@*/
+	/*@modifies validator->tag_n@*/
+	/*@modifies validator->last_tag@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t size;
+	size = sizeof (HTML5) / sizeof (HTML5[0]);
+	return init_tags_from_spec (validator, HTML5, size, status);
+}
+
+static inline
+bool
+init_tags_from_spec (/*@special@*/ struct SH_Validator * validator,
+                     const struct HTML_TAG_DEFINITION * spec,
+                     const size_t size,
+                     /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines validator->tags,
+	           validator->tag_n,
+	           validator->last_tag@*/
+	/*@modifies validator->tags@*/
+	/*@modifies validator->tag_n@*/
+	/*@modifies validator->last_tag@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t index;
+	Tag id;
+
+	/* overflow detection */
+	if ((size > TAG_MAX - 1)
+	|| (size >= (SIZE_MAX / sizeof (struct tag_info))))
+	{
+		set_status (status, E_DOMAIN, 2,
+		            "maximum number of tags reached");
+		return FALSE;
+	}
+
+	validator->tags = malloc (sizeof (struct tag_info) * size);
+	if (NULL == validator->tags)
+	{
+		set_status (status, E_ALLOC, 3, "malloc failed");
+		return FALSE;
+	}
+
+	validator->tag_n = 0;
+
+	/* insertion sort */
+	#define tags validator->tags
+	#define tag_n validator->tag_n
+	for (index = 0; index < size; index++)
+	{
+		size_t position;
+
+		/* ignore duplicate tags */
+		if (!find_tag (validator, spec[index].tag, &position))
+		{
+			char * name;
+			size_t index2;
+
+			name = strdup (spec[index].tag);
+			if (NULL == name)
+			{
+				set_status (status, E_ALLOC, 3,
+				            "strdup failed");
+				free_tags (validator);
+				return FALSE;
+			}
+
+			/* only names are initialized */
+			for (index2 = tag_n; index2 > position; index2--)
+			{
+				tags[index2].name = tags[index2-1].name;
+			}
+
+			tags[position].name = name;
+			tag_n++;
+		}
+	}
+	#undef tag_n
+	#undef tags
+
+	/* initialize ids */
+	id = TAG_ERR;
+	for (index = 0; index < validator->tag_n; index++)
+	{
+		validator->tags[index].id = id = NEXT_TAG (id);
+	}
+
+	validator->last_tag = id;
+
+	set_success (status);
+	return TRUE;
+}
+
 static inline
 bool
 copy_tag (/*@special@*/ struct tag_info * copy,
diff --git a/tests/test_validator.c b/tests/test_validator.c
index b6b6b493983fd4771765b2a8cfb1d3a399034ae0..3a04cedd4004a5dbd34b4c44cbd2204fa5dcf007 100644
--- a/tests/test_validator.c
+++ b/tests/test_validator.c
@@ -37,6 +37,16 @@
 #include "macro.h"
 #include "status.h"
 
+/* override HTML spec */
+#include "validator_html.h"
+const struct HTML_TAG_DEFINITION HTML_[] = {
+	{"html"},
+	{"aside"},
+	{"html"},
+	{"body"}
+};
+#define HTML5 HTML_
+
 /* C file is needed, because we want to override SIZE_MAX */
 #include "validator.c"
 
@@ -72,6 +82,67 @@ START_TEST(test_validator_with_status)
 }
 END_TEST
 
+START_TEST(test_validator_spec_no_status)
+{
+	struct SH_Validator * validator;
+
+	/* test */
+	validator = SH_Validator_new_html5 (NULL);
+	ck_assert_ptr_ne (NULL, validator);
+
+	ck_assert_ptr_ne (NULL, validator->tags);
+	ck_assert_int_eq (3, validator->tag_n);
+	ck_assert_int_eq (3, validator->last_tag);
+
+	ck_assert_int_eq (1, validator->tags[0].id);
+	ck_assert_ptr_ne (HTML_[1].tag, validator->tags[0].name);
+	ck_assert_str_eq (HTML_[1].tag, validator->tags[0].name);
+
+	ck_assert_int_eq (2, validator->tags[1].id);
+	ck_assert_ptr_ne (HTML_[3].tag, validator->tags[1].name);
+	ck_assert_str_eq (HTML_[3].tag, validator->tags[1].name);
+
+	ck_assert_int_eq (3, validator->tags[2].id);
+	ck_assert_ptr_ne (HTML_[0].tag, validator->tags[2].name);
+	ck_assert_str_eq (HTML_[0].tag, validator->tags[2].name);
+
+	/* cleanup */
+	SH_Validator_free (validator);
+}
+END_TEST
+
+START_TEST(test_validator_spec_with_status)
+{
+	struct SH_Status status;
+	struct SH_Validator * validator;
+
+	/* test */
+	_status_preinit (status);
+	validator = SH_Validator_new_html5 (&status);
+	ck_assert_ptr_ne (NULL, validator);
+	ck_assert_int_eq (SUCCESS, status.status);
+
+	ck_assert_ptr_ne (NULL, validator->tags);
+	ck_assert_int_eq (3, validator->tag_n);
+	ck_assert_int_eq (3, validator->last_tag);
+
+	ck_assert_int_eq (1, validator->tags[0].id);
+	ck_assert_ptr_ne (HTML_[1].tag, validator->tags[0].name);
+	ck_assert_str_eq (HTML_[1].tag, validator->tags[0].name);
+
+	ck_assert_int_eq (2, validator->tags[1].id);
+	ck_assert_ptr_ne (HTML_[3].tag, validator->tags[1].name);
+	ck_assert_str_eq (HTML_[3].tag, validator->tags[1].name);
+
+	ck_assert_int_eq (3, validator->tags[2].id);
+	ck_assert_ptr_ne (HTML_[0].tag, validator->tags[2].name);
+	ck_assert_str_eq (HTML_[0].tag, validator->tags[2].name);
+
+	/* cleanup */
+	SH_Validator_free (validator);
+}
+END_TEST
+
 START_TEST(test_validator_tag_register_no_status)
 {
 	struct SH_Validator * validator;
@@ -322,6 +393,8 @@ Suite * validator_suite (void)
 
 	tcase_add_test (tc_core, test_validator_no_status);
 	tcase_add_test (tc_core, test_validator_with_status);
+	tcase_add_test (tc_core, test_validator_spec_no_status);
+	tcase_add_test (tc_core, test_validator_spec_with_status);
 	tcase_add_test (tc_core, test_validator_tag_register_no_status);
 	tcase_add_test (tc_core, test_validator_tag_register_with_status);
 	tcase_add_test (tc_core, test_validator_tag_check);