static SVG_Element *svg_parse_element(GF_SVG_Parser *parser, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes, SVG_NodeStack *parent, Bool *has_ns)
{
	GF_FieldInfo info;
	u32	tag, i, count, ns, xmlns;
	Bool needs_init, has_id;
	SVG_Element *elt = NULL;
	const char *node_name = NULL;
	const char *ev_event, *ev_observer;
	SVG_DeferredAnimation *anim = NULL;
	char *ID = NULL;

	GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[SVG Parsing] Parsing node %s\n", name));

	*has_ns = GF_FALSE;

	svg_check_namespace(parser, attributes, nb_attributes, has_ns);

	for (i=0; i<nb_attributes; i++) {
		GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
		if (!att->value || !strlen(att->value)) continue;
		/* FIXME: This should be changed to reflect that xml:id has precedence over id if both are specified with different values */
		if (!stricmp(att->name, "id") || !stricmp(att->name, "xml:id")) {
			if (!ID) ID = att->value;
		}
	}

	/* CHECK: overriding the element namespace with the parent one, if given ???
	   This is wrong ??*/
	xmlns = parser->current_ns;
	if (name_space) {
		xmlns = gf_sg_get_namespace_code(parser->load->scene_graph, (char *) name_space);
		if (!xmlns) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] line %d - XMLNS prefix %s not defined - skipping\n", gf_xml_sax_get_line(parser->sax_parser), name_space));
			return NULL;
		}
	}

	/* Translates the node type (called name) from a String into a unique numeric identifier in GPAC */
	tag = xmlns ? gf_xml_get_element_tag(name, xmlns) : TAG_UndefinedNode;
	if (tag == TAG_UndefinedNode) {
#ifdef SKIP_UNKNOWN_NODES
		GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[SVG Parsing] line %d - Unknown element %s - skipping\n", gf_xml_sax_get_line(parser->sax_parser), name));
		return NULL;
#else
		tag = TAG_DOMFullNode;
#endif
	}

	/* If this element has an ID, we look in the list of elements already created in advance (in case of reference) to see if it is there,
	   in which case we will reuse it*/
	has_id = GF_FALSE;
	count = gf_list_count(parser->peeked_nodes);
	if (count && ID) {
		for (i=0; i<count; i++) {
			GF_Node *n = (GF_Node *)gf_list_get(parser->peeked_nodes, i);
			const char *n_id = gf_node_get_name(n);
			if (n_id && !strcmp(n_id, ID)) {
				gf_list_rem(parser->peeked_nodes, i);
				has_id = GF_TRUE;
				elt = (SVG_Element*)n;
				break;
			}
		}
	}

	/* If the element was found in the list of elements already created, we do not need to create it, we reuse it.
	   Otherwise, we create it based on the tag */
	if (!has_id) {
		/* Creates a node in the current scene graph */
		elt = (SVG_Element*)gf_node_new(parser->load->scene_graph, tag);
		if (!elt) {
			parser->last_error = GF_SG_UNKNOWN_NODE;
			return NULL;
		}
		/* CHECK: Why isn't this code in the gf_node_new call ?? */
		if (tag == TAG_DOMFullNode) {
			GF_DOMFullNode *d = (GF_DOMFullNode *)elt;
			d->name = gf_strdup(name);
			d->ns = xmlns;
			if (ID)
				gf_svg_parse_element_id((GF_Node *)d, ID, GF_FALSE);
		}
	}

	/* We indicate that the element is used by its parent (reference counting for safe deleting) */
	gf_node_register((GF_Node *)elt, (parent ? (GF_Node *)parent->node : NULL));
	/* We attach this element as the last child of its parent */
	if (parent && elt) gf_node_list_add_child_last( & parent->node->children, (GF_Node*)elt, & parent->last_child);

	/* By default, all elements will need initialization for rendering, except some that will explicitly set it to 0 */
	needs_init = GF_TRUE;

	if (gf_svg_is_animation_tag(tag)) {
		GF_SAFEALLOC(anim, SVG_DeferredAnimation);
		if (!anim) {
			parser->last_error = GF_OUT_OF_MEM;
			return NULL;
		}
		/*default anim target is parent node*/
		anim->animation_elt = elt;
		if (!parent) {
			if (parser->command) {
				anim->target = anim->anim_parent = (SVG_Element*) parser->command->node;
			}
		} else {
			anim->target = anim->anim_parent = parent->node;
		}
	} else if (gf_svg_is_timing_tag(tag)) {
		/* warning: we use the SVG_DeferredAnimation structure for some timing nodes which are not
		   animations, but we put the parse stage at 1 (timing) see svg_parse_animation. */
		GF_SAFEALLOC(anim, SVG_DeferredAnimation);
		if (!anim) {
			parser->last_error = GF_OUT_OF_MEM;
			return NULL;
		}
		/*default anim target is parent node*/
		anim->animation_elt = elt;
		if (!parent) {
			if (parser->command) {
				anim->target = anim->anim_parent = (SVG_Element*) parser->command->node;
			}
		} else {
			anim->target = anim->anim_parent = parent->node;
		}
		anim->resolve_stage = 1;
	} else if ((tag == TAG_SVG_script) || (tag==TAG_SVG_handler)) {
		/* Scripts and handlers don't render and have no initialization phase */
		needs_init = GF_FALSE;
	}

	ev_event = ev_observer = NULL;

#ifdef SKIP_ATTS
	nb_attributes = 0;
#endif

	/*set the root of the SVG tree BEFORE processing events in order to have it setup for script init (e.g. load events, including in root svg)*/
	if ((tag == TAG_SVG_svg) && !parser->has_root) {
		svg_init_root_element(parser, elt);
	}

	/*parse all att*/
	for (i=0; i<nb_attributes; i++) {
		GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
		char *att_name = NULL;
		if (!att->value || !strlen(att->value)) continue;

		/* first determine in which namespace is the attribute and store the result in ns,
		then shift the char buffer to point to the local name of the attribute*/
		ns = xmlns;
		att_name = strchr(att->name, ':');
		if (att_name) {
			if (!strncmp(att->name, "xmlns", 5)) {
				ns = gf_sg_get_namespace_code(parser->load->scene_graph, att_name+1);
				att_name = att->name;
			} else {
				att_name[0] = 0;
				ns = gf_sg_get_namespace_code(parser->load->scene_graph, att->name);
				att_name[0] = ':';
				att_name++;
			}
		} else {
			att_name = att->name;
		}

		/* Begin of special cases of attributes */

		/* CHECK: Shouldn't namespaces be checked here ? */
		if (!stricmp(att_name, "style")) {
			gf_svg_parse_style((GF_Node *)elt, att->value);
			continue;
		}

		/* Some attributes of the animation elements cannot be parsed (into typed values) until the type of value is known,
		   we defer the parsing and store them temporarily as strings */
		if (anim) {
			if (!stricmp(att_name, "to")) {
				anim->to = gf_strdup(att->value);
				continue;
			}
			if (!stricmp(att_name, "from")) {
				anim->from = gf_strdup(att->value);
				continue;
			}
			if (!stricmp(att_name, "by")) {
				anim->by = gf_strdup(att->value);
				continue;
			}
			if (!stricmp(att_name, "values")) {
				anim->values = gf_strdup(att->value);
				continue;
			}
			if ((tag == TAG_SVG_animateTransform) && !stricmp(att_name, "type")) {
				anim->type = gf_strdup(att->value);
				continue;
			}
		}

		/* Special case for xlink:href attributes */
		if ((ns == GF_XMLNS_XLINK) && !stricmp(att_name, "href") ) {

			if (gf_svg_is_animation_tag(tag)) {
				/* For xlink:href in animation elements,
				we try to locate the target of the xlink:href to determine the type of values to be animated */
				assert(anim);
				anim->target_id = gf_strdup(att->value);
				/*The target may be NULL, if it has not yet been parsed, we will try to resolve it later on */
				anim->target = (SVG_Element *) gf_sg_find_node_by_name(parser->load->scene_graph, anim->target_id + 1);
				continue;
			} else {
				/* For xlink:href attribute on elements other than animation elements,
				   we create the attribute, parse it and try to do some special process it */
				XMLRI *iri = NULL;
				if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info)==GF_OK) {
					gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
					iri = (XMLRI *)info.far_ptr;

					/* extract streamID ref or data URL and store as file */
					svg_post_process_href(parser, (GF_Node *)elt, iri);
					continue;
				}
			}
		}

		/* For the XML Event handler element, we need to defer the parsing of some attributes */
		if ((tag == TAG_SVG_handler) && (ns == GF_XMLNS_XMLEV)) {
			if (!stricmp(att_name, "event") ) {
				ev_event = att->value;
				continue;
			}
			if (!stricmp(att_name, "observer") ) {
				ev_observer = att->value;
				continue;
			}
		}

		/*laser specific stuff*/
		if (ns == GF_XMLNS_LASER) {
			/* CHECK: we should probably check the namespace of the attribute here */
			if (!stricmp(att_name, "scale") ) {
				if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_SVG_ATT_transform, GF_TRUE, GF_TRUE, &info)==GF_OK) {
					SVG_Point pt;
					SVG_Transform *mat = (SVG_Transform *)info.far_ptr;
					svg_parse_point(&pt, att->value);
					gf_mx2d_add_scale(&mat->mat, pt.x, pt.y);
					continue;
				}
			}
			if (!stricmp(att_name, "translation") ) {
				if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_SVG_ATT_transform, GF_TRUE, GF_TRUE, &info)==GF_OK) {
					SVG_Point pt;
					SVG_Transform *mat = (SVG_Transform *)info.far_ptr;
					svg_parse_point(&pt, att->value);
					gf_mx2d_add_translation(&mat->mat, pt.x, pt.y);
					continue;
				}
			}
		}

		/* For all attributes of the form 'on...', like 'onclick' we create a listener for the event on the current element,
		   we connect the listener to a handler that contains the code in the 'on...' attribute. */
		/* CHECK: we should probably check the namespace of the attribute and of the element here */
		if (!strncmp(att_name, "on", 2)) {
			u32 evtType = gf_dom_event_type_by_name(att_name + 2);
			if (evtType != GF_EVENT_UNKNOWN) {
				SVG_handlerElement *handler = gf_dom_listener_build((GF_Node *) elt, evtType, 0);
				gf_dom_add_text_node((GF_Node *)handler, gf_strdup(att->value) );
				gf_node_init((GF_Node *)handler);
				continue;
			}
			svg_report(parser, GF_OK, "Skipping unknown event handler %s on node %s", att->name, name);
		}

		/* end of special cases of attributes */

		/* General attribute creation and parsing */
		if (gf_node_get_attribute_by_name((GF_Node *)elt, att_name, ns, GF_TRUE, GF_FALSE, &info)==GF_OK) {
#ifndef SKIP_ATTS_PARSING
			GF_Err e = gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
			if (e) {
				svg_report(parser, e, "Error parsing attribute %s on node %s", att->name, name);
				continue;
			}
			if (info.fieldType == SVG_ID_datatype) {
				/*"when both 'id' and 'xml:id'  are specified on the same element but with different values,
				the SVGElement::id field must return either of the values but should give precedence to
				the 'xml:id'  attribute."*/
				if (!node_name || (info.fieldIndex == TAG_XML_ATT_id)) {
					node_name = *(SVG_ID *)info.far_ptr;
					/* Check if ID start with a digit, which is not a valid ID for a node according to XML (see http://www.w3.org/TR/xml/#id) */
					if (isdigit(node_name[0])) {
						svg_report(parser, GF_BAD_PARAM, "Invalid value %s for node %s %s", node_name, name, att->name);
						node_name = NULL;
					}
				}
			} else {
				switch (info.fieldIndex) {
				case TAG_SVG_ATT_syncMaster:
				case TAG_SVG_ATT_focusHighlight:
				case TAG_SVG_ATT_initialVisibility:
				case TAG_SVG_ATT_fullscreen:
				case TAG_SVG_ATT_requiredFonts:
					/*switch LASeR Configuration to v2 because these attributes are not part of v1*/
					svg_lsr_set_v2(parser);
					break;
				}
			}
#endif
			continue;
		}

		/* all other attributes (??? failed to be created) should fall in this category */
		svg_report(parser, GF_OK, "Skipping attribute %s on node %s", att->name, name);
	}

	/* When a handler element specifies the event attribute, an implicit listener is defined */
	if (ev_event) {
		GF_Node *node = (GF_Node *)elt;
		SVG_Element *listener;
		u32 type;
		listener = (SVG_Element *) gf_node_new(node->sgprivate->scenegraph, TAG_SVG_listener);
		/*We don't want to insert the implicit listener in the DOM. However remember
		the listener at the handler level in case the handler gets destroyed*/
		gf_node_set_private(node, (GF_Node*)listener );
		gf_node_register((GF_Node*)listener, NULL);

		/* this listener listens to the given type of event */
		type = gf_dom_event_type_by_name(ev_event);
		gf_node_get_attribute_by_tag(node, TAG_XMLEV_ATT_event, GF_TRUE, GF_FALSE, &info);
		((XMLEV_Event *)info.far_ptr)->type = type;
		gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_event, GF_TRUE, GF_FALSE, &info);
		((XMLEV_Event *)info.far_ptr)->type = type;
		gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_handler, GF_TRUE, GF_FALSE, &info);
		((XMLRI *)info.far_ptr)->target = node;

		if (ev_observer) {
			/* An observer was specified, so it needs to be used */
			gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_TRUE, GF_FALSE, &info);
			gf_svg_parse_attribute((GF_Node *)elt, &info, (char*)ev_observer, 0);
		} else {
			/* No observer specified, this listener listens with the parent of the handler as the event target */
			gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_TRUE, GF_FALSE, &info);
			((XMLRI *)info.far_ptr)->target = parent->node;
		}
		/* if the target was found (already parsed), we are fine, otherwise we need to try to find it again,
		   we place the listener in the deferred listener list */
		if ( ((XMLRI *)info.far_ptr)->target)
			gf_node_dom_listener_add(((XMLRI *)info.far_ptr)->target, (GF_Node *) listener);
		else
			gf_list_add(parser->deferred_listeners, listener);
	}

	if (!node_name && ID)
		node_name = ID;

	/* if the new element has an id, we try to resolve deferred references (including animations, href and listeners (just above)*/
	if (node_name) {
		if (!has_id) {
			/* if the element was already created before this call, we don't need to get a numerical id, we have it already */
			gf_svg_parse_element_id((GF_Node *)elt, node_name, parser->command_depth ? GF_TRUE : GF_FALSE);
		}
		svg_resolved_refs(parser, parser->load->scene_graph, node_name);
	}

	/* if the new element is an animation, now that all specified attributes have been found,
	   we can start parsing them */
	if (anim) {
		/*FIXME - we need to parse from/to/values but not initialize the stack*/
//		if (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
		needs_init = GF_FALSE;
		if (svg_parse_animation(parser, parser->load->scene_graph, anim, NULL, 0)) {
			svg_delete_deferred_anim(anim, NULL);
		} else {
			gf_list_add(parser->deferred_animations, anim);
		}
//		} else {
//			svg_delete_deferred_anim(anim, NULL);
//		}
	}

#ifndef SKIP_INIT
	if (needs_init) {
		/* For elements that need it, we initialize the rendering stack */
		gf_node_init((GF_Node *)elt);
	}
#endif

	if (parent && elt) {
		/*mark parent element as dirty (new child added) and invalidate parent graph for progressive rendering*/
		gf_node_dirty_set((GF_Node *)parent->node, GF_SG_CHILD_DIRTY, GF_TRUE);
		/*request scene redraw*/
		if (parser->load->scene_graph->NodeCallback) {
			parser->load->scene_graph->NodeCallback(parser->load->scene_graph->userpriv, GF_SG_CALLBACK_MODIFIED, NULL, NULL);
		}
	}

	/*If we are in playback mode, we register (reference counting for safe deleting) the listener element with the element that uses it */
	if ((parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && elt && (tag==TAG_SVG_listener)) {
		Bool post_pone = GF_FALSE;
		SVG_Element *par = NULL;
		SVG_Element *listener = (SVG_Element *)elt;

		if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_FALSE, GF_FALSE, &info) == GF_OK) {
			XMLRI *observer = (XMLRI *)info.far_ptr;
			if (observer->type == XMLRI_ELEMENTID) {
				if (!observer->target) post_pone = GF_TRUE;
				else par = (SVG_Element *)observer->target;
			}
		}

		if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_FALSE, GF_FALSE, &info) == GF_OK) {
			XMLRI *target = (XMLRI *)info.far_ptr;
			if (!par && (target->type == XMLRI_ELEMENTID)) {
				if (!target->target) post_pone = GF_TRUE;
				else par = (SVG_Element *)target->target;
			}
		}
		/*check handler, create it if not specified*/
		if (parent && (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_handler, GF_TRUE, GF_FALSE, &info) == GF_OK)) {
			XMLRI *handler = (XMLRI *)info.far_ptr;
			if (!handler->target) {
				if (!handler->string) handler->target = parent->node;
			}
		}
		/*if event is a key event, register it with root*/
		if (!par && gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_event, GF_FALSE, GF_FALSE, &info) == GF_OK) {
			XMLEV_Event *ev = (XMLEV_Event *)info.far_ptr;
			if ((ev->type>=GF_EVENT_KEYUP) && (ev->type<=GF_EVENT_TEXTINPUT)) par = (SVG_Element*) listener->sgprivate->scenegraph->RootNode;
		}

		if (post_pone) {
			gf_list_add(parser->deferred_listeners, listener);
		} else {
			if (!par && parent) par = parent->node;
			gf_node_dom_listener_add((GF_Node *)par, (GF_Node *) listener);
		}
	}
	return elt;
}
static SVG_Element *svg_parse_element(GF_SVG_Parser *parser, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes, SVG_NodeStack *parent, Bool *has_ns)
{
	GF_FieldInfo info;
	u32	tag, i, count, ns, xmlns;
	Bool needs_init, has_id;
	SVG_Element *elt = NULL;
	const char *node_name = NULL;
	const char *ev_event, *ev_observer;
	SVG_DeferredAnimation *anim = NULL;
	char *ID = NULL;

	GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[SVG Parsing] Parsing node %s\n", name));

	*has_ns = GF_FALSE;

	svg_check_namespace(parser, attributes, nb_attributes, has_ns);

	for (i=0; i<nb_attributes; i++) {
		GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
		if (!att->value || !strlen(att->value)) continue;
		 
		if (!stricmp(att->name, "id") || !stricmp(att->name, "xml:id")) {
			if (!ID) ID = att->value;
		}
	}

	 
	xmlns = parser->current_ns;
	if (name_space) {
		xmlns = gf_sg_get_namespace_code(parser->load->scene_graph, (char *) name_space);
		if (!xmlns) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] line %d - XMLNS prefix %s not defined - skipping\n", gf_xml_sax_get_line(parser->sax_parser), name_space));
			return NULL;
		}
	}

	 
	tag = xmlns ? gf_xml_get_element_tag(name, xmlns) : TAG_UndefinedNode;
	if (tag == TAG_UndefinedNode) {
#ifdef SKIP_UNKNOWN_NODES
		GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[SVG Parsing] line %d - Unknown element %s - skipping\n", gf_xml_sax_get_line(parser->sax_parser), name));
		return NULL;
#else
		tag = TAG_DOMFullNode;
#endif
	}

	 
	has_id = GF_FALSE;
	count = gf_list_count(parser->peeked_nodes);
	if (count && ID) {
		for (i=0; i<count; i++) {
			GF_Node *n = (GF_Node *)gf_list_get(parser->peeked_nodes, i);
			const char *n_id = gf_node_get_name(n);
			if (n_id && !strcmp(n_id, ID)) {
				gf_list_rem(parser->peeked_nodes, i);
				has_id = GF_TRUE;
				elt = (SVG_Element*)n;
				break;
			}
		}
	}

	 
	if (!has_id) {
		 
		elt = (SVG_Element*)gf_node_new(parser->load->scene_graph, tag);
		if (!elt) {
			parser->last_error = GF_SG_UNKNOWN_NODE;
			return NULL;
		}
		 
		if (tag == TAG_DOMFullNode) {
			GF_DOMFullNode *d = (GF_DOMFullNode *)elt;
			d->name = gf_strdup(name);
			d->ns = xmlns;
			if (ID)
				gf_svg_parse_element_id((GF_Node *)d, ID, GF_FALSE);
		}
	}

	 
	gf_node_register((GF_Node *)elt, (parent ? (GF_Node *)parent->node : NULL));
	 
	if (parent && elt) gf_node_list_add_child_last( & parent->node->children, (GF_Node*)elt, & parent->last_child);

	 
	needs_init = GF_TRUE;

	if (gf_svg_is_animation_tag(tag)) {
		GF_SAFEALLOC(anim, SVG_DeferredAnimation);
		if (!anim) {
			parser->last_error = GF_OUT_OF_MEM;
			return NULL;
		}
		 
		anim->animation_elt = elt;
		if (!parent) {
			if (parser->command) {
				anim->target = anim->anim_parent = (SVG_Element*) parser->command->node;
			}
		} else {
			anim->target = anim->anim_parent = parent->node;
		}
	} else if (gf_svg_is_timing_tag(tag)) {
		 
		GF_SAFEALLOC(anim, SVG_DeferredAnimation);
		if (!anim) {
			parser->last_error = GF_OUT_OF_MEM;
			return NULL;
		}
		 
		anim->animation_elt = elt;
		if (!parent) {
			if (parser->command) {
				anim->target = anim->anim_parent = (SVG_Element*) parser->command->node;
			}
		} else {
			anim->target = anim->anim_parent = parent->node;
		}
		anim->resolve_stage = 1;
	} else if ((tag == TAG_SVG_script) || (tag==TAG_SVG_handler)) {
		 
		needs_init = GF_FALSE;
	}

	ev_event = ev_observer = NULL;

#ifdef SKIP_ATTS
	nb_attributes = 0;
#endif

	 
	if ((tag == TAG_SVG_svg) && !parser->has_root) {
		svg_init_root_element(parser, elt);
	}

	 
	for (i=0; i<nb_attributes; i++) {
		GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
		char *att_name = NULL;
		if (!att->value || !strlen(att->value)) continue;

		 
		ns = xmlns;
		att_name = strchr(att->name, ':');
		if (att_name) {
			if (!strncmp(att->name, "xmlns", 5)) {
				ns = gf_sg_get_namespace_code(parser->load->scene_graph, att_name+1);
				att_name = att->name;
			} else {
				att_name[0] = 0;
				ns = gf_sg_get_namespace_code(parser->load->scene_graph, att->name);
				att_name[0] = ':';
				att_name++;
			}
		} else {
			att_name = att->name;
		}

		 

		 
		if (!stricmp(att_name, "style")) {
			gf_svg_parse_style((GF_Node *)elt, att->value);
			continue;
		}

		 
		if (anim) {
			if (!stricmp(att_name, "to")) {
				anim->to = gf_strdup(att->value);
				continue;
			}
			if (!stricmp(att_name, "from")) {
				anim->from = gf_strdup(att->value);
				continue;
			}
			if (!stricmp(att_name, "by")) {
				anim->by = gf_strdup(att->value);
				continue;
			}
			if (!stricmp(att_name, "values")) {
				anim->values = gf_strdup(att->value);
				continue;
			}
			if ((tag == TAG_SVG_animateTransform) && !stricmp(att_name, "type")) {
				anim->type = gf_strdup(att->value);
				continue;
			}
		}

		 
		if ((ns == GF_XMLNS_XLINK) && !stricmp(att_name, "href") ) {

			if (gf_svg_is_animation_tag(tag)) {
				 
				assert(anim);
				anim->target_id = gf_strdup(att->value);
				 
				anim->target = (SVG_Element *) gf_sg_find_node_by_name(parser->load->scene_graph, anim->target_id + 1);
				continue;
			} else {
				 
				XMLRI *iri = NULL;
				if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info)==GF_OK) {
					gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
					iri = (XMLRI *)info.far_ptr;

					 
					svg_post_process_href(parser, (GF_Node *)elt, iri);
					continue;
				}
			}
		}

		 
		if ((tag == TAG_SVG_handler) && (ns == GF_XMLNS_XMLEV)) {
			if (!stricmp(att_name, "event") ) {
				ev_event = att->value;
				continue;
			}
			if (!stricmp(att_name, "observer") ) {
				ev_observer = att->value;
				continue;
			}
		}

		 
		if (ns == GF_XMLNS_LASER) {
			 
			if (!stricmp(att_name, "scale") ) {
				if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_SVG_ATT_transform, GF_TRUE, GF_TRUE, &info)==GF_OK) {
					SVG_Point pt;
					SVG_Transform *mat = (SVG_Transform *)info.far_ptr;
					svg_parse_point(&pt, att->value);
					gf_mx2d_add_scale(&mat->mat, pt.x, pt.y);
					continue;
				}
			}
			if (!stricmp(att_name, "translation") ) {
				if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_SVG_ATT_transform, GF_TRUE, GF_TRUE, &info)==GF_OK) {
					SVG_Point pt;
					SVG_Transform *mat = (SVG_Transform *)info.far_ptr;
					svg_parse_point(&pt, att->value);
					gf_mx2d_add_translation(&mat->mat, pt.x, pt.y);
					continue;
				}
			}
		}

		 
		 
		if (!strncmp(att_name, "on", 2)) {
			u32 evtType = gf_dom_event_type_by_name(att_name + 2);
			if (evtType != GF_EVENT_UNKNOWN) {
				SVG_handlerElement *handler = gf_dom_listener_build((GF_Node *) elt, evtType, 0);
				gf_dom_add_text_node((GF_Node *)handler, gf_strdup(att->value) );
				gf_node_init((GF_Node *)handler);
				continue;
			}
			svg_report(parser, GF_OK, "Skipping unknown event handler %s on node %s", att->name, name);
		}

		 

		 
		if (gf_node_get_attribute_by_name((GF_Node *)elt, att_name, ns, GF_TRUE, GF_FALSE, &info)==GF_OK) {
#ifndef SKIP_ATTS_PARSING
			GF_Err e = gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
			if (e) {
				svg_report(parser, e, "Error parsing attribute %s on node %s", att->name, name);
				continue;
			}
			if (info.fieldType == SVG_ID_datatype) {
				 
				if (!node_name || (info.fieldIndex == TAG_XML_ATT_id)) {
					node_name = *(SVG_ID *)info.far_ptr;
					 
					if (isdigit(node_name[0])) {
						svg_report(parser, GF_BAD_PARAM, "Invalid value %s for node %s %s", node_name, name, att->name);
						node_name = NULL;
					}
				}
			} else {
				switch (info.fieldIndex) {
				case TAG_SVG_ATT_syncMaster:
				case TAG_SVG_ATT_focusHighlight:
				case TAG_SVG_ATT_initialVisibility:
				case TAG_SVG_ATT_fullscreen:
				case TAG_SVG_ATT_requiredFonts:
					 
					svg_lsr_set_v2(parser);
					break;
				}
			}
#endif
			continue;
		}

		 
		svg_report(parser, GF_OK, "Skipping attribute %s on node %s", att->name, name);
	}

	 
	if (ev_event) {
		GF_Node *node = (GF_Node *)elt;
		SVG_Element *listener;
		u32 type;
		listener = (SVG_Element *) gf_node_new(node->sgprivate->scenegraph, TAG_SVG_listener);
		 
		gf_node_set_private(node, (GF_Node*)listener );
		gf_node_register((GF_Node*)listener, NULL);

		 
		type = gf_dom_event_type_by_name(ev_event);
		gf_node_get_attribute_by_tag(node, TAG_XMLEV_ATT_event, GF_TRUE, GF_FALSE, &info);
		((XMLEV_Event *)info.far_ptr)->type = type;
		gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_event, GF_TRUE, GF_FALSE, &info);
		((XMLEV_Event *)info.far_ptr)->type = type;
		gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_handler, GF_TRUE, GF_FALSE, &info);
		((XMLRI *)info.far_ptr)->target = node;

		if (ev_observer) {
			 
			gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_TRUE, GF_FALSE, &info);
			gf_svg_parse_attribute((GF_Node *)elt, &info, (char*)ev_observer, 0);
		} else {
			 
			gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_TRUE, GF_FALSE, &info);
			((XMLRI *)info.far_ptr)->target = parent->node;
		}
		 
		if ( ((XMLRI *)info.far_ptr)->target)
			gf_node_dom_listener_add(((XMLRI *)info.far_ptr)->target, (GF_Node *) listener);
		else
			gf_list_add(parser->deferred_listeners, listener);
	}

	if (!node_name && ID)
		node_name = ID;

	 
	if (node_name) {
		if (!has_id) {
			 
			gf_svg_parse_element_id((GF_Node *)elt, node_name, parser->command_depth ? GF_TRUE : GF_FALSE);
		}
		svg_resolved_refs(parser, parser->load->scene_graph, node_name);
	}

	 
	if (anim) {
		 
 
		needs_init = GF_FALSE;
		if (svg_parse_animation(parser, parser->load->scene_graph, anim, NULL, 0)) {
			svg_delete_deferred_anim(anim, NULL);
		} else {
			gf_list_add(parser->deferred_animations, anim);
		}
 
 
 
	}

#ifndef SKIP_INIT
	if (needs_init) {
		 
		gf_node_init((GF_Node *)elt);
	}
#endif

	if (parent && elt) {
		 
		gf_node_dirty_set((GF_Node *)parent->node, GF_SG_CHILD_DIRTY, GF_TRUE);
		 
		if (parser->load->scene_graph->NodeCallback) {
			parser->load->scene_graph->NodeCallback(parser->load->scene_graph->userpriv, GF_SG_CALLBACK_MODIFIED, NULL, NULL);
		}
	}

	 
	if ((parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && elt && (tag==TAG_SVG_listener)) {
		Bool post_pone = GF_FALSE;
		SVG_Element *par = NULL;
		SVG_Element *listener = (SVG_Element *)elt;

		if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_FALSE, GF_FALSE, &info) == GF_OK) {
			XMLRI *observer = (XMLRI *)info.far_ptr;
			if (observer->type == XMLRI_ELEMENTID) {
				if (!observer->target) post_pone = GF_TRUE;
				else par = (SVG_Element *)observer->target;
			}
		}

		if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_FALSE, GF_FALSE, &info) == GF_OK) {
			XMLRI *target = (XMLRI *)info.far_ptr;
			if (!par && (target->type == XMLRI_ELEMENTID)) {
				if (!target->target) post_pone = GF_TRUE;
				else par = (SVG_Element *)target->target;
			}
		}
		 
		if (parent && (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_handler, GF_TRUE, GF_FALSE, &info) == GF_OK)) {
			XMLRI *handler = (XMLRI *)info.far_ptr;
			if (!handler->target) {
				if (!handler->string) handler->target = parent->node;
			}
		}
		 
		if (!par && gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_event, GF_FALSE, GF_FALSE, &info) == GF_OK) {
			XMLEV_Event *ev = (XMLEV_Event *)info.far_ptr;
			if ((ev->type>=GF_EVENT_KEYUP) && (ev->type<=GF_EVENT_TEXTINPUT)) par = (SVG_Element*) listener->sgprivate->scenegraph->RootNode;
		}

		if (post_pone) {
			gf_list_add(parser->deferred_listeners, listener);
		} else {
			if (!par && parent) par = parent->node;
			gf_node_dom_listener_add((GF_Node *)par, (GF_Node *) listener);
		}
	}
	return elt;
}