public List <EngineResult> Process(string contents, string filename) { var doc = GetXml(contents); IEnumerable <XElement> fileGroups = doc.Descendants("FileGroup").ToList(); if (fileGroups.Count() == 0) { fileGroups = new[] { new XElement("FileGroup", new XAttribute("Path", filename), doc) } } ; return(fileGroups .SelectMany(fileGroup => GetEngineResult(fileGroup, filename)) .ToList()); } IEnumerable <EngineResult> GetEngineResult(XElement fileGroup, string filename) { var result = new EngineResult(); if (fileGroup.Attribute("Path") == null) { result.AddException("FileGroup element requires a Path attribute", filename, ErrorCategory.Error); yield return(result); yield break; } var fileGroupPath = (string)fileGroup.Attribute("Path"); var files = GetFiles(fileGroup) .Select(file => FileHandler.GetAbsoluteFileName(file, filename)) .ToLookup(FileHandler.FileExists); // add a warning for each missing file foreach (var file in files[false]) { result.AddException(string.Format("File does not exist '{0}'", file), filename, ErrorCategory.Warning); } // get the contents of all existing files and join them together var fileGroupContents = string.Join("\n", files[true].Select(file => FileHandler.GetContents(file))); result.FileName = fileGroupPath; result.Contents = fileGroupContents; yield return(result); var engine = EngineResolver.GetEngineByFilename(fileGroupPath); if (engine == null) { yield break; } var engineResults = engine.Process(fileGroupContents, fileGroupPath); foreach (var engineResult in engineResults) { if (string.IsNullOrEmpty(engineResult.FileName)) { engineResult.FileName = fileGroupPath; } yield return(engineResult); } }