summaryrefslogtreecommitdiff
path: root/src/core/element.c
blob: 1b351ce3a2b24b55569ceebca18dafd4cb27b438 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
/*
 * This file is part of libdom.
 * Licensed under the MIT License,
 *                http://www.opensource.org/licenses/mit-license.php
 * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
 */

#include <stdio.h>

#include <dom/core/attr.h>
#include <dom/core/element.h>
#include <dom/core/string.h>

#include "core/attr.h"
#include "core/document.h"
#include "core/element.h"
#include "core/node.h"
#include "utils/utils.h"

/**
 * DOM element node
 */
struct dom_element {
	struct dom_node base;		/**< Base node */

	struct dom_attr *attributes;	/**< Element attributes */

	struct dom_type_info *schema_type_info;	/**< Type information */
};

/**
 * Create an element node
 *
 * \param doc     The owning document
 * \param name    The name of the node to create
 * \param result  Pointer to location to receive created element
 * \return DOM_NO_ERR                on success,
 *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
 *         DOM_NO_MEM_ERR            on memory exhaustion.
 *
 * ::doc and ::name will have their reference counts increased.
 *
 * The returned element will already be referenced.
 */
dom_exception dom_element_create(struct dom_document *doc,
		struct dom_string *name, struct dom_element **result)
{
	struct dom_element *el;
	dom_exception err;

	/** \todo Sanity check the tag name */

	/* Allocate the element */
	el = dom_document_alloc(doc, NULL, sizeof(struct dom_element));
	if (el == NULL)
		return DOM_NO_MEM_ERR;

	/* Initialise the base class */
	err = dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE,
			name, NULL);
	if (err != DOM_NO_ERR) {
		dom_document_alloc(doc, el, 0);
		return err;
	}

	/* Perform our type-specific initialisation */
	el->attributes = NULL;
	el->schema_type_info = NULL;

	*result = el;

	return DOM_NO_ERR;
}

/**
 * Destroy an element
 *
 * \param doc      The owning document
 * \param element  The element to destroy
 *
 * The contents of ::element will be destroyed and ::element will be freed.
 */
void dom_element_destroy(struct dom_document *doc,
		struct dom_element *element)
{
	struct dom_node *c, *d;

	/* Destroy children of this node */
	for (c = element->base.first_child; c != NULL; c = d) {
		d = c->next;

		/* Detach child */
		c->parent = NULL;

		if (c->refcnt > 0) {
			/* Something is using this child */

			/** \todo add to list of nodes pending deletion */

			continue;
		}

		/* Detach from sibling list */
		c->previous = NULL;
		c->next = NULL;

		dom_node_destroy(c);
	}

	/* Destroy attributes attached to this node */
	for (c = (struct dom_node *) element->attributes;
			c != NULL; c = d) {
		d = c->next;

		/* Detach child */
		c->parent = NULL;

		if (c->refcnt > 0) {
			/* Something is using this attribute */

			/** \todo add to list of nodes pending deletion */

			continue;
		}

		/* Detach from sibling list */
		c->previous = NULL;
		c->next = NULL;

		dom_node_destroy(c);
	}

	if (element->schema_type_info != NULL) {
		/** \todo destroy schema type info */
	}

	/* Finalise base class */
	dom_node_finalise(doc, &element->base);

	/* Free the element */
	dom_document_alloc(doc, element, 0);
}

/**
 * Retrieve an element's tag name
 *
 * \param element  The element to retrieve the name from
 * \param name     Pointer to location to receive name
 * \return DOM_NO_ERR      on success,
 *         DOM_NO_MEM_ERR  on memory exhaustion.
 *
 * The returned string will have its reference count increased. It is
 * the responsibility of the caller to unref the string once it has
 * finished with it.
 */
dom_exception dom_element_get_tag_name(struct dom_element *element,
		struct dom_string **name)
{
	struct dom_node *e = (struct dom_node *) element;
	struct dom_string *tag_name;

	if (e->localname != NULL) {
		/* Has a localname, so build a qname string */
		size_t local_len = 0, prefix_len = 0;
		const uint8_t *local = NULL, *prefix = NULL;
		dom_exception err;

		if (e->prefix != NULL)
			dom_string_get_data(e->prefix, &prefix, &prefix_len);

		dom_string_get_data(e->localname, &local, &local_len);

		uint8_t qname[prefix_len + 1 /* : */ + local_len + 1 /* \0 */];

		sprintf((char *) qname, "%s:%s", 
				prefix ? (const char *) prefix : "", 
				(const char *) local);

		err = dom_string_create_from_ptr(e->owner, qname, 
				prefix_len + 1 + local_len, &tag_name);
		if (err != DOM_NO_ERR)
			return err;

		/* tag_name is referenced for us */
	} else {
		tag_name = e->name;

		dom_string_ref(tag_name);
	}

	*name = tag_name;

	return DOM_NO_ERR;
}

/**
 * Retrieve an attribute from an element by name
 *
 * \param element  The element to retrieve attribute from
 * \param name     The attribute's name
 * \param value    Pointer to location to receive attribute's value
 * \return DOM_NO_ERR.
 *
 * The returned string will have its reference count increased. It is
 * the responsibility of the caller to unref the string once it has
 * finished with it.
 */
dom_exception dom_element_get_attribute(struct dom_element *element,
		struct dom_string *name, struct dom_string **value)
{
	struct dom_node *a = (struct dom_node *) element->attributes;

	/* Search attributes, looking for name */
	for (; a != NULL; a = a->next) {
		if (dom_string_cmp(a->name, name) == 0)
			break;
	}

	/* Fill in value */
	if (a == NULL) {
		*value = NULL;
	} else {
		dom_attr_get_value(((struct dom_attr *) a), value);
	}

	return DOM_NO_ERR;
}

/**
 * Set an attribute on an element by name
 *
 * \param element  The element to set attribute on
 * \param name     The attribute's name
 * \param value    The attribute's value
 * \return DOM_NO_ERR                      on success,
 *         DOM_INVALID_CHARACTER_ERR       if ::name is invalid,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
 */
dom_exception dom_element_set_attribute(struct dom_element *element,
		struct dom_string *name, struct dom_string *value)
{
	struct dom_node *e = (struct dom_node *) element;
	struct dom_node *a = (struct dom_node *) element->attributes;

	/** \todo validate name */

	/* Ensure element can be written to */
	if (_dom_node_readonly(e))
		return DOM_NO_MODIFICATION_ALLOWED_ERR;

	/* Search for existing attribute with same name */
	for (; a != NULL; a = a->next) {
		if (dom_string_cmp(a->name, name) == 0)
			break;
	}

	if (a != NULL) {
		/* Found an existing attribute, so replace its value */
		dom_exception err;

		err = dom_attr_set_value((struct dom_attr *) a, value);
		if (err != DOM_NO_ERR)
			return err;
	} else {
		/* No existing attribute, so create one */
		dom_exception err;
		struct dom_attr *attr;

		err = dom_attr_create(e->owner, name, &attr);
		if (err != DOM_NO_ERR)
			return err;

		/* Set its value */
		err = dom_attr_set_value(attr, value);
		if (err != DOM_NO_ERR) {
			dom_node_unref((struct dom_node *) attr);
			return err;
		}

		a = (struct dom_node *) attr;

		/* And insert it into the element */
		a->previous = NULL;
		a->next = (struct dom_node *) element->attributes;

		if (a->next != NULL)
			a->next->previous = a;

		element->attributes = attr;
	}

	return DOM_NO_ERR;
}

/**
 * Remove an attribute from an element by name
 *
 * \param element  The element to remove attribute from
 * \param name     The name of the attribute to remove
 * \return DOM_NO_ERR                      on success,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly.
 */
dom_exception dom_element_remove_attribute(struct dom_element *element,
		struct dom_string *name)
{
	struct dom_node *e = (struct dom_node *) element;
	struct dom_node *a = (struct dom_node *) element->attributes;

	/* Ensure element can be written to */
	if (_dom_node_readonly(e))
		return DOM_NO_MODIFICATION_ALLOWED_ERR;

	/* Search for existing attribute with same name */
	for (; a != NULL; a = a->next) {
		if (dom_string_cmp(a->name, name) == 0)
			break;
	}

	/* Detach attr node from list */
	if (a != NULL) {
		if (a->previous != NULL)
			a->previous->next = a->next;
		else
			element->attributes = (struct dom_attr *) a->next;

		if (a->next != NULL)
			a->next->previous = a->previous;

		a->previous = a->next = a->parent = NULL;

		/* And destroy attr */
		dom_node_unref(a);
	}

	/** \todo defaulted attribute handling */

	return DOM_NO_ERR;
}

/**
 * Retrieve an attribute node from an element by name
 *
 * \param element  The element to retrieve attribute node from
 * \param name     The attribute's name
 * \param result   Pointer to location to receive attribute node
 * \return DOM_NO_ERR.
 *
 * The returned node will have its reference count increased. It is
 * the responsibility of the caller to unref the node once it has
 * finished with it.
 */
dom_exception dom_element_get_attribute_node(struct dom_element *element,
		struct dom_string *name, struct dom_attr **result)
{
	struct dom_node *a = (struct dom_node *) element->attributes;

	/* Search attributes, looking for name */
	for (; a != NULL; a = a->next) {
		if (dom_string_cmp(a->name, name) == 0)
			break;
	}

	if (a != NULL)
		dom_node_ref(a);
	*result = (struct dom_attr *) a;

	return DOM_NO_ERR;
}

/**
 * Set an attribute node on an element, replacing existing node, if present
 *
 * \param element  The element to add a node to
 * \param attr     The attribute node to add
 * \param result   Pointer to location to receive previous node
 * \return DOM_NO_ERR                      on success,
 *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
 *                                         same document as ::element,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
 *                                         of another Element node.
 *
 * The returned node will have its reference count increased. It is
 * the responsibility of the caller to unref the node once it has
 * finished with it.
 */
dom_exception dom_element_set_attribute_node(struct dom_element *element,
		struct dom_attr *attr, struct dom_attr **result)
{
	struct dom_node *e = (struct dom_node *) element;
	struct dom_node *a = (struct dom_node *) attr;
	struct dom_attr *prev = NULL;

	/* Ensure element and attribute belong to the same document */
	if (e->owner != a->owner)
		return DOM_WRONG_DOCUMENT_ERR;

	/* Ensure element can be written to */
	if (_dom_node_readonly(e))
		return DOM_NO_MODIFICATION_ALLOWED_ERR;

	/* Ensure attribute isn't attached to another element */
	if (a->parent != NULL && a->parent != e)
		return DOM_INUSE_ATTRIBUTE_ERR;

	/* Attach attr to element, if not already attached */
	if (a->parent == NULL) {

		/* Search for existing attribute with same name */
		prev = element->attributes; 
		while (prev != NULL) {
			struct dom_node *p = (struct dom_node *) prev;

			if (dom_string_cmp(a->name, p->name) == 0)
				break;

			prev = (struct dom_attr *) p->next;
		}

		a->parent = e;

		if (prev != NULL) {
			/* Found an existing attribute, so replace it */
			struct dom_node *p = (struct dom_node *) prev;

			a->previous = p->previous;
			a->next = p->next;

			if (a->previous != NULL)
				a->previous->next = a;
			else
				element->attributes = attr;

			if (a->next != NULL)
				a->next->previous = a;

			/* Invalidate existing attribute's location info */
			p->next = NULL;
			p->previous = NULL;
			p->parent = NULL;
		} else {
			/* No existing attribute, so insert at front of list */
			a->previous = NULL;
			a->next = (struct dom_node *) element->attributes;

			if (a->next != NULL)
				a->next->previous = a;

			element->attributes = attr;
		}
	}

	if (prev != NULL)
		dom_node_ref((struct dom_node *) prev);

	*result = prev;

	return DOM_NO_ERR;
}

/**
 * Remove an attribute node from an element
 *
 * \param element  The element to remove attribute node from
 * \param attr     The attribute node to remove
 * \param result   Pointer to location to receive attribute node
 * \return DOM_NO_ERR                      on success,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_NOT_FOUND_ERR               if ::attr is not an attribute of
 *                                         ::element.
 *
 * The returned node will have its reference count increased. It is
 * the responsibility of the caller to unref the node once it has
 * finished with it.
 */
dom_exception dom_element_remove_attribute_node(struct dom_element *element,
		struct dom_attr *attr, struct dom_attr **result)
{
	struct dom_node *e = (struct dom_node *) element;
	struct dom_node *a = (struct dom_node *) attr;

	/* Ensure element can be written to */
	if (_dom_node_readonly(e))
		return DOM_NO_MODIFICATION_ALLOWED_ERR;

	/* Ensure attr is an attribute of element */
	if (a->parent != e)
		return DOM_NOT_FOUND_ERR;

	/* Detach attr node from list */
	if (a->previous != NULL)
		a->previous->next = a->next;
	else
		element->attributes = (struct dom_attr *) a->next;

	if (a->next != NULL)
		a->next->previous = a->previous;

	a->previous = a->next = a->parent = NULL;

	/** \todo defaulted attribute handling */

	/* Return the detached node */
	dom_node_ref(a);
	*result = attr;

	return DOM_NO_ERR;
}

/**
 * Retrieve a list of descendant elements of an element which match a given
 * tag name
 *
 * \param element  The root of the subtree to search
 * \param name     The tag name to match (or "*" for all tags)
 * \param result   Pointer to location to receive result
 * \return DOM_NO_ERR.
 *
 * The returned nodelist will have its reference count increased. It is
 * the responsibility of the caller to unref the nodelist once it has
 * finished with it.
 */
dom_exception dom_element_get_elements_by_tag_name(
		struct dom_element *element, struct dom_string *name,
		struct dom_nodelist **result)
{
	return dom_document_get_nodelist(element->base.owner, 
			(struct dom_node *) element, name, NULL, NULL, result);
}

/**
 * Retrieve an attribute from an element by namespace/localname
 *
 * \param element    The element to retrieve attribute from
 * \param namespace  The attribute's namespace URI
 * \param localname  The attribute's local name
 * \param value      Pointer to location to receive attribute's value
 * \return DOM_NO_ERR            on success,
 *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
 *                               the feature "XML" and the language exposed
 *                               through the Document does not support
 *                               Namespaces.
 *
 * The returned string will have its reference count increased. It is
 * the responsibility of the caller to unref the string once it has
 * finished with it.
 */
dom_exception dom_element_get_attribute_ns(struct dom_element *element,
		struct dom_string *namespace, struct dom_string *localname,
		struct dom_string **value)
{
	UNUSED(element);
	UNUSED(namespace);
	UNUSED(localname);
	UNUSED(value);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * Set an attribute on an element by namespace/qualified name
 *
 * \param element    The element to set attribute on
 * \param namespace  The attribute's namespace URI
 * \param qname      The attribute's qualified name
 * \param value      The attribute's value
 * \return DOM_NO_ERR                      on success,
 *         DOM_INVALID_CHARACTER_ERR       if ::qname is invalid,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_NAMESPACE_ERR               if ::qname is malformed, or
 *                                         ::qname has a prefix and
 *                                         ::namespace is null, or ::qname
 *                                         has a prefix "xml" and
 *                                         ::namespace is not
 *                                         "http://www.w3.org/XML/1998/namespace",
 *                                         or ::qname has a prefix "xmlns"
 *                                         and ::namespace is not
 *                                         "http://www.w3.org/2000/xmlns",
 *                                         or ::namespace is
 *                                         "http://www.w3.org/2000/xmlns"
 *                                         and ::qname is not prefixed
 *                                         "xmlns",
 *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
 *                                         support the feature "XML" and the
 *                                         language exposed through the
 *                                         Document does not support
 *                                         Namespaces.
 */
dom_exception dom_element_set_attribute_ns(struct dom_element *element,
		struct dom_string *namespace, struct dom_string *qname,
		struct dom_string *value)
{
	UNUSED(element);
	UNUSED(namespace);
	UNUSED(qname);
	UNUSED(value);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * Remove an attribute from an element by namespace/localname
 *
 * \param element    The element to remove attribute from
 * \param namespace  The attribute's namespace URI
 * \param localname  The attribute's local name
 * \return DOM_NO_ERR                      on success,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
 *                                         support the feature "XML" and the
 *                                         language exposed through the
 *                                         Document does not support
 *                                         Namespaces.
 */
dom_exception dom_element_remove_attribute_ns(struct dom_element *element,
		struct dom_string *namespace, struct dom_string *localname)
{
	UNUSED(element);
	UNUSED(namespace);
	UNUSED(localname);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * Retrieve an attribute node from an element by namespace/localname
 *
 * \param element    The element to retrieve attribute from
 * \param namespace  The attribute's namespace URI
 * \param localname  The attribute's local name
 * \param result     Pointer to location to receive attribute node
 * \return DOM_NO_ERR            on success,
 *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
 *                               the feature "XML" and the language exposed
 *                               through the Document does not support
 *                               Namespaces.
 *
 * The returned node will have its reference count increased. It is
 * the responsibility of the caller to unref the node once it has
 * finished with it.
 */
dom_exception dom_element_get_attribute_node_ns(struct dom_element *element,
		struct dom_string *namespace, struct dom_string *localname,
		struct dom_attr **result)
{
	UNUSED(element);
	UNUSED(namespace);
	UNUSED(localname);
	UNUSED(result);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * Set an attribute node on an element, replacing existing node, if present
 *
 * \param element  The element to add a node to
 * \param attr     The attribute node to add
 * \param result   Pointer to location to recieve previous node
 * \return DOM_NO_ERR                      on success,
 *         DOM_WRONG_DOCUMENT_ERR          if ::attr does not belong to the
 *                                         same document as ::element,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_INUSE_ATTRIBUTE_ERR         if ::attr is already an attribute
 *                                         of another Element node.
 *         DOM_NOT_SUPPORTED_ERR           if the implementation does not
 *                                         support the feature "XML" and the
 *                                         language exposed through the
 *                                         Document does not support
 *                                         Namespaces.
 *
 * The returned node will have its reference count increased. It is
 * the responsibility of the caller to unref the node once it has
 * finished with it.
 */
dom_exception dom_element_set_attribute_node_ns(struct dom_element *element,
		struct dom_attr *attr, struct dom_attr **result)
{
	UNUSED(element);
	UNUSED(attr);
	UNUSED(result);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * Retrieve a list of descendant elements of an element which match a given
 * namespace/localname pair.
 *
 * \param element  The root of the subtree to search
 * \param namespace  The namespace URI to match (or "*" for all)
 * \param localname  The local name to match (or "*" for all)
 * \param result   Pointer to location to receive result
 * \return DOM_NO_ERR            on success,
 *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
 *                               the feature "XML" and the language exposed
 *                               through the Document does not support
 *                               Namespaces.
 *
 * The returned nodelist will have its reference count increased. It is
 * the responsibility of the caller to unref the nodelist once it has
 * finished with it.
 */
dom_exception dom_element_get_elements_by_tag_name_ns(
		struct dom_element *element, struct dom_string *namespace,
		struct dom_string *localname, struct dom_nodelist **result)
{
	return dom_document_get_nodelist(element->base.owner, 
			(struct dom_node *) element, NULL, 
			namespace, localname, result);
}

/**
 * Determine if an element possesses and attribute with the given name
 *
 * \param element  The element to query
 * \param name     The attribute name to look for
 * \param result   Pointer to location to receive result
 * \return DOM_NO_ERR.
 */
dom_exception dom_element_has_attribute(struct dom_element *element,
		struct dom_string *name, bool *result)
{
	struct dom_node *a = (struct dom_node *) element->attributes;

	/* Search attributes, looking for name */
	for (; a != NULL; a = a->next) {
		if (dom_string_cmp(a->name, name) == 0)
			break;
	}

	*result = (a != NULL);

	return DOM_NO_ERR;
}

/**
 * Determine if an element possesses and attribute with the given
 * namespace/localname pair.
 *
 * \param element    The element to query
 * \param namespace  The attribute namespace URI to look for
 * \param localname  The attribute local name to look for
 * \param result   Pointer to location to receive result
 * \return DOM_NO_ERR            on success,
 *         DOM_NOT_SUPPORTED_ERR if the implementation does not support
 *                               the feature "XML" and the language exposed
 *                               through the Document does not support
 *                               Namespaces.
 */
dom_exception dom_element_has_attribute_ns(struct dom_element *element,
		struct dom_string *namespace, struct dom_string *localname,
		bool *result)
{
	UNUSED(element);
	UNUSED(namespace);
	UNUSED(localname);
	UNUSED(result);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * Retrieve the type information associated with an element
 *
 * \param element  The element to retrieve type information from
 * \param result   Pointer to location to receive type information
 * \return DOM_NO_ERR.
 *
 * The returned typeinfo will have its reference count increased. It is
 * the responsibility of the caller to unref the typeinfo once it has
 * finished with it.
 */
dom_exception dom_element_get_schema_type_info(struct dom_element *element,
		struct dom_type_info **result)
{
	UNUSED(element);
	UNUSED(result);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * (Un)declare an attribute as being an element's ID by name
 *
 * \param element  The element containing the attribute
 * \param name     The attribute's name
 * \param is_id    Whether the attribute is an ID
 * \return DOM_NO_ERR                      on success,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_NOT_FOUND_ERR               if the specified node is not an
 *                                         attribute of ::element.
 */
dom_exception dom_element_set_id_attribute(struct dom_element *element,
		struct dom_string *name, bool is_id)
{
	UNUSED(element);
	UNUSED(name);
	UNUSED(is_id);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * (Un)declare an attribute as being an element's ID by namespace/localname
 *
 * \param element    The element containing the attribute
 * \param namespace  The attribute's namespace URI
 * \param localname  The attribute's local name
 * \param is_id      Whether the attribute is an ID
 * \return DOM_NO_ERR                      on success,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_NOT_FOUND_ERR               if the specified node is not an
 *                                         attribute of ::element.
 */
dom_exception dom_element_set_id_attribute_ns(struct dom_element *element,
		struct dom_string *namespace, struct dom_string *localname,
		bool is_id)
{
	UNUSED(element);
	UNUSED(namespace);
	UNUSED(localname);
	UNUSED(is_id);

	return DOM_NOT_SUPPORTED_ERR;
}

/**
 * (Un)declare an attribute node as being an element's ID
 *
 * \param element  The element containing the attribute
 * \param id_attr  The attribute node
 * \param is_id    Whether the attribute is an ID
 * \return DOM_NO_ERR                      on success,
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::element is readonly,
 *         DOM_NOT_FOUND_ERR               if the specified node is not an
 *                                         attribute of ::element.
 */
dom_exception dom_element_set_id_attribute_node(struct dom_element *element,
		struct dom_attr *id_attr, bool is_id)
{
	UNUSED(element);
	UNUSED(id_attr);
	UNUSED(is_id);

	return DOM_NOT_SUPPORTED_ERR;
}

/*                                                                            */
/*----------------------------------------------------------------------------*/
/*                                                                            */

/**
 * Retrieve a map of attributes associated with an Element
 *
 * \param element  The element to retrieve the attributes of
 * \param result   Pointer to location to receive attribute map
 * \return DOM_NO_ERR.
 *
 * The returned NamedNodeMap will be referenced. It is the responsibility
 * of the caller to unref the map once it has finished with it.
 */
dom_exception dom_element_get_attributes(struct dom_element *element,
		struct dom_namednodemap **result)
{
	return dom_document_get_namednodemap(element->base.owner,
			(struct dom_node *) element, DOM_ATTRIBUTE_NODE,
			result);
}

/**
 * Determine if an element has any attributes
 *
 * \param element  Element to inspect
 * \param result   Pointer to location to receive result
 * \return DOM_NO_ERR.
 */
dom_exception dom_element_has_attributes(struct dom_element *element,
		bool *result)
{
	*result = (element->attributes != NULL);

	return DOM_NO_ERR;
}

/**
 * Retrieve a pointer to the first attribute attached to an element
 *
 * \param element  The element to retrieve the first attribute from
 * \return Pointer to first attribute, or NULL if none.
 */
struct dom_node *dom_element_get_first_attribute(struct dom_element *element)
{
	return (struct dom_node *) element->attributes;
}