Example #1
0
        protected virtual string GetText([NotNull] ITextNode textNode)
        {
            var texts = new List <string>();

            var itemName = textNode.GetAttributeValue("name");

            if (!string.IsNullOrEmpty(itemName))
            {
                texts.Add("named '" + itemName + "'");
            }

            var templateName = textNode.GetAttributeValue("template");

            if (!string.IsNullOrEmpty(templateName))
            {
                texts.Add("with template '" + templateName + "'");
            }

            var itemPath = textNode.GetAttributeValue("path");

            if (!string.IsNullOrEmpty(itemPath))
            {
                texts.Add("with path '" + itemPath + "'");
            }

            return(string.Join(" and ", texts));
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var itemIdOrPath = PathHelper.CombineItemPath(context.ParentItemPath, itemNameTextNode.Value);
            var guid = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName = textNode.GetAttributeValue("Database", context.DatabaseName);
            var templateIdOrPathTextNode = textNode.GetAttribute("Template");
            var templateIdOrPath = templateIdOrPathTextNode?.Value ?? string.Empty;

            var item = context.ParseContext.Factory.Item(context.ParseContext.Project, textNode, guid, databaseName, itemNameTextNode.Value, itemIdOrPath, templateIdOrPath);
            item.ItemNameProperty.AddSourceTextNode(itemNameTextNode);
            item.IsEmittable = !string.Equals(textNode.GetAttributeValue(Constants.Fields.IsEmittable), "False", StringComparison.OrdinalIgnoreCase);
            item.IsImport = string.Equals(textNode.GetAttributeValue(Constants.Fields.IsExtern, context.IsExtern.ToString()), "True", StringComparison.OrdinalIgnoreCase);

            if (templateIdOrPathTextNode != null)
            {
                item.TemplateIdOrPathProperty.AddSourceTextNode(templateIdOrPathTextNode);

                if (!item.IsImport)
                {
                    item.References.AddRange(context.ParseContext.ReferenceParser.ParseReferences(item, item.TemplateIdOrPathProperty));
                }
            }

            context.ParseContext.PipelineService.Resolve<ItemParserPipeline>().Execute(context, item, textNode);

            ParseChildNodes(context, item, textNode);

            context.ParseContext.Project.AddOrMerge(item);
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var parentItemPath = textNode.GetAttributeValue("ParentItemPath", context.ParentItemPath);
            var itemIdOrPath = PathHelper.CombineItemPath(parentItemPath, itemNameTextNode.Value);
            var guid = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName = textNode.GetAttributeValue("Database", context.DatabaseName);
            var templateIdOrPath = textNode.Key.UnescapeXmlElementName();

            var item = context.ParseContext.Factory.Item(context.ParseContext.Project, textNode, guid, databaseName, itemNameTextNode.Value, itemIdOrPath, templateIdOrPath);
            item.ItemNameProperty.AddSourceTextNode(itemNameTextNode);
            item.TemplateIdOrPathProperty.AddSourceTextNode(new AttributeNameTextNode(textNode));
            item.IsEmittable = !string.Equals(textNode.GetAttributeValue(Constants.Fields.IsEmittable), "False", StringComparison.OrdinalIgnoreCase);
            item.IsImport = string.Equals(textNode.GetAttributeValue(Constants.Fields.IsExtern, context.IsExtern.ToString()), "True", StringComparison.OrdinalIgnoreCase);

            if (!item.IsImport)
            {
                item.References.AddRange(context.ParseContext.ReferenceParser.ParseReferences(item, item.TemplateIdOrPathProperty));
            }

            var fieldContext = new LanguageVersionContext();
            ParseAttributes(context, item, fieldContext, textNode);

            ParseChildNodes(context, item, textNode);

            context.ParseContext.Project.AddOrMerge(item);
        }
        protected virtual void ParseField([NotNull] ItemParseContext context, [NotNull] Template template, [NotNull] TemplateSection templateSection, [NotNull] ITextNode templateFieldTextNode, ref int nextSortOrder)
        {
            SchemaService.ValidateTextNodeSchema(templateFieldTextNode, "TemplateField");

            GetName(context.ParseContext, templateFieldTextNode, out var fieldName, out var fieldNameTextNode, "Field", "Name");
            if (string.IsNullOrEmpty(fieldName))
            {
                Trace.TraceError(Msg.P1005, Texts._Field__element_must_have_a__Name__attribute, templateFieldTextNode.Snapshot.SourceFile.AbsoluteFileName, templateFieldTextNode.TextSpan);
                return;
            }

            var templateField = templateSection.Fields.FirstOrDefault(f => string.Equals(f.FieldName, fieldName, StringComparison.OrdinalIgnoreCase));

            if (templateField == null)
            {
                var itemIdOrPath = template.ItemIdOrPath + "/" + templateSection.SectionName + "/" + fieldName;
                var guid         = StringHelper.GetGuid(template.Project, templateFieldTextNode.GetAttributeValue("Id", itemIdOrPath));

                templateField = Factory.TemplateField(template, guid).With(templateFieldTextNode);
                templateSection.Fields.Add(templateField);
                templateField.FieldNameProperty.SetValue(fieldNameTextNode);
                templateField.FieldName = fieldName;
            }

            templateField.TypeProperty.Parse(templateFieldTextNode, "Single-Line Text");
            templateField.Shared      = string.Equals(templateFieldTextNode.GetAttributeValue("Sharing"), "Shared", StringComparison.OrdinalIgnoreCase);
            templateField.Unversioned = string.Equals(templateFieldTextNode.GetAttributeValue("Sharing"), "Unversioned", StringComparison.OrdinalIgnoreCase);
            templateField.SourceProperty.Parse(templateFieldTextNode);
            templateField.ShortHelpProperty.Parse(templateFieldTextNode);
            templateField.LongHelpProperty.Parse(templateFieldTextNode);
            templateField.SortorderProperty.Parse(templateFieldTextNode, nextSortOrder);

            nextSortOrder = templateField.Sortorder + 100;

            // set field standard value
            var standardValueTextNode = templateFieldTextNode.GetAttribute("StandardValue");

            if (standardValueTextNode != null && !string.IsNullOrEmpty(standardValueTextNode.Value))
            {
                if (template.StandardValuesItem == null)
                {
                    Trace.TraceError(Msg.P1006, Texts.Template_does_not_a_standard_values_item, standardValueTextNode);
                }
                else
                {
                    var field = template.StandardValuesItem.Fields.GetField(templateField.FieldName);
                    if (field == null)
                    {
                        field = Factory.Field(template.StandardValuesItem).With(standardValueTextNode);
                        field.FieldNameProperty.SetValue(fieldNameTextNode);
                        template.StandardValuesItem.Fields.Add(field);
                    }

                    field.ValueProperty.SetValue(standardValueTextNode);
                }
            }

            template.References.AddRange(ReferenceParser.ParseReferences(template, templateField.SourceProperty));
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var guid = GetGuid(textNode, "ID");

            if (guid == Guid.Empty)
            {
                Trace.TraceError(Msg.P1035, "'ID' attribute is missing or invalid", textNode);
                return;
            }

            var templateGuid = GetGuid(textNode, "Template");

            if (templateGuid == Guid.Empty)
            {
                Trace.TraceError(Msg.P1036, "'Template' attribute is missing or invalid", textNode);
                return;
            }

            var databaseName     = textNode.GetAttributeValue("DB", context.Database.DatabaseName);
            var database         = context.ParseContext.Project.GetDatabase(databaseName);
            var itemIdOrPath     = textNode.GetAttributeValue("Path");
            var itemName         = Path.GetFileName(itemIdOrPath);
            var templateIdOrPath = templateGuid.Format();

            var item = Factory.Item(database, guid, itemName, itemIdOrPath, templateIdOrPath).With(textNode);

            var sharedFieldContext = new LanguageVersionContext();

            ParseFields(item, textNode, sharedFieldContext);

            foreach (var languageNode in textNode.ChildNodes.Where(n => n.Key == "Language"))
            {
                var unversionedFieldContext = new LanguageVersionContext();
                unversionedFieldContext.LanguageProperty.SetValue(languageNode);

                ParseFields(item, languageNode, unversionedFieldContext);

                foreach (var versionNode in languageNode.ChildNodes.Where(n => n.Key == "Version"))
                {
                    if (!int.TryParse(versionNode.Value, out var _))
                    {
                        Trace.TraceError(Msg.P1037, "Version number must be an integer", versionNode);
                        continue;
                    }

                    var versionedFieldContext = new LanguageVersionContext();
                    versionedFieldContext.LanguageProperty.SetValue(languageNode);
                    versionedFieldContext.VersionProperty.SetValue(versionNode);

                    ParseFields(item, versionNode, versionedFieldContext);
                }
            }

            context.ParseContext.Project.AddOrMerge(item);
        }
Example #6
0
        private IEnumerable <IDiagnostic> MatchMinMaxOccurs([NotNull] Item item, [NotNull] ITextNode schemaTextNode, [NotNull, ItemNotNull] ITextNode[] schemaChildNodes, [NotNull, ItemNotNull] Item[] children)
        {
            foreach (var schemaChildNode in schemaChildNodes)
            {
                if (schemaChildNode.Key != "item")
                {
                    throw new InvalidOperationException($"Unexpected node {schemaChildNode.Key} at {schemaChildNode.Snapshot.SourceFile.AbsoluteFileName} {schemaChildNode.TextSpan}");
                }

                // in references, the referring text node may overwrite the referred text nodes

                var minOccurs = 0;
                var maxOccurs = 0;

                if (schemaChildNode.HasAttribute("minOccurs"))
                {
                    minOccurs = int.Parse(schemaChildNode.GetAttributeValue("minOccurs", "0"));
                }

                if (schemaTextNode.HasAttribute("minOccurs"))
                {
                    minOccurs = int.Parse(schemaTextNode.GetAttributeValue("minOccurs", "0"));
                }

                if (schemaChildNode.HasAttribute("maxOccurs"))
                {
                    maxOccurs = int.Parse(schemaChildNode.GetAttributeValue("maxOccurs", "0"));
                }

                if (schemaTextNode.HasAttribute("maxOccurs"))
                {
                    maxOccurs = int.Parse(schemaTextNode.GetAttributeValue("maxOccurs", "0"));
                }

                if (minOccurs <= 0 && maxOccurs <= 0)
                {
                    continue;
                }

                var count = children.Count(child => IsMatch(child, schemaChildNode));

                if (minOccurs > 0 && count < minOccurs)
                {
                    yield return(Factory.Diagnostic(Msg.D1025, item.Snapshot.SourceFile.RelativeFileName, TraceHelper.GetTextNode(item).TextSpan, Severity.Error, $"Item {GetText(schemaChildNode)} must occur at least {minOccurs} times [ArchitectureSchema]"));
                }

                if (maxOccurs > 0 && count > maxOccurs)
                {
                    yield return(Factory.Diagnostic(Msg.D1025, item.Snapshot.SourceFile.RelativeFileName, TraceHelper.GetTextNode(item).TextSpan, Severity.Error, $"Item {GetText(schemaChildNode)} must not occur more than {maxOccurs} times [ArchitectureSchema]"));
                }
            }
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var itemIdOrPath = PathHelper.CombineItemPath(context.ParentItemPath, itemNameTextNode.Value);
            var guid = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName = textNode.GetAttributeValue("Database", context.DatabaseName);

            var template = context.ParseContext.Factory.Template(context.ParseContext.Project, guid, textNode, databaseName, itemNameTextNode.Value, itemIdOrPath);
            template.ItemNameProperty.AddSourceTextNode(itemNameTextNode);
            template.BaseTemplatesProperty.Parse(textNode, Constants.Templates.StandardTemplate);
            template.IconProperty.Parse(textNode);
            template.ShortHelpProperty.Parse(textNode);
            template.LongHelpProperty.Parse(textNode);
            template.IsEmittable = !string.Equals(textNode.GetAttributeValue(Constants.Fields.IsEmittable), "False", StringComparison.OrdinalIgnoreCase);
            template.IsImport = string.Equals(textNode.GetAttributeValue(Constants.Fields.IsExtern, context.IsExtern.ToString()), "True", StringComparison.OrdinalIgnoreCase);

            template.References.AddRange(context.ParseContext.ReferenceParser.ParseReferences(template, template.BaseTemplatesProperty));

            // create standard values item
            var standardValuesItemIdOrPath = itemIdOrPath + "/__Standard Values";
            var standardValuesGuid = StringHelper.GetGuid(context.ParseContext.Project, standardValuesItemIdOrPath);
            var standardValuesItem = context.ParseContext.Factory.Item(context.ParseContext.Project, textNode, standardValuesGuid, databaseName, "__Standard Values", standardValuesItemIdOrPath, itemIdOrPath);
            standardValuesItem.IsImport = template.IsImport;

            // todo: should be Uri
            template.StandardValuesItem = standardValuesItem;

            // parse fields and sections
            var sections = textNode.GetSnapshotLanguageSpecificChildNode("Sections");
            if (sections != null)
            {
                foreach (var sectionTreeNode in sections.ChildNodes)
                {
                    ParseSection(context, template, sectionTreeNode);
                }
            }

            // setup HtmlTemplate
            var htmlFileTextNode = textNode.GetAttribute("Layout.HtmlFile");
            if (htmlFileTextNode != null && !string.IsNullOrEmpty(htmlFileTextNode.Value))
            {
                var field = context.ParseContext.Factory.Field(template.StandardValuesItem, htmlFileTextNode);
                field.FieldNameProperty.SetValue("__Renderings");
                field.ValueProperty.SetValue(htmlFileTextNode.Value);
                field.ValueHintProperty.SetValue("HtmlTemplate");
                template.StandardValuesItem.Fields.Add(field);
            }

            context.ParseContext.Project.AddOrMerge(template);
            context.ParseContext.Project.AddOrMerge(standardValuesItem);
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var itemIdOrPath = PathHelper.CombineItemPath(context.ParentItemPath, itemNameTextNode.Value);
            var guid = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName = textNode.GetAttributeValue("Database", context.DatabaseName);

            var item = context.ParseContext.Factory.Item(context.ParseContext.Project, textNode, guid, databaseName, itemNameTextNode.Value, itemIdOrPath, string.Empty);
            item.ItemNameProperty.AddSourceTextNode(itemNameTextNode);

            Parse(context, textNode, item);

            context.ParseContext.Project.AddOrMerge(item);
        }
        protected virtual void WritePlaceholder([NotNull] LayoutCompileContext context, [NotNull] XmlWriter output, [NotNull, ItemNotNull] IEnumerable <Item> renderingItems, [NotNull] ITextNode placeholderTextNode)
        {
            var placeholderName = placeholderTextNode.Key;

            if (string.Equals(placeholderName, "Placeholder", StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(placeholderName))
            {
                placeholderName = placeholderTextNode.Value;
            }

            if (string.IsNullOrEmpty(placeholderName))
            {
                placeholderName = placeholderTextNode.GetAttributeValue("Placeholder");
            }

            if (string.IsNullOrEmpty(placeholderName))
            {
                Trace.TraceError(Msg.C1129, "Placeholder name missing", placeholderTextNode);
                return;
            }

            if (!placeholderTextNode.ChildNodes.Any())
            {
                Trace.TraceWarning(Msg.C1131, "Placeholder contains no renderings", placeholderTextNode, placeholderName);
                return;
            }

            foreach (var renderingTextNode in placeholderTextNode.ChildNodes)
            {
                WriteRendering(context, output, renderingItems, placeholderName, renderingTextNode);
            }
        }
Example #10
0
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            SchemaService.ValidateTextNodeSchema(textNode, "Item");

            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var parentItemPath   = textNode.GetAttributeValue("ParentItemPath", context.ParentItemPath);
            var itemIdOrPath     = textNode.GetAttributeValue("ItemPath");

            if (string.IsNullOrEmpty(itemIdOrPath))
            {
                itemIdOrPath = PathHelper.CombineItemPath(parentItemPath, itemNameTextNode.Value);
            }
            else if (itemNameTextNode.Value != Path.GetFileName(itemIdOrPath))
            {
                Trace.TraceError(Msg.P1027, "Item name in 'ItemPath' and 'Name' does not match. Using 'Name'");
            }

            var guid             = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName     = textNode.GetAttributeValue("Database", context.Database.DatabaseName);
            var database         = context.ParseContext.Project.GetDatabase(databaseName);
            var templateIdOrPath = textNode.GetAttributeValue("TemplateName", textNode.Key.UnescapeXmlElementName());

            var item = Factory.Item(database, guid, itemNameTextNode.Value, itemIdOrPath, templateIdOrPath).With(textNode);

            item.ItemNameProperty.AddSourceTextNode(itemNameTextNode);
            item.TemplateIdOrPathProperty.AddSourceTextNode(new AttributeNameTextNode(textNode));
            item.SortorderProperty.Parse(textNode, context.Sortorder);
            item.IsEmittable = textNode.GetAttributeBool(Constants.Fields.IsEmittable, true);
            item.IsImport    = textNode.GetAttributeBool(Constants.Fields.IsImport, context.IsImport);

            if (!item.IsImport)
            {
                item.References.AddRange(ReferenceParser.ParseReferences(item, item.TemplateIdOrPathProperty));
            }

            // parse shared fields
            var fieldContext = new LanguageVersionContext();

            ParseAttributes(context, item, fieldContext, textNode);

            // parse Fields, Layout and Items child text nodes
            ParseChildNodes(context, item, textNode);

            context.ParseContext.Project.AddOrMerge(item);
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var itemIdOrPath = PathHelper.CombineItemPath(context.ParentItemPath, itemNameTextNode.Value);
            var guid = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName = textNode.GetAttributeValue("Database", context.DatabaseName);

            var template = context.ParseContext.Factory.Template(context.ParseContext.Project, guid, textNode, databaseName, itemNameTextNode.Value, itemIdOrPath);
            template.ItemNameProperty.AddSourceTextNode(itemNameTextNode);
            template.BaseTemplatesProperty.Parse(textNode, Constants.Templates.StandardTemplate);
            template.IconProperty.Parse(textNode);
            template.ShortHelpProperty.Parse(textNode);
            template.LongHelpProperty.Parse(textNode);
            // todo: yuck
            template.IsEmittable = !string.Equals(textNode.GetAttributeValue(Constants.Fields.IsEmittable), "False", StringComparison.OrdinalIgnoreCase);
            template.IsImport = string.Equals(textNode.GetAttributeValue(Constants.Fields.IsImport, context.IsImport.ToString()), "True", StringComparison.OrdinalIgnoreCase);

            template.References.AddRange(context.ParseContext.ReferenceParser.ParseReferences(template, template.BaseTemplatesProperty));

            // create standard values item
            var standardValuesItemIdOrPath = itemIdOrPath + "/__Standard Values";
            var standardValuesGuid = StringHelper.GetGuid(context.ParseContext.Project, standardValuesItemIdOrPath);
            var standardValuesItem = context.ParseContext.Factory.Item(context.ParseContext.Project, textNode, standardValuesGuid, databaseName, "__Standard Values", standardValuesItemIdOrPath, itemIdOrPath);
            standardValuesItem.IsImport = template.IsImport;

            // todo: should be Uri
            template.StandardValuesItem = standardValuesItem;

            // parse fields and sections
            var sections = textNode.GetSnapshotLanguageSpecificChildNode("Sections");
            if (sections != null)
            {
                foreach (var sectionTreeNode in sections.ChildNodes)
                {
                    ParseSection(context, template, sectionTreeNode);
                }
            }

            context.ParseContext.PipelineService.Resolve<TemplateParserPipeline>().Execute(context, template, textNode);

            context.ParseContext.Project.AddOrMerge(template);
            context.ParseContext.Project.AddOrMerge(standardValuesItem);
        }
        public static bool GetAttributeBool([NotNull] this ITextNode textNode, [NotNull] string attributeName, bool defaultValue = false)
        {
            if (!textNode.HasAttribute(attributeName))
            {
                return(defaultValue);
            }

            var value = textNode.GetAttributeValue(attributeName);

            return(string.Equals(value, "true", StringComparison.OrdinalIgnoreCase));
        }
Example #13
0
        protected virtual bool IsMatch([NotNull] Item item, [NotNull] ITextNode textNode)
        {
            var isMatch = true;

            var itemName = textNode.GetAttributeValue("name");

            if (!string.IsNullOrEmpty(itemName))
            {
                if (!string.Equals(itemName, item.ItemName, StringComparison.OrdinalIgnoreCase))
                {
                    isMatch = false;
                }
            }

            var templateName = textNode.GetAttributeValue("template");

            if (!string.IsNullOrEmpty(templateName))
            {
                if (!string.Equals(templateName, item.TemplateName, StringComparison.OrdinalIgnoreCase))
                {
                    isMatch = false;
                }
            }

            var itemPath = textNode.GetAttributeValue("path");

            if (!string.IsNullOrEmpty(itemPath))
            {
                if (!string.Equals(itemPath, item.ItemIdOrPath, StringComparison.OrdinalIgnoreCase))
                {
                    isMatch = false;
                }
            }

            return(isMatch);
        }
        public override IEnumerable<ITextNode> Parse(SnapshotParseContext snapshotParseContext, ITextNode textNode)
        {
            var key = textNode.GetAttributeValue("Key");
            if (string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(textNode.Value))
            {
                key = textNode.Value;
            }

            if (string.IsNullOrEmpty(key))
            {
                key = string.Empty;
            }

            List<ITextNode> textNodes;
            return snapshotParseContext.PlaceholderTextNodes.TryGetValue(key, out textNodes) ? textNodes : Enumerable.Empty<ITextNode>();
        }
Example #15
0
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var itemIdOrPath     = PathHelper.CombineItemPath(context.ParentItemPath, itemNameTextNode.Value);
            var guid             = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName     = textNode.GetAttributeValue("Database", context.Database.DatabaseName);
            var database         = context.ParseContext.Project.GetDatabase(databaseName);

            var item = Factory.Item(database, guid, itemNameTextNode.Value, itemIdOrPath, string.Empty).With(textNode);

            item.ItemNameProperty.AddSourceTextNode(itemNameTextNode);

            Parse(context, textNode, item);

            context.ParseContext.Project.AddOrMerge(item);
        }
        protected virtual void WriteDataSource([NotNull] LayoutCompileContext context, [NotNull] XmlWriter output, [NotNull] ITextNode renderingTextNode)
        {
            var dataSource = renderingTextNode.GetAttributeValue("DataSource");

            if (string.IsNullOrEmpty(dataSource))
            {
                return;
            }

            var item = context.Project.Indexes.FindQualifiedItem <IProjectItem>(dataSource);

            if (item == null)
            {
                Trace.TraceError(Msg.C1028, Texts.Datasource_not_found, dataSource);
                return;
            }

            output.WriteAttributeString("ds", item.Uri.Guid.Format());
        }
        protected virtual void ParseSection([NotNull] ItemParseContext context, [NotNull] Template template, [NotNull] ITextNode templateSectionTextNode)
        {
            if (string.Equals(templateSectionTextNode.Value, "__Standard Values", StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            SchemaService.ValidateTextNodeSchema(templateSectionTextNode, "TemplateSection");

            GetName(context.ParseContext, templateSectionTextNode, out var sectionName, out var sectionNameTextNode, "Section", "Name");
            if (string.IsNullOrEmpty(sectionName))
            {
                Trace.TraceError(Msg.P1007, Texts._Section__element_must_have_a__Name__attribute, sectionNameTextNode);
                return;
            }

            var templateSection = template.Sections.FirstOrDefault(s => string.Equals(s.SectionName, sectionName, StringComparison.OrdinalIgnoreCase));

            if (templateSection == null)
            {
                var itemIdOrPath = template.ItemIdOrPath + "/" + sectionName;
                var guid         = StringHelper.GetGuid(template.Project, templateSectionTextNode.GetAttributeValue("Id", itemIdOrPath));

                templateSection = Factory.TemplateSection(template, guid).With(templateSectionTextNode);
                templateSection.SectionNameProperty.SetValue(sectionNameTextNode);
                templateSection.SectionName = sectionName;

                template.Sections.Add(templateSection);
            }

            templateSection.IconProperty.Parse(templateSectionTextNode);

            var nextSortOrder = 0;

            foreach (var fieldTextNode in templateSectionTextNode.ChildNodes)
            {
                ParseField(context, template, templateSection, fieldTextNode, ref nextSortOrder);
            }
        }
        protected virtual void WriteBool([NotNull] LayoutCompileContext context, [NotNull] XmlWriter output, [NotNull] ITextNode renderingTextNode, [NotNull] string id, [NotNull] string attributeName, [NotNull] string name, bool ignoreValue = false)
        {
            var value = renderingTextNode.GetAttributeValue(attributeName);

            if (string.IsNullOrEmpty(value))
            {
                return;
            }

            if (value != "True" && value != "False")
            {
                Trace.TraceError(Msg.C1030, id + Texts.__Boolean_parameter_must_have_value__True__or__False_, renderingTextNode, attributeName);
                value = "False";
            }

            var b = string.Equals(value, "True", StringComparison.OrdinalIgnoreCase);

            if (b == ignoreValue)
            {
                return;
            }

            output.WriteAttributeString(name, b ? "1" : "0");
        }
        public override IEnumerable<ITextNode> Parse(SnapshotParseContext snapshotParseContext, ITextNode textNode)
        {
            var mutableTextNode = textNode as IMutableTextNode;
            if (mutableTextNode == null)
            {
                throw new InvalidOperationException("Text node cannot be modified");
            }

            var textNodes = new List<ITextNode>();

            if (!textNode.Attributes.Any() && textNode.ChildNodes.Any())
            {
                foreach (var childNode in textNode.ChildNodes)
                {
                    var collection = Parse(snapshotParseContext, childNode);
                    if (collection != null)
                    {
                        textNodes.AddRange(collection);
                    }
                }

                return textNodes;
            }

            var fileName = textNode.GetAttributeValue("File");
            if (string.IsNullOrEmpty(fileName) && !string.IsNullOrEmpty(textNode.Value))
            {
                fileName = textNode.Value;
            }

            if (string.IsNullOrEmpty(fileName))
            {
                throw new InvalidOperationException("'File' attribute expected");
            }

            // todo: enable this check
            /*
            if (!string.Equals(Path.GetExtension(fileName), Path.GetExtension(textNode.Snapshot.SourceFile.AbsoluteFileName), StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("Include file has a different format (Json/Xml/Yaml)");
            }
            */

            var placeholderTextNodes = new Dictionary<string, List<ITextNode>>(snapshotParseContext.PlaceholderTextNodes);

            var placeholdersTextNode = textNode.GetSnapshotLanguageSpecificChildNode("Placeholders");
            if (placeholdersTextNode != null)
            {
                foreach (var childNode in placeholdersTextNode.ChildNodes)
                {
                    var placeholderKey = childNode.GetAttributeValue("Key");
                    placeholderTextNodes[placeholderKey] = childNode.ChildNodes.ToList();
                }
            }

            mutableTextNode.ChildNodeCollection.Clear();

            var tokens = new Dictionary<string, string>(snapshotParseContext.Tokens).AddRange(textNode.Attributes.ToDictionary(a => a.Key, a => a.Value));
            var context = new SnapshotParseContext(snapshotParseContext.SnapshotService, tokens, placeholderTextNodes);

            textNodes.Add(snapshotParseContext.SnapshotService.LoadIncludeFile(context, textNode.Snapshot, fileName));

            return textNodes;
        }
        private Guid GetGuid([NotNull] ITextNode textNode, [NotNull] string attributeName)
        {
            var value = textNode.GetAttributeValue(attributeName);

            return(string.IsNullOrEmpty(value) ? Guid.Empty : GetGuid(value));
        }
        public override void Parse(ItemParseContext context, ITextNode textNode)
        {
            SchemaService.ValidateTextNodeSchema(textNode, "Template");

            var itemNameTextNode = GetItemNameTextNode(context.ParseContext, textNode);
            var parentItemPath   = textNode.GetAttributeValue("ParentItemPath", context.ParentItemPath);
            var itemIdOrPath     = textNode.GetAttributeValue("ItemPath");

            if (string.IsNullOrEmpty(itemIdOrPath))
            {
                itemIdOrPath = PathHelper.CombineItemPath(parentItemPath, itemNameTextNode.Value);
            }
            else if (itemNameTextNode.Value != Path.GetFileName(itemIdOrPath))
            {
                Trace.TraceError(Msg.P1034, "Item name in 'ItemPath' and 'Name' does not match. Using 'Name'");
            }

            var guid         = StringHelper.GetGuid(context.ParseContext.Project, textNode.GetAttributeValue("Id", itemIdOrPath));
            var databaseName = textNode.GetAttributeValue("Database", context.Database.DatabaseName);
            var database     = context.ParseContext.Project.GetDatabase(databaseName);

            var template = Factory.Template(database, guid, itemNameTextNode.Value, itemIdOrPath);

            template.ItemNameProperty.AddSourceTextNode(itemNameTextNode);
            template.BaseTemplatesProperty.Parse(textNode, Constants.Templates.StandardTemplateId);
            template.IconProperty.Parse(textNode);
            template.ShortHelpProperty.Parse(textNode);
            template.LongHelpProperty.Parse(textNode);

            template.IsEmittable = textNode.GetAttributeBool(Constants.Fields.IsEmittable, true);
            template.IsImport    = textNode.GetAttributeBool(Constants.Fields.IsImport, context.IsImport);

            template.References.AddRange(ReferenceParser.ParseReferences(template, template.BaseTemplatesProperty));

            Item standardValuesItem;
            var  standardValuesTextNode = textNode.ChildNodes.FirstOrDefault(n => string.Equals(n.Value, "__Standard Values", StringComparison.OrdinalIgnoreCase));

            if (standardValuesTextNode != null)
            {
                var newContext = Factory.ItemParseContext(context.ParseContext, context.Parser, template.Database, template.ItemIdOrPath, template.IsImport);
                context.Parser.ParseTextNode(newContext, standardValuesTextNode);
                standardValuesItem = template.Database.GetItem(template.ItemIdOrPath + "/__Standard Values");

                if (standardValuesItem == null)
                {
                    Trace.TraceError(Msg.C1137, "'__Standard Values' item not parsed correctly", standardValuesTextNode);
                }
            }
            else
            {
                // create standard values item
                var standardValuesItemIdOrPath = itemIdOrPath + "/__Standard Values";
                var standardValuesGuid         = StringHelper.GetGuid(context.ParseContext.Project, standardValuesItemIdOrPath);
                standardValuesItem = Factory.Item(database, standardValuesGuid, "__Standard Values", standardValuesItemIdOrPath, itemIdOrPath).With(textNode);
                context.ParseContext.Project.AddOrMerge(standardValuesItem);
            }

            if (standardValuesItem != null)
            {
                // todo: should be Uri
                template.StandardValuesItem = standardValuesItem;
                standardValuesItem.IsImport = template.IsImport;
            }

            // parse fields and sections
            foreach (var sectionTreeNode in textNode.ChildNodes)
            {
                ParseSection(context, template, sectionTreeNode);
            }

            Pipelines.GetPipeline <TemplateParserPipeline>().Execute(context, template, textNode);

            context.ParseContext.Project.AddOrMerge(template);
        }
        protected virtual void WriteRendering([NotNull] LayoutCompileContext context, [NotNull] XmlWriter output, [NotNull, ItemNotNull] IEnumerable <Item> renderingItems, [NotNull] string placeholderName, [NotNull] ITextNode renderingTextNode)
        {
            string renderingItemId;

            if (renderingTextNode.Key == "r")
            {
                renderingItemId = renderingTextNode.GetAttributeValue("id");
            }
            else if (string.Equals(renderingTextNode.Key, "Rendering", StringComparison.OrdinalIgnoreCase))
            {
                renderingItemId = renderingTextNode.Value;
                if (string.IsNullOrEmpty(renderingItemId))
                {
                    renderingItemId = renderingTextNode.GetAttributeValue("Name");
                }
            }
            else
            {
                renderingItemId = renderingTextNode.Key.UnescapeXmlElementName();
            }

            var id = renderingTextNode.GetAttributeValue("Id");

            if (string.IsNullOrEmpty(id))
            {
                id = renderingItemId;
            }

            if (string.IsNullOrEmpty(renderingItemId))
            {
                Trace.TraceError(Msg.C1035, $"Unknown element \"{id}\".", renderingTextNode);
                return;
            }

            Item renderingItem;

            if (Guid.TryParse(renderingItemId, out Guid guid))
            {
                renderingItem = context.Project.ProjectItems.OfType <Item>().FirstOrDefault(i => i.Uri.Guid == guid && i.Database == context.Database);
            }
            else
            {
                var matches = ResolveRenderingItemId(renderingItems, renderingItemId);

                if (matches.Length == 0)
                {
                    Trace.TraceError(Msg.C1036, $"Rendering \"{renderingItemId}\" not found.", renderingTextNode);
                    return;
                }

                if (matches.Length > 1)
                {
                    Trace.TraceError(Msg.C1037, $"Ambiguous rendering match. {matches.Length} renderings match \"{renderingItemId}\".", renderingTextNode);
                    return;
                }

                renderingItem = matches[0];
            }

            if (renderingItem == null)
            {
                Trace.TraceError(Msg.C1038, $"Rendering \"{renderingItemId}\" not found.", renderingTextNode);
                return;
            }

            output.WriteStartElement("r");

            WriteBool(context, output, renderingTextNode, id, "Cacheable", "cac");
            output.WriteAttributeString("id", renderingItem.Uri.Guid.Format());
            WriteDataSource(context, output, renderingTextNode);
            WriteParameters(context, output, renderingTextNode, renderingItem, id);
            output.WriteAttributeString("ph", placeholderName);

            // WriteAttributeStringNotEmpty(@"uid", this.UniqueId);
            WriteBool(context, output, renderingTextNode, id, "VaryByData", "vbd");
            WriteBool(context, output, renderingTextNode, id, "VaryByDevice", "vbdev");
            WriteBool(context, output, renderingTextNode, id, "VaryByLogin", "vbl");
            WriteBool(context, output, renderingTextNode, id, "VaryByParameters", "vbp");
            WriteBool(context, output, renderingTextNode, id, "VaryByQueryString", "vbqs");
            WriteBool(context, output, renderingTextNode, id, "VaryByUser", "vbu");

            output.WriteEndElement();

            foreach (var placeholderTextNode in renderingTextNode.ChildNodes)
            {
                WritePlaceholder(context, output, renderingItems, placeholderTextNode);
            }
        }
        protected virtual void WriteDevice([NotNull] LayoutCompileContext context, [NotNull] XmlWriter output, [NotNull, ItemNotNull] IEnumerable <Item> renderingItems, [NotNull] ITextNode deviceTextNode)
        {
            output.WriteStartElement("d");

            var deviceName = deviceTextNode.Key;
            var layout     = deviceTextNode.Value;

            if (string.Equals(deviceName, "Device", StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(deviceName))
            {
                deviceName = deviceTextNode.GetAttributeValue("Name");
                layout     = deviceTextNode.GetAttributeValue("Layout");
            }

            if (string.IsNullOrEmpty(deviceName))
            {
                Trace.TraceError(Msg.C1029, Texts.Device_element_is_missing__Name__attribute_, deviceTextNode);
            }
            else
            {
                var devices = context.Project.ProjectItems.OfType <Item>().Where(i => string.Equals(i.TemplateIdOrPath, "/sitecore/templates/System/Layout/Device", StringComparison.OrdinalIgnoreCase) || string.Equals(i.TemplateIdOrPath, "{B6F7EEB4-E8D7-476F-8936-5ACE6A76F20B}", StringComparison.OrdinalIgnoreCase)).ToList();
                if (!devices.Any())
                {
                    Trace.TraceError(Msg.C1031, Texts.Device_item_not_found, deviceTextNode);
                }
                else
                {
                    var device = devices.FirstOrDefault(d => string.Equals(d.ItemName, deviceName, StringComparison.OrdinalIgnoreCase));
                    if (device == null)
                    {
                        Trace.TraceError(Msg.C1032, Texts.Device_not_found, deviceTextNode, deviceName);
                    }
                    else
                    {
                        output.WriteAttributeString("id", device.Uri.Guid.Format());
                    }
                }
            }

            if (!string.IsNullOrEmpty(layout))
            {
                var l = context.Project.Indexes.FindQualifiedItem <IProjectItem>(layout);

                if (l == null)
                {
                    var layouts = ResolveRenderingItem(renderingItems, layout);
                    if (layouts.Length > 1)
                    {
                        Trace.TraceError(Msg.C1130, "Ambiguous layout", layout);
                        return;
                    }

                    l = layouts.FirstOrDefault();
                }

                if (l == null)
                {
                    Trace.TraceError(Msg.C1033, Texts.Layout_not_found_, layout);
                    return;
                }

                output.WriteAttributeString("l", l.Uri.Guid.Format());
            }

            foreach (var placeholderTextNode in deviceTextNode.ChildNodes)
            {
                WritePlaceholder(context, output, renderingItems, placeholderTextNode);
            }

            output.WriteEndElement();
        }