private Feature ReadAttribute() { string attributeName = ReadToken(endOfLine: false); string typeString = ReadToken(endOfLine: false, quoting: false); FeatureType attributeType; if (string.Equals(typeString, "integer", StringComparison.OrdinalIgnoreCase)) { attributeType = FeatureType.Integer; ReadToken(endOfLine: true); } else if (string.Equals(typeString, "numeric", StringComparison.OrdinalIgnoreCase) || string.Equals(typeString, "real", StringComparison.OrdinalIgnoreCase)) { attributeType = FeatureType.Numeric; ReadToken(endOfLine: true); } else if (string.Equals(typeString, "string", StringComparison.OrdinalIgnoreCase)) { attributeType = FeatureType.String; ReadToken(endOfLine: true); } else if (string.Equals(typeString, "date", StringComparison.OrdinalIgnoreCase)) { string dateFormat = ReadToken(); if (dateFormat == null) { attributeType = FeatureType.Date(); } else { attributeType = FeatureType.Date(dateFormat); ReadToken(endOfLine: true); } } else if (typeString == "{") { List <string> nominalValues = new List <string>(); while (true) { string value = ReadToken(out bool quoted, endOfLine: false); if (!quoted && value == "}") { break; } else if (!quoted && value == ",") { continue; } else { nominalValues.Add(value); } } attributeType = FeatureType.Nominal(nominalValues); ReadToken(endOfLine: true); } else if (string.Equals(typeString, "relational", StringComparison.OrdinalIgnoreCase)) { ReadToken(endOfLine: true); List <Feature> childAttributes = new List <Feature>(); while (true) { string token = ReadToken(skipEndOfLine: true, endOfLine: false, quoting: false); if (string.Equals(token, "@attribute", StringComparison.OrdinalIgnoreCase)) { Feature attribute = ReadAttribute(); childAttributes.Add(attribute); } else if (string.Equals(token, "@end", StringComparison.OrdinalIgnoreCase)) { ReadToken(expectedToken: attributeName, endOfLine: false); ReadToken(endOfLine: true); break; } else { throw new InvalidDataException($"Unexpected token \"{token}\". Expected \"@attribute\" or \"@end\"."); } } attributeType = FeatureType.Relational(childAttributes); } else { throw new InvalidDataException($"Unexpected token \"{typeString}\". Expected attribute type."); } return(new Feature(attributeName, attributeType)); }