/// <summary> /// Установить содержимое блока. /// </summary> /// <param name="element">Xml-элемент.</param> /// <param name="configSettingsParser">Настройки конфига.</param> /// <param name="nodesToRemove">Узлы для последующего удаления.</param> private void SetBlockContent(XElement element, ConfigSettingsParser configSettingsParser, List <XNode> nodesToRemove) { string blockContent = null; foreach (var node in element.Nodes()) { if (node is XComment commentNode) { var comment = commentNode.Value.Trim(); if (comment.Length > 3 && comment.StartsWith("{~", StringComparison.Ordinal) && comment.EndsWith("}", StringComparison.Ordinal)) { var blockName = comment.Substring(2, comment.Length - 3); blockContent = configSettingsParser.GetBlockContent(blockName); } else { blockContent = null; } } else if (node is XElement elementNode) { if (!string.IsNullOrEmpty(blockContent)) { nodesToRemove.AddRange(elementNode.Nodes()); foreach (var subNode in this.ParseElement(blockContent, elementNode).Nodes()) { elementNode.Add(subNode); } blockContent = null; } this.SetBlockContent(elementNode, configSettingsParser, nodesToRemove); } } }
/// <summary> /// Применить настройки к элементу. /// </summary> /// <param name="element">XML элемент.</param> /// <param name="configSettingsParser">Парсер настроек.</param> /// <param name="isAncestorSetter">Установлено в предке.</param> public override void Apply(XElement element, ConfigSettingsParser configSettingsParser, bool isAncestorSetter) { if (isAncestorSetter) { return; } var textNode = element.Nodes().OfType <XText>().FirstOrDefault(node => !string.IsNullOrWhiteSpace(node.Value)) ?? element.Nodes().OfType <XText>().FirstOrDefault(); if (textNode == null) { textNode = new XText(string.Empty); element.Add(textNode); } var textValue = textNode.Value; var result = this.EvaluateValue(textValue, configSettingsParser); if (result != null) { var leftWhitespace = textValue.Substring(0, textValue.Length - textValue.TrimStart().Length); var rightWhitespace = textValue.Substring(textValue.TrimEnd().Length); textNode.Value = leftWhitespace + result + rightWhitespace; } }
/// <summary> /// Применить настройки доступности блоков. /// </summary> /// <param name="configSettingsParser">Настройки конфига.</param> public void ApplyAccess(ConfigSettingsParser configSettingsParser) { this.Apply(this.EnableBlocks, configSettingsParser); this.Apply(this.DisableBlocks, configSettingsParser); if (configSettingsParser.HasContentBlocks) { this.Apply(this.SetBlockContent, configSettingsParser); } }
/// <summary> /// Получить фактическое значение аргумента. /// </summary> /// <param name="argumentExpression">Строка с выражением-аргументом.</param> /// <param name="configSettingsParser">Настройки конфига.</param> /// <returns>Фактическое значение аргумента.</returns> private string GetActualArgumentValue(string argumentExpression, ConfigSettingsParser configSettingsParser) { if (argumentExpression.StartsWith(FunctionPrefix, StringComparison.Ordinal)) { return(new ExpressionEvaluator(argumentExpression).EvaluateValue(string.Empty, configSettingsParser)); } if (argumentExpression.Length >= 2 && argumentExpression[0] == '"' && argumentExpression[argumentExpression.Length - 1] == '"') { return(argumentExpression.Substring(1, argumentExpression.Length - 2)); } return(configSettingsParser.HasVariable(argumentExpression) ? configSettingsParser.GetVariableValue(argumentExpression) : null); }
/// <inheritdoc /> public override void Apply(XElement element, ConfigSettingsParser configSettingsParser, bool isAncestorSetter) { if (!this.IsElelementSuitable(element, isAncestorSetter)) { return; } var isExistingAttribute = element.Attribute(this.AttributeName) != null; var attributeValue = isExistingAttribute ? element.Attribute(this.AttributeName).Value : string.Empty; var result = this.EvaluateValue(attributeValue, configSettingsParser); if (result != null) { element.SetAttributeValue(this.AttributeName, result != "_REMOVE_" ? result : null); } }
/// <summary> /// Получить фактическое значение для установки. /// </summary> /// <param name="currentValue">Текущее значение.</param> /// <param name="configSettingsParser">Настройки конфига.</param> /// <returns>Фактическое (новое) значение.</returns> public string EvaluateValue(string currentValue, ConfigSettingsParser configSettingsParser) { if (string.IsNullOrEmpty(this.FunctionName)) { return(null); } var actualArgumentsValues = this.FunctionArguments.Select(arg => this.GetActualArgumentValue(arg, configSettingsParser)).ToArray(); if (actualArgumentsValues.Any(v => v == null)) { return(null); } if (this.FunctionName == IdentityFunctionName) { return(actualArgumentsValues[0]); } if (this.FunctionName == "if-not-empty" && actualArgumentsValues.Length == 1) { return(string.IsNullOrWhiteSpace(actualArgumentsValues[0]) ? null : actualArgumentsValues[0]); } if (this.FunctionName == "replace" && actualArgumentsValues.Length == 2) { return(currentValue.Replace(actualArgumentsValues[0], actualArgumentsValues[1])); } if (this.FunctionName == "replace-if" && actualArgumentsValues.Length == 3 && actualArgumentsValues[0].ToUpperInvariant() == "TRUE") { return(currentValue.Replace(actualArgumentsValues[1], actualArgumentsValues[2])); } if (this.FunctionName == "replace-if-not" && actualArgumentsValues.Length == 3 && actualArgumentsValues[0].ToUpperInvariant() != "TRUE") { return(currentValue.Replace(actualArgumentsValues[1], actualArgumentsValues[2])); } if (this.FunctionName == "concat") { return(string.Join(string.Empty, actualArgumentsValues)); } if (this.FunctionName == "equals" && actualArgumentsValues.Length == 2) { return(string.Equals(actualArgumentsValues[0], actualArgumentsValues[1], StringComparison.OrdinalIgnoreCase) ? "true" : "false"); } if (this.FunctionName == "not" && actualArgumentsValues.Length == 1) { return(string.Equals(actualArgumentsValues[0], "false", StringComparison.OrdinalIgnoreCase) ? "true" : "false"); } return(null); }
/// <summary> /// Сделать блоки xml-элемента доступными (раскомментировать элементы). /// </summary> /// <param name="element">Xml-элемент.</param> /// <param name="configSettingsParser">Настройки конфига.</param> /// <param name="nodesToRemove">Узлы для последующего удаления.</param> private void EnableBlocks(XElement element, ConfigSettingsParser configSettingsParser, List <XNode> nodesToRemove) { var needEnableBlock = false; foreach (var node in element.Nodes()) { var commentNode = node as XComment; var elementNode = node as XElement; if (commentNode != null) { var comment = commentNode.Value.Trim(); if (comment.Length > 3 && comment.StartsWith("{~", StringComparison.Ordinal) && comment.EndsWith("}", StringComparison.Ordinal)) { var blockName = comment.Substring(2, comment.Length - 3); var negateEnabled = this.IsNegatedBlockName(ref blockName); var blockEnabled = configSettingsParser.IsBlockEnabled(blockName); if (negateEnabled) { blockEnabled = !blockEnabled; } if (blockEnabled) { needEnableBlock = true; } } else { if (needEnableBlock) { var newBlock = this.ParseElement(comment, element); node.AddAfterSelf(newBlock); nodesToRemove.Add(node); needEnableBlock = false; } } } else if (elementNode != null) { needEnableBlock = false; this.EnableBlocks(elementNode, configSettingsParser, nodesToRemove); } } }
/// <summary> /// Конструктор. /// </summary> /// <param name="config">Xml-конфиг.</param> /// <param name="configSettingsParser">Настройки конфига.</param> public ConfigPatch(XDocument config, ConfigSettingsParser configSettingsParser) { this.config = config; this.configSettingsParser = configSettingsParser; }
/// <summary> /// Применить настройки доступности блоков. /// </summary> /// <param name="action">Действие для управления доступностью.</param> /// <param name="configSettingsParser">Настройки конфига.</param> private void Apply(Action <XElement, ConfigSettingsParser, List <XNode> > action, ConfigSettingsParser configSettingsParser) { var nodesToRemove = new List <XNode>(); action(this.config.Root, configSettingsParser, nodesToRemove); foreach (var node in nodesToRemove) { node.Remove(); } }
/// <summary> /// Применить установку значения к переданному xml-элементу. /// </summary> /// <param name="element">Xml-элемент.</param> /// <param name="configSettingsParser">Настройки конфига.</param> /// <param name="isAncestorSetter">Признак, что правило установки является унаследованным (с предыдущих уровней xml-документа).</param> public abstract void Apply(XElement element, ConfigSettingsParser configSettingsParser, bool isAncestorSetter);
/// <summary> /// Получить фактическое значение для установки. /// </summary> /// <param name="currentValue">Текущее значение.</param> /// <param name="configSettingsParser">Настройки конфига.</param> /// <returns>Фактическое (новое) значение.</returns> public string EvaluateValue(string currentValue, ConfigSettingsParser configSettingsParser) { return(this.expressionEvaluator.EvaluateValue(currentValue, configSettingsParser)); }