/// <summary>Deserialize by reading element from the tree reader.</summary>
        public static void DeserializeFrom(this IList obj, string elementName, ITreeReader reader)
        {
            // Check if the list is null
            if (obj == null)
            {
                throw new Exception("List passed to DeserializeFrom method for element {elementName} is null.");
            }

            // If the list is not empty, error message because the
            // object must be empty prior to parsing
            if (obj.Count > 0)
            {
                throw new Exception("List passed to DeserializeFrom method for element {elementName} is not empty.");
            }

            // Get item type from list type using reflection
            Type listType = obj.GetType();

            if (!listType.IsGenericType)
            {
                throw new Exception(
                          $"Type {listType} cannot be serialized because it implements only IList but not IList<T>.");
            }
            Type[] genericParameterTypes = listType.GenericTypeArguments;
            if (genericParameterTypes.Length != 1)
            {
                throw new Exception(
                          $"Generic parameter type list {genericParameterTypes} has more than " +
                          $"one element creating an ambiguity for deserialization code.");
            }
            Type itemType = genericParameterTypes[0];

            // Select XML node list with the specified name and iterate over XML nodes
            IEnumerable <ITreeReader> selectedXmlNodes = reader.ReadElements(elementName);

            foreach (ITreeReader selectedXmlNode in selectedXmlNodes)
            {
                if (selectedXmlNode == null)
                {
                    // Add null value
                    obj.Add(null);
                }
                else
                {
                    // Switch on item type
                    if (itemType == typeof(string))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            obj.Add(token);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(double) || itemType == typeof(double?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = double.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(bool) || itemType == typeof(bool?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = bool.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(int) || itemType == typeof(int?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = int.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(long) || itemType == typeof(long?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = long.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(LocalDate) || itemType == typeof(LocalDate?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = LocalDateUtil.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(LocalTime) || itemType == typeof(LocalTime?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = LocalTimeUtil.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(LocalMinute) || itemType == typeof(LocalMinute?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = LocalMinuteUtil.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(LocalDateTime) || itemType == typeof(LocalDateTime?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = LocalDateTimeUtil.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType == typeof(Instant) || itemType == typeof(Instant?))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = InstantUtil.Parse(token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else if (itemType.IsSubclassOf(typeof(Enum)))
                    {
                        string token = selectedXmlNode.ReadValue();
                        if (!string.IsNullOrEmpty(token))
                        {
                            var value = Enum.Parse(itemType, token);
                            obj.Add(value);
                        }
                        else
                        {
                            obj.Add(null);
                        }
                    }
                    else
                    {
                        // If none of the supported atomic types match, use the activator
                        // to create and empty instance of a complex type and populate it
                        var item = Activator.CreateInstance(itemType);
                        switch (item)
                        {
                        case ICollection collectionItem:
                            throw new Exception($"Deserialization is not supported for element {elementName} " +
                                                $"which is collection containing another collection.");

                        case Data dataItem:
                            var keyItem = dataItem as Key;
                            if (keyItem != null)
                            {
                                string token = selectedXmlNode.ReadValue();
                                if (!string.IsNullOrEmpty(token))
                                {
                                    // Parse semicolon delimited token to populate key item
                                    keyItem.PopulateFrom(token);
                                    obj.Add(item);
                                }
                                else
                                {
                                    obj.Add(null);
                                }
                            }
                            else
                            {
                                // Deserialize data item
                                dataItem.DeserializeFrom(selectedXmlNode);
                                obj.Add(item);
                            }
                            break;

                        default:
                            // Error message if the type does not match any of the value or reference types
                            throw new Exception($"Serialization is not supported for type {itemType}.");
                        }
                    }
                }
            }
        }