예제 #1
0
        public string Resolve(string stringToResolve, IEntityBase dataSource)
        {
            StringBuilder resolved = new StringBuilder();
            int           index    = 0;

            while (index != stringToResolve.Length - 1)
            {
                Match sequenceFound = controlSequenceFinder.Match(stringToResolve, index);
                if (!sequenceFound.Success)
                {
                    break;
                }

                resolved.Append(ResolveTemplateContent(stringToResolve.Substring(index, sequenceFound.Index - index)));

                string controlSequence = sequenceFound.Groups["expression"].Value;
                string startTag        = $"$([{controlSequence}]";
                string endTag          = $"$([end-{controlSequence}])";
                int    length          = sequenceFound.Length;
                index = sequenceFound.Index;
                int nestedSequences =
                    Count(stringToResolve.Substring(index + startTag.Length, length - startTag.Length), startTag);
                int endIndex = index + length;
                while (nestedSequences > 0)
                {
                    int newEnd = stringToResolve.Substring(endIndex)
                                 .IndexOf(endTag, StringComparison.OrdinalIgnoreCase);
                    if (newEnd < 0)
                    {
                        throw new ControlSequenceEndTagNotFoundException(controlSequence);
                    }

                    newEnd = endIndex + newEnd;

                    //Find nested tags between last end tag and this end tag
                    nestedSequences += Count(stringToResolve.Substring(endIndex, newEnd - endIndex), startTag);
                    nestedSequences--;
                    endIndex = newEnd + endTag.Length;
                }

                Match controlSequenceDataMatch = greedyContentFinder.Match(stringToResolve, index, endIndex - index);
                if (!controlSequenceDataMatch.Success)
                {
                    throw new InvalidOperationException("Should not happen");
                }

                resolved.Append(ResolveControlSequence(controlSequenceDataMatch.Groups["expression"].Value,
                                                       controlSequenceDataMatch.Groups["parameter"].Value,
                                                       controlSequenceDataMatch.Groups["content"].Value));
                if (controlSequenceDataMatch.Value.Contains('\n'))
                {
                    Match newlineMatch = newlineSearcher.Match(stringToResolve, endIndex);
                    if (newlineMatch.Success && newlineMatch.Index == endIndex)
                    {
                        endIndex += newlineMatch.Length;
                    }
                }

                index = endIndex;
            }

            resolved.Append(ResolveTemplateContent(stringToResolve.Substring(index)));
            return(resolved.ToString());

            string ResolveControlSequence(string sequence, string parameter, string content)
            {
                switch (sequence.ToUpperInvariant())
                {
                case "IF-EXIST":
                    return(IfSequence(IfExistCondition));

                case "IF-SPECIFIED":
                    return(IfSequence(IfSpecifiedCondition));

                case "FOREACH":
                    return(ForeachSequence());

                case "NO-DUPLICATE-LINES":
                    return(RemoveDuplicateLinesSequence());

                default:
                    throw new UnrecognizedControlSequenceException(sequence);
                }

                string RemoveDuplicateLinesSequence()
                {
                    if (!string.IsNullOrEmpty(parameter))
                    {
                        throw new NoDuplicateLinesParameterMismatchException();
                    }

                    string[] lines = (Resolve(content, dataSource)).Split(new[] { '\r', '\n' },
                                                                          StringSplitOptions.RemoveEmptyEntries);
                    return(string.Join(Environment.NewLine, lines.Distinct()) + Environment.NewLine);
                }

                string IfSequence(Func <bool> conditionCheck)
                {
                    if (string.IsNullOrEmpty(parameter))
                    {
                        throw new IfSequenceParameterMismatchException();
                    }

                    bool condition = conditionCheck();

                    return(IfResult(condition));
                }

                bool IfExistCondition()
                {
                    CommandDefinition definition = dataSource.Value <CommandDefinition>();
                    Argument          argument   = definition?.Argument <Argument>(parameter);

                    return(argument != null ||
                           dataSource.HasContent(parameter));
                }

                bool IfSpecifiedCondition()
                {
                    CommandDefinition definition = dataSource.Value <CommandDefinition>();
                    Argument          argument   = definition?.Argument <Argument>(parameter);
                    bool specified;

                    if (argument != null)
                    {
                        specified = argument.IsDefined;
                    }
                    else
                    {
                        specified = dataSource.HasContent(parameter) &&
                                    !string.IsNullOrEmpty(dataSource[parameter].Value <string>());
                    }

                    return(specified);
                }

                string IfResult(bool condition)
                {
                    string result = string.Empty;

                    string[] elseSplit = content.Split(new[] { "$([else])" }, StringSplitOptions.RemoveEmptyEntries);
                    if (condition)
                    {
                        result = Resolve(elseSplit[0], dataSource);
                    }
                    else if (elseSplit.Length == 2)
                    {
                        result = Resolve(elseSplit[1], dataSource);
                    }

                    return(result);
                }

                string ForeachSequence()
                {
                    StringBuilder foreachResult = new StringBuilder();

                    if ((content.StartsWith("\n", StringComparison.Ordinal) ||
                         content.StartsWith("\r\n", StringComparison.Ordinal)) &&
                        (content.EndsWith("\n", StringComparison.Ordinal) ||
                         content.EndsWith("\r\n", StringComparison.Ordinal)))
                    {
                        //This would leads to unwanted empty lines
                        content = content.TrimStart('\r').TrimStart('\n');
                    }

                    string[] nameSplit = parameter.Split(new[] { "[in]" }, StringSplitOptions.RemoveEmptyEntries);
                    if (nameSplit.Length != 2)
                    {
                        throw new ForeachSequenceParameterMismatchException(parameter);
                    }

                    string elementName = nameSplit[0].Trim();

                    string[] ofTypeSplit =
                        nameSplit[1].Split(new[] { "[of-type]" }, StringSplitOptions.RemoveEmptyEntries);
                    string splitPart = ofTypeSplit.Length == 2 ? ofTypeSplit[1] : ofTypeSplit[0];

                    string[] split      = splitPart.Split(new[] { "[split]" }, StringSplitOptions.RemoveEmptyEntries);
                    string   collection = ofTypeSplit.Length == 2 ? ofTypeSplit[0].Trim() : split[0].Trim();
                    string   filter     = string.Empty;
                    string   splitSize  = split.Length == 2 ? split[1].Trim() : string.Empty;

                    if (!int.TryParse(splitSize, out int chunksize))
                    {
                        chunksize = -1;
                    }
                    if (ofTypeSplit.Length == 2)
                    {
                        filter = split.Length == 2 ? split[0].Trim() : ofTypeSplit[1].Trim();
                    }

                    string[]             path = collection.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                    IEnumerable <Entity> data = ResolveRecursively(path);

                    if (!string.IsNullOrEmpty(filter))
                    {
                        data = data.Where(TemplateEqualsFilter);
                    }

                    ForeachItemContainer container = new ForeachItemContainer(elementName);

                    if (chunksize > 0)
                    {
                        var query = data.Select((entity, idx) => new { idx, entity });
                        IEnumerable <IEnumerable <Entity> > dataChunks = query.GroupBy(x => x.idx / chunksize, a => a.entity);
                        using (dataSource.AddTemporaryDataSource(container))
                            using (dataSource.SkipCaching(elementName))
                            {
                                foreach (IEnumerable <Entity> chunk in dataChunks)
                                {
                                    using (dataSource.SkipCaching(EntityKeys.ChunkStartKey))
                                        using (dataSource.SkipCaching(EntityKeys.ChunkEndKey))
                                        {
                                            string start = data.TakeWhile(x => !x.Equals(chunk.FirstOrDefault())).Count().ToString(CultureInfo.InvariantCulture);
                                            string end   = data.TakeWhile(x => !x.Equals(chunk.LastOrDefault())).Count().ToString(CultureInfo.InvariantCulture);

                                            if (dataSource is Entity)
                                            {
                                                Entity dataSourceEntity = dataSource as Entity;
                                                container.Current = dataSourceEntity.Create(Guid.NewGuid().ToByteString(), chunk);
                                                using (container.Current.AddTemporaryDataSource(new DataChunk(start, end)))
                                                    foreachResult.Append(Resolve(content, dataSource));
                                            }
                                            else
                                            {
                                                throw new FormattableException($"The datasource should be an entity but is of type {dataSource.GetType()}");
                                            }
                                        }
                                }
                            }
                    }
                    else
                    {
                        using (dataSource.AddTemporaryDataSource(container))
                            using (dataSource.SkipCaching(elementName))
                            {
                                foreach (Entity entity in data)
                                {
                                    container.Current = entity;
                                    foreachResult.Append(Resolve(content, dataSource));
                                }
                            }
                    }
                    return(foreachResult.ToString());

                    bool TemplateEqualsFilter(Entity entity)
                    {
                        return(entity.Template().TemplateNames(repository)
                               .Any(n => n.Equals(filter, StringComparison.OrdinalIgnoreCase)));
                    }
                }
            }

            string ResolveTemplateContent(string resolvable)
            {
                string result = resolvable;
                Match  controlSequenceMatch = templateAccessRegex.Match(resolvable);

                while (controlSequenceMatch.Success)
                {
                    string content = controlSequenceMatch.Groups["content"].Value;
                    if (content.StartsWith("[", StringComparison.Ordinal) &&
                        content.EndsWith("]", StringComparison.Ordinal))
                    {
                        throw new WildControlSequenceException(content);
                    }

                    string[] path  = content.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                    string   value = (ResolveRecursively(path)).Value <string>();
                    if (controlSequenceMatch.Groups["text_control"].Success)
                    {
                        string textControlSequence = controlSequenceMatch.Groups["text_control"].Value;
                        textControlSequence = textControlSequence.Substring(0, textControlSequence.Length - 1);
                        value = ResolveTextControlSequences(value, textControlSequence);
                    }
                    result = result.Replace(controlSequenceMatch.Value, value);
                    controlSequenceMatch = controlSequenceMatch.NextMatch();
                }

                return(result);
            }

            IEntityBase ResolveRecursively(string[] path)
            {
                IEntityBase current = dataSource;

                foreach (string part in path)
                {
                    current = current[part];
                    if (current.HasValue <string>())
                    {
                        string value = Resolve(current.Value <string>(), current);
                        current.SetValue(value);
                    }
                }

                return(current);
            }

            int Count(string data, string substring)
            {
                return((data.Length - data.Replace(substring, string.Empty).Length) / substring.Length);
            }
        }
예제 #2
0
 public virtual IDisposable AddTemporaryDataSource <T>(T dataSource)
 {
     return(entityBase.AddTemporaryDataSource(dataSource));
 }