/// <summary> /// Convenience method to add a piece of metadata to this item definition. /// Adds after any existing metadata. Does not modify any existing metadata. /// </summary> /// <param name="name">The name of the metadata to add</param> /// <param name="unevaluatedValue">The value of the metadata to add</param> /// <param name="expressAsAttribute">If true, then the metadata will be expressed as an attribute instead of a child element, for example /// <Content CopyToOutputDirectory="PreserveNewest" /> /// </param> public ProjectMetadataElement AddMetadata(string name, string unevaluatedValue, bool expressAsAttribute) { ErrorUtilities.VerifyThrowArgumentLength(name, nameof(name)); ErrorUtilities.VerifyThrowArgumentNull(unevaluatedValue, nameof(unevaluatedValue)); if (expressAsAttribute) { ProjectMetadataElement.ValidateValidMetadataAsAttributeName(name, ElementName, Location); } ProjectMetadataElement metadata = ContainingProject.CreateMetadataElement(name); metadata.Value = unevaluatedValue; metadata.ExpressedAsAttribute = expressAsAttribute; AppendChild(metadata); return(metadata); }
/// <summary> /// Parse a ProjectMetadataElement /// </summary> private ProjectMetadataElement ParseProjectMetadataElement(XmlElementWithLocation element, ProjectElementContainer parent) { ProjectXmlUtilities.VerifyThrowProjectAttributes(element, ValidAttributesOnlyConditionAndLabel); XmlUtilities.VerifyThrowProjectValidElementName(element); ProjectErrorUtilities.VerifyThrowInvalidProject(!(parent is ProjectItemElement) || ((ProjectItemElement)parent).Remove.Length == 0, element.Location, "ChildElementsBelowRemoveNotAllowed", element.Name); ProjectErrorUtilities.VerifyThrowInvalidProject(!FileUtilities.ItemSpecModifiers.IsItemSpecModifier(element.Name), element.Location, "ItemSpecModifierCannotBeCustomMetadata", element.Name); ProjectErrorUtilities.VerifyThrowInvalidProject(!XMakeElements.ReservedItemNames.Contains(element.Name), element.Location, "CannotModifyReservedItemMetadata", element.Name); ProjectMetadataElement metadatum = new ProjectMetadataElement(element, parent, _project); // If the parent is an item definition, we don't allow expressions like @(foo) in the value, as no items exist at that point if (parent is ProjectItemDefinitionElement) { bool containsItemVector = Expander.ExpressionContainsItemVector(metadatum.Value); ProjectErrorUtilities.VerifyThrowInvalidProject(!containsItemVector, element.Location, "MetadataDefinitionCannotContainItemVectorExpression", metadatum.Value, metadatum.Name); } return(metadatum); }
/// <summary> /// Pasre a ProjectItemDefinitionElement /// </summary> private ProjectItemDefinitionElement ParseProjectItemDefinitionXml(XmlElementWithLocation element, ProjectItemDefinitionGroupElement parent) { // Orcas inadvertently did not check for reserved item types (like "Choose") in item definitions, // as we do for item types in item groups. So we do not have a check here. // Although we could perhaps add one, as such item definitions couldn't be used // since no items can have the reserved itemType. ProjectItemDefinitionElement itemDefinition = new ProjectItemDefinitionElement(element, parent, _project); foreach (XmlAttributeWithLocation attribute in element.Attributes) { CheckMetadataAsAttributeName(attribute.Name, out bool isKnownAttribute, out bool isValidMetadataNameInAttribute); if (!isKnownAttribute && !isValidMetadataNameInAttribute) { ProjectXmlUtilities.ThrowProjectInvalidAttribute(attribute); } else if (isValidMetadataNameInAttribute) { ProjectMetadataElement metadatum = _project.CreateMetadataElement(attribute.Name, attribute.Value); metadatum.ExpressedAsAttribute = true; metadatum.Parent = itemDefinition; itemDefinition.AppendParentedChildNoChecks(metadatum); } else if (!ValidAttributesOnlyConditionAndLabel.Contains(attribute.Name)) { ProjectXmlUtilities.ThrowProjectInvalidAttribute(attribute); } } foreach (XmlElementWithLocation childElement in ProjectXmlUtilities.GetVerifyThrowProjectChildElements(element)) { ProjectMetadataElement metadatum = ParseProjectMetadataElement(childElement, itemDefinition); itemDefinition.AppendParentedChildNoChecks(metadatum); } return(itemDefinition); }
/// <summary> /// Parse a ProjectItemElement /// </summary> private ProjectItemElement ParseProjectItemElement(XmlElementWithLocation element, ProjectItemGroupElement parent) { bool belowTarget = parent.Parent is ProjectTargetElement; string itemType = element.Name; string include = element.GetAttribute(XMakeAttributes.include); string exclude = element.GetAttribute(XMakeAttributes.exclude); string remove = element.GetAttribute(XMakeAttributes.remove); string update = element.GetAttribute(XMakeAttributes.update); var exclusiveItemOperation = ""; int exclusiveAttributeCount = 0; if (element.HasAttribute(XMakeAttributes.include)) { exclusiveAttributeCount++; exclusiveItemOperation = XMakeAttributes.include; } if (element.HasAttribute(XMakeAttributes.remove)) { exclusiveAttributeCount++; exclusiveItemOperation = XMakeAttributes.remove; } if (element.HasAttribute(XMakeAttributes.update)) { exclusiveAttributeCount++; exclusiveItemOperation = XMakeAttributes.update; } // At most one of the include, remove, or update attributes may be specified if (exclusiveAttributeCount > 1) { XmlAttributeWithLocation errorAttribute = remove.Length > 0 ? (XmlAttributeWithLocation)element.Attributes[XMakeAttributes.remove] : (XmlAttributeWithLocation)element.Attributes[XMakeAttributes.update]; ProjectErrorUtilities.ThrowInvalidProject(errorAttribute.Location, "InvalidAttributeExclusive"); } // Include, remove, or update must be present unless inside a target ProjectErrorUtilities.VerifyThrowInvalidProject(exclusiveAttributeCount == 1 || belowTarget, element.Location, "IncludeRemoveOrUpdate", exclusiveItemOperation, itemType); // Exclude must be missing, unless Include exists ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(exclude.Length == 0 || include.Length > 0, (XmlAttributeWithLocation)element.Attributes[XMakeAttributes.exclude]); // If we have an Include attribute at all, it must have non-zero length ProjectErrorUtilities.VerifyThrowInvalidProject(include.Length > 0 || element.Attributes[XMakeAttributes.include] == null, element.Location, "MissingRequiredAttribute", XMakeAttributes.include, itemType); // If we have a Remove attribute at all, it must have non-zero length ProjectErrorUtilities.VerifyThrowInvalidProject(remove.Length > 0 || element.Attributes[XMakeAttributes.remove] == null, element.Location, "MissingRequiredAttribute", XMakeAttributes.remove, itemType); // If we have an Update attribute at all, it must have non-zero length ProjectErrorUtilities.VerifyThrowInvalidProject(update.Length > 0 || element.Attributes[XMakeAttributes.update] == null, element.Location, "MissingRequiredAttribute", XMakeAttributes.update, itemType); XmlUtilities.VerifyThrowProjectValidElementName(element); ProjectErrorUtilities.VerifyThrowInvalidProject(!XMakeElements.ReservedItemNames.Contains(itemType), element.Location, "CannotModifyReservedItem", itemType); ProjectItemElement item = new ProjectItemElement(element, parent, _project); foreach (XmlAttributeWithLocation attribute in element.Attributes) { bool isKnownAttribute; bool isValidMetadataNameInAttribute; CheckMetadataAsAttributeName(attribute.Name, out isKnownAttribute, out isValidMetadataNameInAttribute); if (!isKnownAttribute && !isValidMetadataNameInAttribute) { ProjectXmlUtilities.ThrowProjectInvalidAttribute(attribute); } else if (isValidMetadataNameInAttribute) { ProjectMetadataElement metadatum = _project.CreateMetadataElement(attribute.Name, attribute.Value); metadatum.ExpressedAsAttribute = true; metadatum.Parent = item; item.AppendParentedChildNoChecks(metadatum); } } foreach (XmlElementWithLocation childElement in ProjectXmlUtilities.GetVerifyThrowProjectChildElements(element)) { ProjectMetadataElement metadatum = ParseProjectMetadataElement(childElement, item); item.AppendParentedChildNoChecks(metadatum); } return(item); }
internal override bool ShouldCloneXmlAttribute(XmlAttributeLink attributeLink) => !ProjectMetadataElement.AttributeNameIsValidMetadataName(attributeLink.LocalName);
/// <summary> /// Do not clone attributes which can be metadata. The corresponding expressed as attribute project elements are responsible for adding their attribute /// </summary> protected override bool ShouldCloneXmlAttribute(XmlAttribute attribute) => !ProjectMetadataElement.AttributeNameIsValidMetadataName(attribute.LocalName);