public static PropertyElement BuildElement(XmlNode node, Hashtable types, Hashtable sqltypes, IPropertyContainer entity, bool isReference, ParserValidationDelegate vd)
        {
            PropertyElement field = new PropertyElement();

            if (node.Attributes["name"] != null)
            {
                field.Name = node.Attributes["name"].Value;
            }
            else
            {
                vd(ParserValidationArgs.NewError("Property in " + entity.Name + " has no name."));
            }

            if (isReference && field.Name != "*")
            {
                PropertyElement refProperty = entity.FindFieldByName(field.Name);

                if (refProperty == null)
                {
                    vd(ParserValidationArgs.NewError("Property " + field.Name + " in " + entity.Name + " refers to a property that does not exist."));
                }
                else
                {
                    field = (PropertyElement)(refProperty.Clone());
                }
            }

            if (node.Attributes["column"] != null)
            {
                if (node.Attributes["column"].Value.Equals("*"))
                {
                    field.Column.Name = field.Name;
                }
                else
                {
                    field.Column.Name = node.Attributes["column"].Value;
                }

                // Column only occurs on entity eement.
                SqlEntityElement sqlEntity = ((EntityElement)entity).SqlEntity;
                ColumnElement    column    = sqlEntity.FindColumnByName(field.Column.Name);
                if (column != null)
                {
                    field.Column = (ColumnElement)column.Clone();
                    if (types.Contains(field.Column.SqlType.Type))
                    {
                        field.Type = (TypeElement)((TypeElement)types[field.Column.SqlType.Type]).Clone();
                    }
                    else
                    {
                        vd(ParserValidationArgs.NewError("Type " + field.Column.SqlType.Type + " was not defined [property=" + field.name + "]"));
                    }
                }
                else
                {
                    vd(ParserValidationArgs.NewError("column (" + field.Column.Name + ") specified for property (" + field.Name + ") on entity (" + entity.Name + ") was not found in sql entity (" + sqlEntity.Name + ")"));
                }
            }

            field.Description = node.InnerText.Trim();

            if (node.Attributes["accessmodifier"] != null)
            {
                field.AccessModifier = node.Attributes["accessmodifier"].Value;
            }

            // the concrete type is the *real* type, type can be the same or can be in interface or coersable type
            if (node.Attributes["type"] != null)
            {
                String type         = node.Attributes[TYPE].Value;
                String concreteType = type;
                if (node.Attributes[CONCRETE_TYPE] != null)
                {
                    concreteType = node.Attributes[CONCRETE_TYPE].Value;
                }
                // if the data type is defined, default it as the property and left be overridden
                if (types.Contains(concreteType))
                {
                    field.Type      = (TypeElement)((TypeElement)types[concreteType]).Clone();
                    field.Type.Name = type;
                }
                else
                {
                    vd(ParserValidationArgs.NewError("Type " + concreteType + " was not defined for property " + field.Name + " in " + entity.Name + "."));
                }

                String dataObjectTypeName = concreteType + "Data";
                if (types.Contains(dataObjectTypeName))
                {
                    field.DataObjectType = (TypeElement)((TypeElement)types[dataObjectTypeName]).Clone();
                }
                else
                {
                    field.DataObjectType = field.Type;
                }
            }

            if (node.Attributes["convertfromsqltypeformat"] != null)
            {
                field.Type.ConvertFromSqlTypeFormat = node.Attributes["convertfromsqltypeformat"].Value;
            }
            if (node.Attributes["converttosqltypeformat"] != null)
            {
                field.Type.ConvertToSqlTypeFormat = node.Attributes["converttosqltypeformat"].Value;
            }
            if (node.Attributes[PARAMETER_NAME] != null)
            {
                field.ParameterName = node.Attributes[PARAMETER_NAME].Value;
            }
            if (node.Attributes[EXPRESSION] != null)
            {
                field.Expression = node.Attributes[EXPRESSION].Value;
            }
            if (node.Attributes[GROUP_FUNCTION] != null)
            {
                field.GroupFunction = node.Attributes[GROUP_FUNCTION].Value;
                if (field.GroupFunction.ToLower() != GROUP_FUNCTION_SUM &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_MIN &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_MAX &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_AVG &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_STDEV &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_STDEVP &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_VAR &&
                    field.GroupFunction.ToLower() != GROUP_FUNCTION_VARP)
                {
                    vd(ParserValidationArgs.NewError("Invalid group function specified for entity reference property " + field.Name + " in " + entity.Name));
                }
            }

            if (node.Attributes[GROUP_BY] != null)
            {
                field.GroupBy = Boolean.Parse(node.Attributes[GROUP_BY].Value);
            }
            if (node.Attributes[SQL_TYPE] != null)
            {
                field.Column.SqlType.Name = node.Attributes[SQL_TYPE].Value;
                if (sqltypes.ContainsKey(field.Column.SqlType.Name))
                {
                    field.Column.SqlType = (SqlTypeElement)((SqlTypeElement)sqltypes[field.Column.SqlType.Name]).Clone();
                }
                else
                {
                    vd(ParserValidationArgs.NewError("SqlType " + field.Column.SqlType.Name + " was not defined in " + entity.Name + " for property " + field.Name + "."));
                }
            }
            if (node.Attributes[ALIAS] != null)
            {
                field.Alias = node.Attributes[ALIAS].Value;
            }

            field.container = entity;

            if (node.Attributes["readable"] != null)
            {
                field.Readable = Boolean.Parse(node.Attributes["readable"].Value);
            }
            if (node.Attributes["writable"] != null)
            {
                field.Writable = Boolean.Parse(node.Attributes["writable"].Value);
            }

            if (node.Attributes["derived"] != null)
            {
                field.Derived = Boolean.Parse(node.Attributes["derived"].Value);
            }

            if (node.Attributes["encrypted"] != null)
            {
                field.Encrypted = Boolean.Parse(node.Attributes["encrypted"].Value);
            }

            if (node.Attributes["log"] != null)
            {
                field.DoLog = Boolean.Parse(node.Attributes["log"].Value);
            }

            if (node.Attributes["returnasidentity"] != null)
            {
                field.ReturnAsIdentity = Boolean.Parse(node.Attributes["returnasidentity"].Value);
            }

            if (node.Attributes[DIRECTION] == null)
            {
                field.Direction = ASCENDING;
            }
            else if (node.Attributes["direction"].Value != ASCENDING && node.Attributes["direction"].Value != DESCENDING)
            {
                vd(ParserValidationArgs.NewError("Comparer in entity " + entity.Name + " has direction value other than 'ascending' or 'descending'"));
            }
            else
            {
                field.Direction = node.Attributes[DIRECTION].Value;
            }

            if (node.Attributes[CONVERT_FOR_COMPARE] != null)
            {
                field.Type.ConvertForCompare = node.Attributes[CONVERT_FOR_COMPARE].Value;
            }

            if (node.Attributes[USE_ENTITY_DAO] != null)
            {
                field.UseEntityDao = Boolean.Parse(node.Attributes[USE_ENTITY_DAO].Value);
            }

            if (node.Attributes["entity"] != null)
            {
                field.Entity.Name = node.Attributes["entity"].Value;
            }

            if (node.Attributes["prefix"] != null)
            {
                field.Prefix = node.Attributes["prefix"].Value;
            }
            else
            {
                field.Prefix = field.Entity.Name + "_";
            }

            return(field);
        }
        public static ArrayList ParseFromXml(XmlNode propertiesNode, IList entities, IPropertyContainer entity, Hashtable sqltypes, Hashtable types, bool isReference, ParserValidationDelegate vd)
        {
            ArrayList fields = new ArrayList();

            if (propertiesNode != null)
            {
                foreach (XmlNode node in propertiesNode.ChildNodes)
                {
                    if (node.NodeType == XmlNodeType.Comment)
                    {
                        continue;
                    }
                    PropertyElement field = BuildElement(node, types, sqltypes, entity, isReference, vd);

                    //Adds all attributes including all non defined by element class
                    foreach (XmlAttribute attribute in node.Attributes)
                    {
                        if (!field.Attributes.ContainsKey(attribute.Name))
                        {
                            field.Attributes.Add(attribute.Name, attribute.Value);
                        }
                    }

                    fields.Add(field);

                    // Add in any subfields...
                    if (field.Entity.Name.Length > 0 && !field.UseEntityDao)
                    {
                        String        subEntityName = node.Attributes["entity"].Value;
                        EntityElement subentity     = EntityElement.FindEntityByName((ArrayList)entities, subEntityName);

                        // check to see if subentity is self
                        if (subentity == null && entity.Name == subEntityName)
                        {
                            subentity = (EntityElement)entity;
                        }

                        if (subentity != null)
                        {
                            // Only entity elements have entity atttribute
                            SqlEntityElement sqlEntity = ((EntityElement)entity).SqlEntity;

                            String prefix = subentity.Name + "_";
                            if (node.Attributes["prefix"] != null)
                            {
                                prefix = node.Attributes["prefix"].Value;
                            }

                            foreach (PropertyElement f in subentity.Fields)
                            {
                                PropertyElement subfield = (PropertyElement)f.Clone();
                                subfield.Name = field.Name + "." + subfield.Name;

                                // if field has sql column defined
                                if (!f.Column.Name.Equals(String.Empty))
                                {
                                    ColumnElement column = sqlEntity.FindColumnByName(prefix + subfield.Column.Name);
                                    if (column != null)
                                    {
                                        subfield.Column = (ColumnElement)column.Clone();
                                    }
                                    else
                                    {
                                        vd(ParserValidationArgs.NewError("column (" + prefix + subfield.Column.Name + ") specified for property (" + subfield.Name + ") on entity (" + entity.Name + ") was not found in sql entity (" + sqlEntity.Name + ")"));
                                    }
                                }
                                fields.Add(subfield);
                            }
                        }
                        else
                        {
                            vd(ParserValidationArgs.NewError("Entity " + entity.Name + " referenced another entity that was not defined (or defined below this one): " + node.Attributes["entity"].Value));
                        }
                    }
                }
            }
            return(fields);
        }