static GF_Err lsr_parse_command(GF_SVG_Parser *parser, const GF_XMLAttribute *attributes, u32 nb_attributes)
{
	GF_FieldInfo info;
	GF_Node *opNode;
	Bool is_replace = GF_FALSE;
	char *atNode = NULL;
	char *atAtt = NULL;
	char *atOperandNode = NULL;
	char *atOperandAtt = NULL;
	char *atValue = NULL;
	char *atPoint = NULL;
	char *atInteger = NULL;
	char *atEvent = NULL;
	char *atString = NULL;
	GF_CommandField *field;
	s32 index = -1;
	u32 i;
	switch (parser->command->tag) {
	case GF_SG_LSR_NEW_SCENE:
		return GF_OK;
	case GF_SG_LSR_DELETE:
		for (i=0; i<nb_attributes; i++) {
			GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
			if (!strcmp(att->name, "ref")) atNode = att->value;
			else if (!strcmp(att->name, "attributeName")) atAtt = att->value;
			else if (!strcmp(att->name, "index")) index = atoi(att->value);
		}
		if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
		/*should be a XML IDREF, not an XML IRI*/
		if (atNode[0]=='#') atNode++;

		parser->command->node = svg_find_node(parser, atNode);
		if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node node ref %s for command", atNode);
		if (atAtt) {
			if (!strcmp(atAtt, "children")) {
				field = gf_sg_command_field_new(parser->command);
				field->pos = index;
				field->fieldIndex = 0;
				field->fieldType = 0;
			} else {
				if (gf_node_get_attribute_by_name(parser->command->node, atAtt, parser->current_ns, GF_FALSE, GF_FALSE, &info)==GF_OK) {
					field = gf_sg_command_field_new(parser->command);
					field->pos = index;
					field->fieldIndex = info.fieldIndex;
					field->fieldType = info.fieldType;
				}
			}
		} else if (index>=0) {
			field = gf_sg_command_field_new(parser->command);
			field->pos = index;
		}
		gf_node_register(parser->command->node, NULL);
		return GF_OK;
	case GF_SG_LSR_REPLACE:
		is_replace = GF_TRUE;
	case GF_SG_LSR_ADD:
	case GF_SG_LSR_INSERT:
		for (i=0; i<nb_attributes; i++) {
			GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
			if (!strcmp(att->name, "ref")) atNode = att->value;
			else if (!strcmp(att->name, "operandElementId")) atOperandNode = att->value;
			else if (!strcmp(att->name, "operandAttributeName")) atOperandAtt = att->value;
			else if (!strcmp(att->name, "value")) atValue = att->value;
			else if (!strcmp(att->name, "attributeName")) atAtt = att->value;
			/*replace only*/
			else if (!strcmp(att->name, "index")) index = atoi(att->value);
		}
		if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
		parser->command->node = svg_find_node(parser, atNode);
		if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node node ref %s for command", atNode);
		/*child or node replacement*/
		if ( (is_replace || (parser->command->tag==GF_SG_LSR_INSERT)) && (!atAtt || !strcmp(atAtt, "children")) ) {
			field = gf_sg_command_field_new(parser->command);
			field->pos = index;
			if (atAtt) field->fieldIndex = TAG_LSR_ATT_children;
			gf_node_register(parser->command->node, NULL);
			return GF_OK;
		}
		if (!atAtt) return svg_report(parser, GF_BAD_PARAM, "Missing attribute name for command");
		if (!strcmp(atAtt, "textContent")) {
			field = gf_sg_command_field_new(parser->command);
			field->pos = -1;
			field->fieldIndex = (u32) -1;
			field->fieldType = DOM_String_datatype;
			gf_node_register(parser->command->node, NULL);
			if (atValue) {
				field->field_ptr = gf_svg_create_attribute_value(field->fieldType);
				*(SVG_String *)field->field_ptr = gf_strdup(atValue);
			}
			return GF_OK;
		}
		if (!strcmp(atAtt, "scale") || !strcmp(atAtt, "translation") || !strcmp(atAtt, "rotation")) {
			if (!strcmp(atAtt, "scale")) {
				info.fieldType = SVG_Transform_Scale_datatype;
				info.fieldIndex = TAG_LSR_ATT_scale;
			}
			else if (!strcmp(atAtt, "translation")) {
				info.fieldType = SVG_Transform_Translate_datatype;
				info.fieldIndex = TAG_LSR_ATT_translation;
			}
			else /*if (!strcmp(atAtt, "rotation")) */ {
				info.fieldType = SVG_Transform_Rotate_datatype;
				info.fieldIndex = TAG_LSR_ATT_rotation;
			}
		} else {
			/*FIXME - handle namespace properly here !!*/
			info.fieldIndex = gf_xml_get_attribute_tag(parser->command->node, atAtt, (strchr(atAtt, ':')==NULL) ? parser->current_ns : 0);
			info.fieldType = gf_xml_get_attribute_type(info.fieldIndex);

#ifndef GPAC_DISABLE_LASER
			/*
						if (gf_lsr_anim_type_from_attribute(info.fieldIndex)<0) {
							return svg_report(parser, GF_BAD_PARAM, "Attribute %s of element %s is not updatable\n", atAtt, gf_node_get_class_name(parser->command->node));
						}
			*/
#endif /*GPAC_DISABLE_LASER*/
		}

		opNode = NULL;
		if (atOperandNode) {
			opNode = gf_sg_find_node_by_name(parser->load->scene_graph, atOperandNode);
			if (!opNode) return svg_report(parser, GF_BAD_PARAM, "Cannot find operand element %s for command", atOperandNode);
		}
		if (!atValue && (!atOperandNode || !atOperandAtt) ) return svg_report(parser, GF_BAD_PARAM, "Missing attribute value for command");
		field = gf_sg_command_field_new(parser->command);
		field->pos = index;
		field->fieldIndex = info.fieldIndex;
		field->fieldType = info.fieldType;
		if (atValue) {
			GF_FieldInfo nf;
			nf.fieldType = info.fieldType;
			field->field_ptr = nf.far_ptr = gf_svg_create_attribute_value(info.fieldType);
			if (field->field_ptr) {
				gf_svg_parse_attribute(parser->command->node, &nf, atValue, (u8) info.fieldType);
				if (info.fieldType==XMLRI_datatype)
					svg_process_media_href(parser, parser->command->node, (XMLRI*)field->field_ptr);
			}
		} else if (opNode) {
			parser->command->fromNodeID = gf_node_get_id(opNode);
			/*FIXME - handle namespace properly here !!*/
			parser->command->fromFieldIndex = gf_xml_get_attribute_tag(opNode, atOperandAtt, parser->current_ns);
		}
		gf_node_register(parser->command->node, NULL);
		return GF_OK;
	case GF_SG_LSR_ACTIVATE:
	case GF_SG_LSR_DEACTIVATE:
		for (i=0; i<nb_attributes; i++) {
			GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
			if (!strcmp(att->name, "ref")) atNode = att->value;
		}
		if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
		/*should be a XML IDREF, not an XML IRI*/
		if (atNode[0]=='#') atNode++;
		parser->command->node = svg_find_node(parser, atNode);
		if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node ref %s for command", atNode);
		gf_node_register(parser->command->node, NULL);

		/*switch to V2*/
		svg_lsr_set_v2(parser);

		return GF_OK;
	case GF_SG_LSR_SEND_EVENT:
		for (i=0; i<nb_attributes; i++) {
			GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
			if (!strcmp(att->name, "ref")) atNode = att->value;
			else if (!strcmp(att->name, "event")) atEvent = att->value;
			else if (!strcmp(att->name, "pointvalue")) atPoint = att->value;
			else if (!strcmp(att->name, "intvalue")) atInteger = att->value;
			else if (!strcmp(att->name, "stringvalue")) atString = att->value;
		}

		if (!atEvent) return svg_report(parser, GF_BAD_PARAM, "Missing event name for command");
		if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
		/*should be a XML IDREF, not an XML IRI*/
		if (atNode[0]=='#') atNode++;
		parser->command->node = svg_find_node(parser, atNode);
		if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node node ref %s for command", atNode);
		gf_node_register(parser->command->node, NULL);

		parser->command->send_event_name = gf_dom_event_type_by_name(atEvent);

		parser->command->send_event_integer = 0;
		if (atString) {
			u32 key = gf_dom_get_key_type(atString);
			if (key == GF_KEY_UNIDENTIFIED) {
				parser->command->send_event_string = gf_strdup(atString);
			} else {
				parser->command->send_event_integer = key;
			}
		}
		if (atInteger) parser->command->send_event_integer = atoi(atInteger);
		if (atPoint) {
			SVG_Point pt;
			svg_parse_point(&pt, atPoint);
			parser->command->send_event_x = FIX2INT(pt.x);
			parser->command->send_event_y = FIX2INT(pt.y);
		}
		return GF_OK;
	default:
		return GF_NOT_SUPPORTED;
	}
}