private void ReadParentSegment(EpmTargetPathSegment targetSegment, AtomEntryMetadata entryMetadata) { switch (targetSegment.SegmentName) { case "author": { AtomPersonMetadata personMetadata = entryMetadata.Authors.FirstOrDefault<AtomPersonMetadata>(); if (personMetadata != null) { this.ReadPersonEpm(ReaderUtils.GetPropertiesList(base.EntryState.Entry.Properties), base.EntryState.EntityType.ToTypeReference(), targetSegment, personMetadata); } return; } case "contributor": { AtomPersonMetadata metadata2 = entryMetadata.Contributors.FirstOrDefault<AtomPersonMetadata>(); if (metadata2 != null) { this.ReadPersonEpm(ReaderUtils.GetPropertiesList(base.EntryState.Entry.Properties), base.EntryState.EntityType.ToTypeReference(), targetSegment, metadata2); } return; } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadParentSegment_TargetSegmentName)); }
/// <summary> /// Reads an EPM for the entire entry. /// </summary> private void ReadEntryEpm() { // Note that this property access will create empty entry metadata if none were read yet. AtomEntryMetadata entryMetadata = this.EntryState.AtomEntryMetadata; Debug.Assert(entryMetadata != null, "entryMetadata != null"); // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = this.EntryState.CachedEpm.EpmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return; } foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.HasContent) { this.ReadPropertyValueSegment(targetSegment, entryMetadata); } else { this.ReadParentSegment(targetSegment, entryMetadata); } } }
/// <summary> /// Writes an EPM attribute target. /// </summary> /// <param name="writer">The writer to write to.</param> /// <param name="targetSegment">The target segment describing the attribute to write.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="entityType">The type of the entry.</param> /// <param name="alreadyDeclaredPrefix">The name of the prefix if it was already declared.</param> private void WriteAttributeEpm( XmlWriter writer, EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType, ref string alreadyDeclaredPrefix) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(targetSegment != null && targetSegment.IsAttribute, "Only attribute target segments are supported by this method."); Debug.Assert(targetSegment.HasContent, "Attribute target segments must have content."); string textPropertyValue = this.GetEntryPropertyValueAsText(targetSegment, epmValueCache, entityType); Debug.Assert(textPropertyValue != null, "Text value of a property mapped to attribute must not be null, the GetEntryPropertyValueAsText should take care of that."); // If the prefix is null, the WCF DS will still write it as the default namespace, so we need it to be an empty string. string attributePrefix = targetSegment.SegmentNamespacePrefix ?? string.Empty; writer.WriteAttributeString(attributePrefix, targetSegment.AttributeName, targetSegment.SegmentNamespaceUri, textPropertyValue); // Write out the declaration explicitely only if the prefix is not empty (just like the WCF DS does) if (attributePrefix.Length > 0) { WriteNamespaceDeclaration(writer, targetSegment, ref alreadyDeclaredPrefix); } }
private void WriteElementEpm(XmlWriter writer, EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType, ref string alreadyDeclaredPrefix) { string prefix = targetSegment.SegmentNamespacePrefix ?? string.Empty; writer.WriteStartElement(prefix, targetSegment.SegmentName, targetSegment.SegmentNamespaceUri); if (prefix.Length > 0) { WriteNamespaceDeclaration(writer, targetSegment, ref alreadyDeclaredPrefix); } foreach (EpmTargetPathSegment segment in targetSegment.SubSegments) { if (segment.IsAttribute) { this.WriteAttributeEpm(writer, segment, epmValueCache, entityType, ref alreadyDeclaredPrefix); } } if (targetSegment.HasContent) { string str2 = this.GetEntryPropertyValueAsText(targetSegment, epmValueCache, entityType); ODataAtomWriterUtils.WriteString(writer, str2); } else { foreach (EpmTargetPathSegment segment2 in targetSegment.SubSegments) { if (!segment2.IsAttribute) { this.WriteElementEpm(writer, segment2, epmValueCache, entityType, ref alreadyDeclaredPrefix); } } } writer.WriteEndElement(); }
private void ReadTextConstructEpm(EpmTargetPathSegment targetSegment, AtomTextConstruct textConstruct) { if ((textConstruct != null) && (textConstruct.Text != null)) { base.SetEntryEpmValue(targetSegment.EpmInfo, textConstruct.Text); } }
protected AtomPersonMetadata ReadAtomPersonConstruct(EpmTargetPathSegment epmTargetPathSegment) { AtomPersonMetadata metadata = new AtomPersonMetadata(); if (base.XmlReader.IsEmptyElement) { goto Label_011B; } base.XmlReader.Read(); Label_0022: switch (base.XmlReader.NodeType) { case XmlNodeType.Element: EpmTargetPathSegment segment; string str2; if ((base.XmlReader.NamespaceEquals(this.AtomNamespace) && this.ShouldReadElement(epmTargetPathSegment, base.XmlReader.LocalName, out segment)) && ((str2 = base.XmlReader.LocalName) != null)) { if (!(str2 == "name")) { if (str2 == "uri") { Uri xmlBaseUri = base.XmlReader.XmlBaseUri; string uriFromPayload = this.ReadElementStringValue(); if (segment != null) { metadata.UriFromEpm = uriFromPayload; } if (this.ReadAtomMetadata) { metadata.Uri = base.ProcessUriFromPayload(uriFromPayload, xmlBaseUri); } goto Label_0109; } if (str2 == "email") { metadata.Email = this.ReadElementStringValue(); goto Label_0109; } } else { metadata.Name = this.ReadElementStringValue(); goto Label_0109; } } break; case XmlNodeType.EndElement: goto Label_0109; } base.XmlReader.Skip(); Label_0109: if (base.XmlReader.NodeType != XmlNodeType.EndElement) { goto Label_0022; } Label_011B: base.XmlReader.Read(); return(metadata); }
private void ReadParentSegment(EpmTargetPathSegment targetSegment, AtomEntryMetadata entryMetadata) { switch (targetSegment.SegmentName) { case "author": { AtomPersonMetadata personMetadata = entryMetadata.Authors.FirstOrDefault <AtomPersonMetadata>(); if (personMetadata != null) { this.ReadPersonEpm(ReaderUtils.GetPropertiesList(base.EntryState.Entry.Properties), base.EntryState.EntityType.ToTypeReference(), targetSegment, personMetadata); } return; } case "contributor": { AtomPersonMetadata metadata2 = entryMetadata.Contributors.FirstOrDefault <AtomPersonMetadata>(); if (metadata2 != null) { this.ReadPersonEpm(ReaderUtils.GetPropertiesList(base.EntryState.Entry.Properties), base.EntryState.EntityType.ToTypeReference(), targetSegment, metadata2); } return; } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadParentSegment_TargetSegmentName)); }
private void WriteParentSegment(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { if (targetSegment.SegmentName == "author") { AtomPersonMetadata item = this.WritePersonEpm(targetSegment, epmValueCache, typeReference); if (item != null) { List <AtomPersonMetadata> authors = (List <AtomPersonMetadata>) this.entryMetadata.Authors; if (authors == null) { authors = new List <AtomPersonMetadata>(); this.entryMetadata.Authors = authors; } authors.Add(item); } } else { if (!(targetSegment.SegmentName == "contributor")) { throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteParentSegment_TargetSegmentName)); } AtomPersonMetadata metadata2 = this.WritePersonEpm(targetSegment, epmValueCache, typeReference); if (metadata2 != null) { List <AtomPersonMetadata> contributors = (List <AtomPersonMetadata>) this.entryMetadata.Contributors; if (contributors == null) { contributors = new List <AtomPersonMetadata>(); this.entryMetadata.Contributors = contributors; } contributors.Add(metadata2); } } }
/// <summary> /// Writes the custom mapped EPM properties to an XML writer which is expected to be positioned such to write /// a child element of the entry element. /// </summary> /// <param name="writer">The XmlWriter to write to.</param> /// <param name="epmTargetTree">The EPM target tree to use.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="entityType">The type of the entry.</param> private void WriteEntryEpm( XmlWriter writer, EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(epmTargetTree != null, "epmTargetTree != null"); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(entityType != null, "For any EPM to exist the metadata must be available."); // If there are no custom mappings, just return null. EpmTargetPathSegment customRootSegment = epmTargetTree.NonSyndicationRoot; Debug.Assert(customRootSegment != null, "EPM Target tree must always have non-syndication root."); if (customRootSegment.SubSegments.Count == 0) { return; } foreach (EpmTargetPathSegment targetSegment in customRootSegment.SubSegments) { Debug.Assert(!targetSegment.IsAttribute, "Target segments under the custom root must be for elements only."); string alreadyDeclaredPrefix = null; this.WriteElementEpm(writer, targetSegment, epmValueCache, entityType, ref alreadyDeclaredPrefix); } }
/// <summary> /// Reads an attribute for custom EPM. /// </summary> /// <param name="entryState">The reader entry state for the entry being read.</param> /// <param name="epmTargetPathSegmentForElement">The EPM target segment for the element to which the attribute belongs.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Attribute - the attribute to read. /// Post-Condition: XmlNodeType.Attribute - the same attribute, the method doesn't move the reader. /// /// The method works on any attribute, it checks if the attribute should be used for EPM or not. /// </remarks> private void ReadCustomEpmAttribute(IODataAtomReaderEntryState entryState, EpmTargetPathSegment epmTargetPathSegmentForElement) { Debug.Assert(entryState != null, "entryState != null"); this.AssertXmlCondition(XmlNodeType.Attribute); Debug.Assert(epmTargetPathSegmentForElement != null, "epmTargetPathSegmentForElement != null"); string localName = this.XmlReader.LocalName; string namespaceUri = this.XmlReader.NamespaceURI; EpmTargetPathSegment attributeSegment = epmTargetPathSegmentForElement.SubSegments.FirstOrDefault( segment => segment.IsAttribute && string.CompareOrdinal(segment.AttributeName, localName) == 0 && string.CompareOrdinal(segment.SegmentNamespaceUri, namespaceUri) == 0); if (attributeSegment != null) { // Don't add values which we already have // Both WCF DS client and server will only read the first value from custom EPM for any given EPM info. // It also follows the behavior for syndication EPM, where we read only the first author if there are multiple (for example). if (!entryState.EpmCustomReaderValueCache.Contains(attributeSegment.EpmInfo)) { // Note that there's no way for an attribute to specify null value. entryState.EpmCustomReaderValueCache.Add(attributeSegment.EpmInfo, this.XmlReader.Value); } } }
/// <summary> /// Determines if we need to read a child element (either for EPM or for ATOM metadata). /// </summary> /// <param name="parentSegment">The parent EPM target path segment.</param> /// <param name="segmentName">The name of the element/segment to read.</param> /// <param name="subSegment">The EPM target path subsegment which describes the element, or null if there's none.</param> /// <returns>true if the subelement should be read, false otherwise.</returns> protected bool ShouldReadElement(EpmTargetPathSegment parentSegment, string segmentName, out EpmTargetPathSegment subSegment) { subSegment = null; // NOTE: We should always read the element if this.ReadAtomMetadata is true, but we still // need to search for a matching subsegment when ATOM metadata reading is on and this // element is also an EPM target. This is less efficient than returning early, but // needed for the URI case, since callers need to know whether to save the URI value // in the special UriFromEpm property. if (parentSegment != null) { subSegment = parentSegment.SubSegments.FirstOrDefault(segment => string.CompareOrdinal(segment.SegmentName, segmentName) == 0); Debug.Assert( subSegment == null || subSegment.SegmentNamespaceUri == AtomConstants.AtomNamespace, "Only elements from ATOM namespace should appear in the syndication mappings."); // We do not read out-of-content EPM if the KeepInContent=true. if (subSegment != null && subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute.KeepInContent) { return(this.ReadAtomMetadata); } } return(subSegment != null || this.ReadAtomMetadata); }
/// <summary> /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM. /// </summary> /// <param name="targetSegment">The target segment to read the value for.</param> /// <param name="epmValueCache">EPM value cache to use to get property values, or a primitive value</param> /// <param name="typeReference">The type of the entry or collection item.</param> /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns> private string GetPropertyValueAsText( EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content."); Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property."); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(typeReference != null, "typeReference != null"); object propertyValue; EntryPropertiesValueCache entryPropertiesValueCache = epmValueCache as EntryPropertiesValueCache; if (entryPropertiesValueCache != null) { propertyValue = this.ReadEntryPropertyValue( targetSegment.EpmInfo, entryPropertiesValueCache, typeReference.AsEntity()); } else { propertyValue = epmValueCache; ValidationUtils.ValidateIsExpectedPrimitiveType(propertyValue, typeReference); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
/// <summary> /// Reads a leaf segment which maps to a property value. /// </summary> /// <param name="targetSegment">The segment being read.</param> /// <param name="entryMetadata">The ATOM entry metadata to read from.</param> private void ReadPropertyValueSegment(EpmTargetPathSegment targetSegment, AtomEntryMetadata entryMetadata) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(entryMetadata != null, "entryMetadata != null"); EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the Epm attribute"); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: if (this.MessageReaderSettings.ReaderBehavior.FormatBehaviorKind == ODataBehaviorKind.WcfDataServicesClient) { if (entryMetadata.UpdatedString != null) { this.SetEntryEpmValue(targetSegment.EpmInfo, entryMetadata.UpdatedString); } } else if (entryMetadata.Updated.HasValue) { this.SetEntryEpmValue(targetSegment.EpmInfo, XmlConvert.ToString(entryMetadata.Updated.Value)); } break; case SyndicationItemProperty.Published: if (this.MessageReaderSettings.ReaderBehavior.FormatBehaviorKind == ODataBehaviorKind.WcfDataServicesClient) { if (entryMetadata.PublishedString != null) { this.SetEntryEpmValue(targetSegment.EpmInfo, entryMetadata.PublishedString); } } else if (entryMetadata.Published.HasValue) { this.SetEntryEpmValue(targetSegment.EpmInfo, XmlConvert.ToString(entryMetadata.Published.Value)); } break; case SyndicationItemProperty.Rights: this.ReadTextConstructEpm(targetSegment, entryMetadata.Rights); break; case SyndicationItemProperty.Summary: this.ReadTextConstructEpm(targetSegment, entryMetadata.Summary); break; case SyndicationItemProperty.Title: this.ReadTextConstructEpm(targetSegment, entryMetadata.Title); break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadEntryEpm_ContentTarget)); } }
private static void WriteNamespaceDeclaration(XmlWriter writer, EpmTargetPathSegment targetSegment, ref string alreadyDeclaredPrefix) { if (alreadyDeclaredPrefix == null) { writer.WriteAttributeString("xmlns", targetSegment.SegmentNamespacePrefix, "http://www.w3.org/2000/xmlns/", targetSegment.SegmentNamespaceUri); alreadyDeclaredPrefix = targetSegment.SegmentNamespacePrefix; } }
private AtomPersonMetadata WritePersonEpm(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { AtomPersonMetadata metadata = null; foreach (EpmTargetPathSegment segment in targetSegment.SubSegments) { string str = this.GetPropertyValueAsText(segment, epmValueCache, typeReference); if (str != null) { switch (segment.EpmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.ContributorEmail: { if ((str != null) && (str.Length > 0)) { if (metadata == null) { metadata = new AtomPersonMetadata(); } metadata.Email = str; } continue; } case SyndicationItemProperty.AuthorName: case SyndicationItemProperty.ContributorName: { if (str != null) { if (metadata == null) { metadata = new AtomPersonMetadata(); } metadata.Name = str; } continue; } case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorUri: { if ((str != null) && (str.Length > 0)) { if (metadata == null) { metadata = new AtomPersonMetadata(); } metadata.UriFromEpm = str; } continue; } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WritePersonEpm)); } } return(metadata); }
/// <summary>Used for creating non-root nodes in the syndication/custom trees</summary> /// <param name="segmentName">Name of xml element/attribute</param> /// <param name="segmentNamespaceUri">URI of the namespace for <paramref name="segmentName"/></param> /// <param name="parentSegment">Reference to the parent node if this is a sub-node, useful for traversals in visitors</param> internal EpmTargetPathSegment(String segmentName, String segmentNamespaceUri, EpmTargetPathSegment parentSegment) : this() { Debug.Assert(segmentName == null || segmentName.Length > 0, "Empty segment name is not allowed."); this.segmentName = segmentName; this.segmentNamespaceUri = segmentNamespaceUri; this.parentSegment = parentSegment; }
private string GetEntryPropertyValueAsText(EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { object propertyValue = base.ReadEntryPropertyValue(targetSegment.EpmInfo, epmValueCache, entityType); if (propertyValue == null) { return(string.Empty); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
private void WriteAttributeEpm(XmlWriter writer, EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType, ref string alreadyDeclaredPrefix) { string str = this.GetEntryPropertyValueAsText(targetSegment, epmValueCache, entityType); string prefix = targetSegment.SegmentNamespacePrefix ?? string.Empty; writer.WriteAttributeString(prefix, targetSegment.AttributeName, targetSegment.SegmentNamespaceUri, str); if (prefix.Length > 0) { WriteNamespaceDeclaration(writer, targetSegment, ref alreadyDeclaredPrefix); } }
private void ReadPropertyValueSegment(EpmTargetPathSegment targetSegment, AtomEntryMetadata entryMetadata) { switch (targetSegment.EpmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: if (base.MessageReaderSettings.ReaderBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesClient) { if (!entryMetadata.Updated.HasValue) { break; } base.SetEntryEpmValue(targetSegment.EpmInfo, XmlConvert.ToString(entryMetadata.Updated.Value)); return; } if (entryMetadata.UpdatedString == null) { break; } base.SetEntryEpmValue(targetSegment.EpmInfo, entryMetadata.UpdatedString); return; case SyndicationItemProperty.Published: if (base.MessageReaderSettings.ReaderBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesClient) { if (entryMetadata.Published.HasValue) { base.SetEntryEpmValue(targetSegment.EpmInfo, XmlConvert.ToString(entryMetadata.Published.Value)); return; } break; } if (entryMetadata.PublishedString == null) { break; } base.SetEntryEpmValue(targetSegment.EpmInfo, entryMetadata.PublishedString); return; case SyndicationItemProperty.Rights: this.ReadTextConstructEpm(targetSegment, entryMetadata.Rights); return; case SyndicationItemProperty.Summary: this.ReadTextConstructEpm(targetSegment, entryMetadata.Summary); return; case SyndicationItemProperty.Title: this.ReadTextConstructEpm(targetSegment, entryMetadata.Title); return; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadEntryEpm_ContentTarget)); } }
private void ReadContributorElement(IODataAtomReaderEntryState entryState, EpmTargetPathSegment epmTargetPathSegment) { if (this.ShouldReadCollectionElement(entryState.AtomEntryMetadata.Contributors.Any <AtomPersonMetadata>())) { AtomMetadataReaderUtils.AddContributorToEntryMetadata(entryState.AtomEntryMetadata, base.ReadAtomPersonConstruct(epmTargetPathSegment)); } else { base.XmlReader.Skip(); } }
internal EpmCustomContentWriterNodeData(EpmCustomContentWriterNodeData parentData, EpmTargetPathSegment segment, object element, EpmContentSerializer.EpmNullValuedPropertyTree nullValuedProperties, DataServiceProviderWrapper provider) #endif { this.XmlContentStream = parentData.XmlContentStream; this.XmlContentWriter = parentData.XmlContentWriter; #if ASTORIA_CLIENT this.PopulateData(segment, element); #else this.PopulateData(segment, element, nullValuedProperties, provider); #endif }
private void ReadCustomEpmAttribute(IODataAtomReaderEntryState entryState, EpmTargetPathSegment epmTargetPathSegmentForElement) { string localName = base.XmlReader.LocalName; string namespaceUri = base.XmlReader.NamespaceURI; EpmTargetPathSegment segment = epmTargetPathSegmentForElement.SubSegments.FirstOrDefault <EpmTargetPathSegment>(x => (x.IsAttribute && (string.CompareOrdinal(x.AttributeName, localName) == 0)) && (string.CompareOrdinal(x.SegmentNamespaceUri, namespaceUri) == 0)); if ((segment != null) && !entryState.EpmCustomReaderValueCache.Contains(segment.EpmInfo)) { entryState.EpmCustomReaderValueCache.Add(segment.EpmInfo, base.XmlReader.Value); } }
internal bool TryReadExtensionElementInEntryContent(IODataAtomReaderEntryState entryState) { ODataEntityPropertyMappingCache cachedEpm = entryState.CachedEpm; if (cachedEpm == null) { return(false); } EpmTargetPathSegment nonSyndicationRoot = cachedEpm.EpmTargetTree.NonSyndicationRoot; return(this.TryReadCustomEpmElement(entryState, nonSyndicationRoot)); }
/// <summary> /// Writes an EPM element target. /// </summary> /// <param name="writer">The writer to write to.</param> /// <param name="targetSegment">The target segment describing the element to write.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="entityType">The type of the entry.</param> /// <param name="alreadyDeclaredPrefix">The name of the prefix if it was already declared.</param> private void WriteElementEpm( XmlWriter writer, EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType, ref string alreadyDeclaredPrefix) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(targetSegment != null && !targetSegment.IsAttribute, "Only element target segments are supported by this method."); // If the prefix is null, the WCF DS will still write it as the default namespace, so we need it to be an empty string. string elementPrefix = targetSegment.SegmentNamespacePrefix ?? string.Empty; writer.WriteStartElement(elementPrefix, targetSegment.SegmentName, targetSegment.SegmentNamespaceUri); // Write out the declaration explicitly only if the prefix is not empty (just like the WCF DS does) if (elementPrefix.Length > 0) { WriteNamespaceDeclaration(writer, targetSegment, ref alreadyDeclaredPrefix); } // Serialize the sub segment attributes first foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments) { if (subSegment.IsAttribute) { this.WriteAttributeEpm(writer, subSegment, epmValueCache, entityType, ref alreadyDeclaredPrefix); } } if (targetSegment.HasContent) { Debug.Assert(!targetSegment.SubSegments.Any(subSegment => !subSegment.IsAttribute), "If the segment has a content, it must not have any element children."); string textPropertyValue = this.GetEntryPropertyValueAsText(targetSegment, epmValueCache, entityType); ODataAtomWriterUtils.WriteString(writer, textPropertyValue); } else { // Serialize the sub segment elements now foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments) { if (!subSegment.IsAttribute) { this.WriteElementEpm(writer, subSegment, epmValueCache, entityType, ref alreadyDeclaredPrefix); } } } // Close the element writer.WriteEndElement(); }
private bool TryReadCustomEpmElement(IODataAtomReaderEntryState entryState, EpmTargetPathSegment epmTargetPathSegment) { string localName = base.XmlReader.LocalName; string namespaceUri = base.XmlReader.NamespaceURI; EpmTargetPathSegment epmTargetPathSegmentForElement = epmTargetPathSegment.SubSegments.FirstOrDefault <EpmTargetPathSegment>(segment => (!segment.IsAttribute && (string.CompareOrdinal(segment.SegmentName, localName) == 0)) && (string.CompareOrdinal(segment.SegmentNamespaceUri, namespaceUri) == 0)); if ((epmTargetPathSegmentForElement != null) && (!epmTargetPathSegmentForElement.HasContent || !entryState.EpmCustomReaderValueCache.Contains(epmTargetPathSegmentForElement.EpmInfo))) { while (base.XmlReader.MoveToNextAttribute()) { this.ReadCustomEpmAttribute(entryState, epmTargetPathSegmentForElement); } base.XmlReader.MoveToElement(); if (epmTargetPathSegmentForElement.HasContent) { string str = base.ReadElementStringValue(); entryState.EpmCustomReaderValueCache.Add(epmTargetPathSegmentForElement.EpmInfo, str); goto Label_0115; } if (!base.XmlReader.IsEmptyElement) { base.XmlReader.Read(); while (base.XmlReader.NodeType != XmlNodeType.EndElement) { switch (base.XmlReader.NodeType) { case XmlNodeType.Element: { if (!this.TryReadCustomEpmElement(entryState, epmTargetPathSegmentForElement)) { base.XmlReader.Skip(); } continue; } case XmlNodeType.EndElement: { continue; } } base.XmlReader.Skip(); } } } else { return(false); } base.XmlReader.Read(); Label_0115: return(true); }
/// <summary> /// Removes a path in the tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/> /// </summary> /// <param name="epmInfo">EnitityPropertyMappingInfo holding the target path</param> internal void Remove(EntityPropertyMappingInfo epmInfo) { Debug.Assert(epmInfo != null, "epmInfo != null"); String targetName = epmInfo.Attribute.TargetPath; String namespaceUri = epmInfo.Attribute.TargetNamespaceUri; EpmTargetPathSegment currentSegment = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot; List <EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!String.IsNullOrEmpty(targetName), "Must have been validated during EntityPropertyMappingAttribute construction"); String[] targetSegments = targetName.Split('/'); for (int i = 0; i < targetSegments.Length; i++) { String targetSegment = targetSegments[i]; Debug.Assert(targetSegment.Length > 0 && (targetSegment[0] != '@' || i == targetSegments.Length - 1), "Target segments should have been checked when adding the path to the tree"); EpmTargetPathSegment foundSegment = activeSubSegments.FirstOrDefault( segment => segment.SegmentName == targetSegment && (epmInfo.IsSyndicationMapping || segment.SegmentNamespaceUri == namespaceUri)); if (foundSegment != null) { currentSegment = foundSegment; } else { return; } activeSubSegments = currentSegment.SubSegments; } // Recursively remove all the parent segments which will have no more children left // after removal of the current segment node if (currentSegment.EpmInfo != null) { // Since we are removing a property with KeepInContent false, we should decrement the count if (!currentSegment.EpmInfo.Attribute.KeepInContent) { this.countOfNonContentV2mappings--; } EpmTargetPathSegment parentSegment = null; do { parentSegment = currentSegment.ParentSegment; parentSegment.SubSegments.Remove(currentSegment); currentSegment = parentSegment; }while (currentSegment.ParentSegment != null && !currentSegment.HasContent && currentSegment.SubSegments.Count == 0); } }
/// <summary> /// Reads the value of the ATOM text construct and sets it to the EPM. /// </summary> /// <param name="targetSegment">The EPM target segment for the value to read.</param> /// <param name="textConstruct">The text construct to read it from (can be null).</param> private void ReadTextConstructEpm(EpmTargetPathSegment targetSegment, AtomTextConstruct textConstruct) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(targetSegment.HasContent, "We can only read text construct values into segments which are mapped to a leaf property."); if (textConstruct != null) { if (textConstruct.Text != null) { this.SetEntryEpmValue(targetSegment.EpmInfo, textConstruct.Text); } } }
/// <summary>Checks the validity of a tree.</summary> /// <param name="currentSegment">The segment to validate.</param> private static void DebugValidate(EpmTargetPathSegment currentSegment) { if (currentSegment.ParentSegment != null) { Debug.Assert(!currentSegment.ParentSegment.IsAttribute, "Attributes must be leaf nodes."); } // Walk recursively subsegments and validate them foreach (EpmTargetPathSegment subSegment in currentSegment.SubSegments) { DebugValidate(subSegment); } }
private void WriteEntryEpm(XmlWriter writer, EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { EpmTargetPathSegment nonSyndicationRoot = epmTargetTree.NonSyndicationRoot; if (nonSyndicationRoot.SubSegments.Count != 0) { foreach (EpmTargetPathSegment segment2 in nonSyndicationRoot.SubSegments) { string alreadyDeclaredPrefix = null; this.WriteElementEpm(writer, segment2, epmValueCache, entityType, ref alreadyDeclaredPrefix); } } }
internal EpmCustomContentWriterNodeData(EpmTargetPathSegment segment, object element, EpmContentSerializer.EpmNullValuedPropertyTree nullValuedProperties, DataServiceProviderWrapper provider) #endif { this.XmlContentStream = new MemoryStream(); XmlWriterSettings customContentWriterSettings = new XmlWriterSettings(); customContentWriterSettings.OmitXmlDeclaration = true; customContentWriterSettings.ConformanceLevel = ConformanceLevel.Fragment; this.XmlContentWriter = XmlWriter.Create(this.XmlContentStream, customContentWriterSettings); #if ASTORIA_CLIENT this.PopulateData(segment, element); #else this.PopulateData(segment, element, nullValuedProperties, provider); #endif }
private string GetPropertyValueAsText(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { object obj2; EntryPropertiesValueCache cache = epmValueCache as EntryPropertiesValueCache; if (cache != null) { obj2 = base.ReadEntryPropertyValue(targetSegment.EpmInfo, cache, typeReference.AsEntity()); } else { obj2 = epmValueCache; ValidationUtils.ValidateIsExpectedPrimitiveType(obj2, typeReference); } return(EpmWriterUtils.GetPropertyValueAsText(obj2)); }
/// <summary> /// Reads a contributor element. /// </summary> /// <param name="entryState">The reader entry state for the entry being read.</param> /// <param name="epmTargetPathSegment">The EPM target path segment for the element to read, or null if no EPM for that element is defined.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element (atom:contributor) - the atom:contributor element to read. /// Post-Condition: Any - the node after the atom:contributor element which was read. /// </remarks> private void ReadContributorElement(IODataAtomReaderEntryState entryState, EpmTargetPathSegment epmTargetPathSegment) { Debug.Assert(entryState != null, "entryState != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert( this.XmlReader.LocalName == AtomConstants.AtomContributorElementName && this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace, "Only atom:contributor elements can be read by this method."); if (this.ShouldReadCollectionElement(entryState.AtomEntryMetadata.Contributors.Any())) { entryState.AtomEntryMetadata.AddContributor(this.ReadAtomPersonConstruct(epmTargetPathSegment)); } else { this.XmlReader.Skip(); } }
/// <summary>Checks if mappings could potentially result in mixed content and dis-allows it.</summary> /// <param name="currentSegment">Segment being processed.</param> /// <param name="ancestorHasContent">Does any of the ancestors have content.</param> /// <returns>boolean indicating if the tree is valid or not.</returns> private static bool HasMixedContent(EpmTargetPathSegment currentSegment, bool ancestorHasContent) { foreach (EpmTargetPathSegment childSegment in currentSegment.SubSegments.Where(s => !s.IsAttribute)) { if (childSegment.HasContent && ancestorHasContent) { return(true); } if (HasMixedContent(childSegment, childSegment.HasContent || ancestorHasContent)) { return(true); } } return(false); }
private void ReadPersonEpm(IList targetList, IEdmTypeReference targetTypeReference, EpmTargetPathSegment targetSegment, AtomPersonMetadata personMetadata) { foreach (EpmTargetPathSegment segment in targetSegment.SubSegments) { switch (segment.EpmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.ContributorEmail: { string email = personMetadata.Email; if (email != null) { base.SetEpmValue(targetList, targetTypeReference, segment.EpmInfo, email); } break; } case SyndicationItemProperty.AuthorName: case SyndicationItemProperty.ContributorName: { string name = personMetadata.Name; if (name != null) { base.SetEpmValue(targetList, targetTypeReference, segment.EpmInfo, name); } break; } case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorUri: { string uriFromEpm = personMetadata.UriFromEpm; if (uriFromEpm != null) { base.SetEpmValue(targetList, targetTypeReference, segment.EpmInfo, uriFromEpm); } break; } default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadPersonEpm)); } } }
private static bool HasMixedContent(EpmTargetPathSegment currentSegment, bool ancestorHasContent) { foreach (EpmTargetPathSegment segment in from s in currentSegment.SubSegments where !s.IsAttribute select s) { if (segment.HasContent && ancestorHasContent) { return true; } if (HasMixedContent(segment, segment.HasContent || ancestorHasContent)) { return true; } } return false; }
/// <summary> /// Writes EPM value to a person construct (author or contributor). /// </summary> /// <param name="targetSegment">The target segment which points to either author or contributor element.</param> /// <param name="epmValueCache">The EPM value cache to use to get property values.</param> /// <param name="resourceType">The resource type of the entry being processed.</param> /// <param name="metadata">The metadata provider to use.</param> /// <returns>The person metadata or null if no person metadata should be written for this mapping.</returns> private static AtomPersonMetadata WritePersonEpm( EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert( targetSegment.SegmentName == AtomConstants.AtomAuthorElementName || targetSegment.SegmentName == AtomConstants.AtomContributorElementName, "targetSegment must be author or contributor."); AtomPersonMetadata personMetadata = null; foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments) { Debug.Assert(subSegment.HasContent, "sub segment of author segment must have content, there are no subsegments which don't have content under author."); string textPropertyValue = GetEntryPropertyValueAsText(subSegment, epmValueCache, resourceType, metadata); if (textPropertyValue == null) { // TODO: In Multi-Values or in V3 mapping nulls to author/contributor subelements is not legal since there's no way to express it. // author/contributor subelements don't allow extension attributes, so we can't add the m:null attribute. continue; } // Initialize the person element only if we actually need to write something to it. if (personMetadata == null) { personMetadata = new AtomPersonMetadata(); } Debug.Assert(subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null, "The author subsegment must have EPM info and EPM attribute."); switch (subSegment.EpmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorName: case SyndicationItemProperty.ContributorName: personMetadata.Name = textPropertyValue; break; case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.ContributorEmail: // TODO: Validate the email value. In V3 or in multi-values the email value must not be null and it must not be empty // since the syndication API doesn't allow empty email values (see below) and it's questionable if ATOM allows it itself. // In case the value is empty the syndication API will actually omit the email element from the payload // we have to simulate that behavior here by not setting the property in that case. if (textPropertyValue.Length > 0) { personMetadata.Email = textPropertyValue; } break; case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorUri: // TODO: Validate the uri value. In V3 or in multi-values the uri value must not be null and it must not be empty // since the syndication API doesn't allow empty uri values (see below) and it's questionable if ATOM allows it itself. // In case the value is empty the syndication API will actually omit the uri element from the payload // we have to simulate that behavior here by not setting the property in that case. if (textPropertyValue.Length > 0) { personMetadata.UriFromEpm = textPropertyValue; } break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WritePersonEpm)); } } return personMetadata; }
/// <summary> /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM. /// </summary> /// <param name="targetSegment">The target segment to read the value for.</param> /// <param name="epmValueCache">The entry EPM value cache to use.</param> /// <param name="resourceType">The resource type of the entry being processed.</param> /// <param name="metadata">The metadata provider to use.</param> /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns> private static string GetEntryPropertyValueAsText( EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content."); Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property."); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(resourceType != null, "resourceType != null"); bool nullOnParentProperty; object propertyValue = targetSegment.EpmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty); return EpmWriterUtils.GetPropertyValueAsText(propertyValue); }
private string GetPropertyValueAsText(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { object obj2; EntryPropertiesValueCache cache = epmValueCache as EntryPropertiesValueCache; if (cache != null) { obj2 = base.ReadEntryPropertyValue(targetSegment.EpmInfo, cache, typeReference.AsEntity()); } else { obj2 = epmValueCache; ValidationUtils.ValidateIsExpectedPrimitiveType(obj2, typeReference); } return EpmWriterUtils.GetPropertyValueAsText(obj2); }
/// <summary> /// Writes EPM value to a person construct (author or contributor). /// </summary> /// <param name="targetSegment">The target segment which points to either author or contributor element.</param> /// <param name="epmValueCache">EPM value cache to use to get property values, or a primitive value</param> /// <param name="typeReference">The type of the entry or collection item.</param> /// <returns>The person metadata or null if no person metadata should be written for this mapping.</returns> private AtomPersonMetadata WritePersonEpm(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert( targetSegment.SegmentName == AtomConstants.AtomAuthorElementName || targetSegment.SegmentName == AtomConstants.AtomContributorElementName, "targetSegment must be author or contributor."); AtomPersonMetadata personMetadata = null; foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments) { Debug.Assert(subSegment.HasContent, "sub segment of author segment must have content, there are no subsegments which don't have content under author."); Debug.Assert( subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null && subSegment.EpmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty, "We should never find a subsegment without EPM attribute or for custom mapping when writing syndication person EPM."); string textPropertyValue = this.GetPropertyValueAsText(subSegment, epmValueCache, typeReference); if (textPropertyValue == null) { // In V2 we write the mapped properties always in-content when the value is null. continue; } // Initialize the person element only if we actually need to write something to it. Debug.Assert(subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null, "The author subsegment must have EPM info and EPM attribute."); switch (subSegment.EpmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorName: case SyndicationItemProperty.ContributorName: if (textPropertyValue != null) { if (personMetadata == null) { personMetadata = new AtomPersonMetadata(); } personMetadata.Name = textPropertyValue; } break; case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.ContributorEmail: if (textPropertyValue != null && textPropertyValue.Length > 0) { if (personMetadata == null) { personMetadata = new AtomPersonMetadata(); } personMetadata.Email = textPropertyValue; } break; case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorUri: if (textPropertyValue != null && textPropertyValue.Length > 0) { if (personMetadata == null) { personMetadata = new AtomPersonMetadata(); } personMetadata.UriFromEpm = textPropertyValue; } break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WritePersonEpm)); } } return personMetadata; }
/// <summary> /// Checks the validity of a tree. /// </summary> /// <param name="currentSegment">The segment to validate.</param> private static void DebugValidate(EpmTargetPathSegment currentSegment) { if (currentSegment.ParentSegment != null) { Debug.Assert(!currentSegment.ParentSegment.IsAttribute, "Attributes must be leaf nodes."); if (currentSegment.EpmInfo != null) { switch (currentSegment.EpmInfo.MultiValueStatus) { case EntityPropertyMappingMultiValueStatus.None: Debug.Assert( currentSegment.ParentSegment.EpmInfo == null || currentSegment.ParentSegment.EpmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.None, "non-multiValue property can only be a child of another non-multiValue property."); break; case EntityPropertyMappingMultiValueStatus.MultiValueProperty: Debug.Assert( currentSegment.ParentSegment.EpmInfo == null || (currentSegment.ParentSegment.EpmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.None && currentSegment.ParentSegment.ParentSegment == null), "MultiValue must be child of the root only."); break; case EntityPropertyMappingMultiValueStatus.MultiValueItemProperty: Debug.Assert( currentSegment.ParentSegment.EpmInfo == null || (currentSegment.ParentSegment.EpmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueProperty || currentSegment.ParentSegment.EpmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueItemProperty), "MultiValue item must be child of multiValue or another multiValue item only."); break; } } } // Walk recursively subsegments and validate them foreach (EpmTargetPathSegment subSegment in currentSegment.SubSegments) { DebugValidate(subSegment); } }
private AtomPersonMetadata WritePersonEpm(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { AtomPersonMetadata metadata = null; foreach (EpmTargetPathSegment segment in targetSegment.SubSegments) { string str = this.GetPropertyValueAsText(segment, epmValueCache, typeReference); if (str != null) { switch (segment.EpmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.ContributorEmail: { if ((str != null) && (str.Length > 0)) { if (metadata == null) { metadata = new AtomPersonMetadata(); } metadata.Email = str; } continue; } case SyndicationItemProperty.AuthorName: case SyndicationItemProperty.ContributorName: { if (str != null) { if (metadata == null) { metadata = new AtomPersonMetadata(); } metadata.Name = str; } continue; } case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorUri: { if ((str != null) && (str.Length > 0)) { if (metadata == null) { metadata = new AtomPersonMetadata(); } metadata.UriFromEpm = str; } continue; } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WritePersonEpm)); } } return metadata; }
private void PopulateData(EpmTargetPathSegment segment, object element, EpmContentSerializer.EpmNullValuedPropertyTree nullValuedProperties, DataServiceProviderWrapper provider) #endif { if (segment.EpmInfo != null) { Object propertyValue; try { #if ASTORIA_CLIENT propertyValue = segment.EpmInfo.ReadPropertyValue(element); #else propertyValue = segment.EpmInfo.ReadPropertyValue(element, provider); #endif } catch #if ASTORIA_CLIENT (System.Reflection.TargetInvocationException) #else (System.Reflection.TargetInvocationException e) #endif { #if !ASTORIA_CLIENT ErrorHandler.HandleTargetInvocationException(e); #endif throw; } #if ASTORIA_CLIENT this.Data = propertyValue == null ? String.Empty : ClientConvert.ToString(propertyValue, false); #else if (propertyValue == null || propertyValue == DBNull.Value) { this.Data = String.Empty; nullValuedProperties.Add(segment.EpmInfo); } else { this.Data = PlainXmlSerializer.PrimitiveToString(propertyValue); } #endif } } }
/// <summary> /// Checks if mappings could potentially result in mixed content and dis-allows it. /// </summary> /// <param name="currentSegment">Segment being processed.</param> /// <param name="ancestorsWithContent">A list of ancestor attributes that have content. /// Can contain a maximum of one attribute when the method is called, must never contain more than two.</param> /// <returns>boolean indicating if the tree is valid or not.</returns> private static bool HasMixedContent(EpmTargetPathSegment currentSegment, List<EntityPropertyMappingAttribute> ancestorsWithContent) { Debug.Assert(ancestorsWithContent != null && ancestorsWithContent.Count < 2, "Expected at most 1 ancestor with content."); foreach (EpmTargetPathSegment childSegment in currentSegment.SubSegments.Where(s => !s.IsAttribute)) { if (childSegment.HasContent && ancestorsWithContent.Count == 1) { ancestorsWithContent.Add(childSegment.EpmInfo.Attribute); return true; } if (childSegment.HasContent) { Debug.Assert(ancestorsWithContent.Count == 0, "Should have already returned if we had ancestors with content."); ancestorsWithContent.Add(childSegment.EpmInfo.Attribute); } if (HasMixedContent(childSegment, ancestorsWithContent)) { Debug.Assert(ancestorsWithContent.Count == 2, "Must have two attributes with content to return true."); return true; } if (childSegment.HasContent) { Debug.Assert(ancestorsWithContent.Count == 1, "Should have the one item in the list that we added before."); ancestorsWithContent.Clear(); } } return false; }
/// <summary> /// Initializes the sub-trees for syndication and non-syndication content. /// </summary> internal EpmTargetTree() { DebugUtils.CheckNoExternalCallers(); this.syndicationRoot = new EpmTargetPathSegment(); this.nonSyndicationRoot = new EpmTargetPathSegment(); }
private void PopulateData(EpmTargetPathSegment segment, object element)
private static bool HasMixedContent(EpmTargetPathSegment currentSegment, List<EntityPropertyMappingAttribute> ancestorsWithContent) { foreach (EpmTargetPathSegment segment in from s in currentSegment.SubSegments where !s.IsAttribute select s) { if (segment.HasContent && (ancestorsWithContent.Count == 1)) { ancestorsWithContent.Add(segment.EpmInfo.Attribute); return true; } if (segment.HasContent) { ancestorsWithContent.Add(segment.EpmInfo.Attribute); } if (HasMixedContent(segment, ancestorsWithContent)) { return true; } if (segment.HasContent) { ancestorsWithContent.Clear(); } } return false; }
internal void Add(EntityPropertyMappingInfo epmInfo) { string targetPath = epmInfo.Attribute.TargetPath; string namespaceUri = epmInfo.Attribute.TargetNamespaceUri; string targetNamespacePrefix = epmInfo.Attribute.TargetNamespacePrefix; EpmTargetPathSegment parentSegment = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot; IList<EpmTargetPathSegment> subSegments = parentSegment.SubSegments; string[] strArray = targetPath.Split(new char[] { '/' }); EpmTargetPathSegment segment2 = null; for (int i = 0; i < strArray.Length; i++) { string targetSegment = strArray[i]; if (targetSegment.Length == 0) { throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_InvalidTargetPath_EmptySegment(targetPath)); } if ((targetSegment[0] == '@') && (i != (strArray.Length - 1))) { throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } segment2 = subSegments.SingleOrDefault<EpmTargetPathSegment>(delegate (EpmTargetPathSegment segment) { if (!(segment.SegmentName == targetSegment)) { return false; } if (!epmInfo.IsSyndicationMapping) { return segment.SegmentNamespaceUri == namespaceUri; } return true; }); if (segment2 != null) { parentSegment = segment2; } else { parentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, targetNamespacePrefix, parentSegment); if (targetSegment[0] == '@') { subSegments.Insert(0, parentSegment); } else { subSegments.Add(parentSegment); } } subSegments = parentSegment.SubSegments; } if (parentSegment.EpmInfo != null) { throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_DuplicateEpmAttributesWithSameTargetName(parentSegment.EpmInfo.DefiningType.ODataFullName(), GetPropertyNameFromEpmInfo(parentSegment.EpmInfo), parentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath)); } if (!epmInfo.Attribute.KeepInContent) { this.countOfNonContentV2Mappings++; } parentSegment.EpmInfo = epmInfo; List<EntityPropertyMappingAttribute> ancestorsWithContent = new List<EntityPropertyMappingAttribute>(2); if (HasMixedContent(this.NonSyndicationRoot, ancestorsWithContent)) { throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_InvalidTargetPath_MixedContent(ancestorsWithContent[0].TargetPath, ancestorsWithContent[1].TargetPath)); } }
/// <summary> /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM. /// </summary> /// <param name="targetSegment">The target segment to read the value for.</param> /// <param name="epmValueCache">EPM value cache to use to get property values, or a primitive value</param> /// <param name="typeReference">The type of the entry or collection item.</param> /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns> private string GetPropertyValueAsText( EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content."); Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property."); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(typeReference != null, "typeReference != null"); object propertyValue; EntryPropertiesValueCache entryPropertiesValueCache = epmValueCache as EntryPropertiesValueCache; if (entryPropertiesValueCache != null) { propertyValue = this.ReadEntryPropertyValue( targetSegment.EpmInfo, entryPropertiesValueCache, typeReference.AsEntity()); } else { propertyValue = epmValueCache; ValidationUtils.ValidateIsExpectedPrimitiveType(propertyValue, typeReference); } return EpmWriterUtils.GetPropertyValueAsText(propertyValue); }
/// <summary> /// Checks if mappings could potentially result in mixed content and dis-allows it. /// </summary> /// <param name="currentSegment">Segment being processed.</param> /// <param name="ancestorHasContent">Does any of the ancestors have content.</param> /// <returns>boolean indicating if the tree is valid or not.</returns> private static bool HasMixedContent(EpmTargetPathSegment currentSegment, bool ancestorHasContent) { foreach (EpmTargetPathSegment childSegment in currentSegment.SubSegments.Where(s => !s.IsAttribute)) { if (childSegment.HasContent && ancestorHasContent) { return true; } if (HasMixedContent(childSegment, childSegment.HasContent || ancestorHasContent)) { return true; } } return false; }
internal EpmCustomContentWriterNodeData(EpmCustomContentWriterNodeData parentData, EpmTargetPathSegment segment, object element)
/// <summary> /// Sets the value <paramref name="propertyValue"/> on the <paramref name="currentValue"/> object /// </summary> /// <param name="currentSegment">Target path segment containing the corresponding attribute information</param> /// <param name="currentValue">Object on which to set property</param> /// <param name="propertyValue">Value to be set</param> /// <param name="deserializer">Current deserializer</param> internal void SetEpmValue(EpmTargetPathSegment currentSegment, Object currentValue, object propertyValue, EpmContentDeSerializerBase deserializer) { if (currentSegment.EpmInfo.Attribute.KeepInContent == false) { this.SetPropertyValueFromPath( currentSegment.EpmInfo.Attribute.SourcePath.Split('/'), this, currentValue, propertyValue, 0, deserializer); } }
/// <summary> /// Checks the validity of a tree. /// </summary> /// <param name="currentSegment">The segment to validate.</param> private static void DebugValidate(EpmTargetPathSegment currentSegment) { if (currentSegment.ParentSegment != null) { Debug.Assert(!currentSegment.ParentSegment.IsAttribute, "Attributes must be leaf nodes."); } // Walk recursively subsegments and validate them foreach (EpmTargetPathSegment subSegment in currentSegment.SubSegments) { DebugValidate(subSegment); } }
internal void Add(EntityPropertyMappingInfo epmInfo) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmInfo != null, "epmInfo != null"); String targetPath = epmInfo.Attribute.TargetPath; String namespaceUri = epmInfo.Attribute.TargetNamespaceUri; String namespacePrefix = epmInfo.Attribute.TargetNamespacePrefix; EpmTargetPathSegment currentSegment = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot; IList<EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!String.IsNullOrEmpty(targetPath), "Must have been validated during EntityPropertyMappingAttribute construction"); String[] targetSegments = targetPath.Split('/'); EpmTargetPathSegment foundSegment = null; EpmTargetPathSegment multiValueSegment = null; for (int i = 0; i < targetSegments.Length; i++) { String targetSegment = targetSegments[i]; if (targetSegment.Length == 0) { throw new ODataException(Strings.EpmTargetTree_InvalidTargetPath(targetPath)); } if (targetSegment[0] == '@' && i != targetSegments.Length - 1) { throw new ODataException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } foundSegment = activeSubSegments.SingleOrDefault( segment => segment.SegmentName == targetSegment && (epmInfo.IsSyndicationMapping || segment.SegmentNamespaceUri == namespaceUri) && segment.MatchCriteria(epmInfo.CriteriaValue, epmInfo.Criteria)); if (foundSegment != null) { currentSegment = foundSegment; if (currentSegment.EpmInfo != null && currentSegment.EpmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueProperty) { multiValueSegment = currentSegment; } } else { currentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, namespacePrefix, currentSegment); currentSegment.Criteria = epmInfo.Criteria; currentSegment.CriteriaValue = epmInfo.CriteriaValue; if (targetSegment[0] == '@') { activeSubSegments.Insert(0, currentSegment); } else { activeSubSegments.Add(currentSegment); } } activeSubSegments = currentSegment.SubSegments; } // If we're adding a multiValue property to already existing segment which maps to a non-multiValue property (no EpmInfo or one pointing to a non-multiValue property) // OR if we're adding a non-multiValue property to a segment which has multiValue in its path // we need to fail, since it's invalid to have multiValue property being mapped to the same top-level element as anything else. if ((epmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueProperty && foundSegment != null && (foundSegment.EpmInfo == null || foundSegment.EpmInfo.MultiValueStatus != EntityPropertyMappingMultiValueStatus.MultiValueProperty)) || (epmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.None && multiValueSegment != null)) { EntityPropertyMappingInfo multiValuePropertyEpmInfo = epmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueProperty ? epmInfo : multiValueSegment.EpmInfo; // Trying to map MultiValue property to the same target as something else which was already mapped there // It is ok to map to atom:category and atom:link elements with different sources only if the criteria values are different. if (epmInfo.CriteriaValue != null) { throw new ODataException(Strings.EpmTargetTree_MultiValueAndNormalPropertyMappedToTheSameConditionalTopLevelElement( multiValuePropertyEpmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name, EpmTargetTree.GetPropertyNameFromEpmInfo(multiValuePropertyEpmInfo), epmInfo.CriteriaValue)); } else { throw new ODataException(Strings.EpmTargetTree_MultiValueAndNormalPropertyMappedToTheSameTopLevelElement( multiValuePropertyEpmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name, EpmTargetTree.GetPropertyNameFromEpmInfo(multiValuePropertyEpmInfo))); } } Debug.Assert( epmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.None || epmInfo.IsSyndicationMapping, "Custom EPM mapping is not supported for multiValue properties."); // We only allow multiValues to map to ATOM constructs which can be repeated. if (epmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueItemProperty) { Debug.Assert( epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty, "Trying to add custom mapped property to a syndication target tree."); // Right now all the SyndicationItemProperty targets which do not have SyndicationParent.Entry are valid targets for multiValues // and all the ones which have SyndicationParent.Entry (Title, Updated etc.) are not valid targets for multiValues. if (epmInfo.SyndicationParent == EpmSyndicationParent.Entry) { throw new ODataException(Strings.EpmTargetTree_MultiValueMappedToNonRepeatableAtomElement( epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name, EpmTargetTree.GetPropertyNameFromEpmInfo(epmInfo))); } } Debug.Assert( epmInfo.MultiValueStatus != EntityPropertyMappingMultiValueStatus.MultiValueProperty || targetSegments.Length == 1, "MultiValue property itself can only be mapped to the top-level element."); if (currentSegment.EpmInfo != null) { if (currentSegment.EpmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueProperty) { Debug.Assert( epmInfo.MultiValueStatus == EntityPropertyMappingMultiValueStatus.MultiValueProperty, "MultiValue property values can't be mapped directly to the top-level element content (no such syndication mapping exists)."); // The info we're trying to add is a multiValue property, which would mean two multiValue properties trying to map to the same top-level element. // This can happen if the base type defines mapping for a multiValue property and the derived type defines it again // in which case we will try to add the derived type mapping again. // So we need to check that these properties are from the same source // It is ok to map to atom:category and atom:link elements with different sources only if the criteria values are different. if (epmInfo.Attribute.SourcePath != currentSegment.EpmInfo.Attribute.SourcePath) { if (epmInfo.CriteriaValue != null) { throw new ODataException(Strings.EpmTargetTree_TwoMultiValuePropertiesMappedToTheSameConditionalTopLevelElement( currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name, epmInfo.CriteriaValue)); } else { throw new ODataException(Strings.EpmTargetTree_TwoMultiValuePropertiesMappedToTheSameTopLevelElement( currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } } Debug.Assert( !foundSegment.EpmInfo.DefiningTypesAreEqual(epmInfo), "Trying to add a multiValue property mapping for the same property on the same type twice. The souce tree should have prevented this from happening."); // If the sources are the same (and the types are different), we can safely overwrite the epmInfo // with the new one (which is for the derived type) // The epm info is stored below. } else { Debug.Assert( epmInfo.MultiValueStatus != EntityPropertyMappingMultiValueStatus.MultiValueProperty, "Only non-multiValue propeties should get here, we cover the rest above."); // Two EpmAttributes with same TargetName in the inheritance hierarchy throw new ODataException(Strings.EpmTargetTree_DuplicateEpmAttrsWithSameTargetName(EpmTargetTree.GetPropertyNameFromEpmInfo(currentSegment.EpmInfo), currentSegment.EpmInfo.DefiningType.Name, currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath)); } } // Increment the number of properties for which KeepInContent is false if (!epmInfo.Attribute.KeepInContent) { if (epmInfo.IsAtomLinkMapping || epmInfo.IsAtomCategoryMapping) { this.countOfNonContentV3mappings++; } else { this.countOfNonContentV2mappings++; } } currentSegment.EpmInfo = epmInfo; // Mixed content is dis-allowed. Since root has no ancestor, pass in false for ancestorHasContent if (EpmTargetTree.HasMixedContent(this.NonSyndicationRoot, false)) { throw new ODataException(Strings.EpmTargetTree_InvalidTargetPath(targetPath)); } }
/// <summary> /// Override of the base Visitor method, which actually performs mapping search and serialization /// </summary> /// <param name="targetSegment">Current segment being checked for mapping</param> /// <param name="kind">Which sub segments to serialize</param> /// <param name="provider">Data Service provider used for rights verification.</param> protected override void Serialize(EpmTargetPathSegment targetSegment, EpmSerializationKind kind, DataServiceProviderWrapper provider) { if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Object propertyValue; try { propertyValue = epmInfo.ReadPropertyValue(this.Element, provider); } catch (System.Reflection.TargetInvocationException e) { ErrorHandler.HandleTargetInvocationException(e); throw; } if (propertyValue == null) { this.nullValuedProperties.Add(epmInfo); } String textPropertyValue = propertyValue != null ? PlainXmlSerializer.PrimitiveToString(propertyValue) : String.Empty; TextSyndicationContentKind contentKind = (TextSyndicationContentKind)epmInfo.Attribute.TargetTextContentKind; switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: this.CreateAuthor(false); this.author.Email = textPropertyValue; break; case SyndicationItemProperty.AuthorName: this.CreateAuthor(false); this.author.Name = textPropertyValue; this.authorNamePresent = true; break; case SyndicationItemProperty.AuthorUri: this.CreateAuthor(false); this.author.Uri = textPropertyValue; break; case SyndicationItemProperty.ContributorEmail: case SyndicationItemProperty.ContributorName: case SyndicationItemProperty.ContributorUri: this.SetContributorProperty(epmInfo.Attribute.TargetSyndicationItem, textPropertyValue); break; case SyndicationItemProperty.Updated: this.Target.LastUpdatedTime = EpmSyndicationContentSerializer.GetDate(propertyValue, Strings.EpmSerializer_UpdatedHasWrongType); break; case SyndicationItemProperty.Published: this.Target.PublishDate = EpmSyndicationContentSerializer.GetDate(propertyValue, Strings.EpmSerializer_PublishedHasWrongType); break; case SyndicationItemProperty.Rights: this.Target.Copyright = new TextSyndicationContent(textPropertyValue, contentKind); break; case SyndicationItemProperty.Summary: this.Target.Summary = new TextSyndicationContent(textPropertyValue, contentKind); break; case SyndicationItemProperty.Title: this.Target.Title = new TextSyndicationContent(textPropertyValue, contentKind); break; default: Debug.Fail("Unhandled SyndicationItemProperty enum value - should never get here."); break; } } else { base.Serialize(targetSegment, kind, provider); } }
private void WriteParentSegment(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { if (targetSegment.SegmentName == "author") { AtomPersonMetadata item = this.WritePersonEpm(targetSegment, epmValueCache, typeReference); if (item != null) { List<AtomPersonMetadata> authors = (List<AtomPersonMetadata>) this.entryMetadata.Authors; if (authors == null) { authors = new List<AtomPersonMetadata>(); this.entryMetadata.Authors = authors; } authors.Add(item); } } else { if (!(targetSegment.SegmentName == "contributor")) { throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteParentSegment_TargetSegmentName)); } AtomPersonMetadata metadata2 = this.WritePersonEpm(targetSegment, epmValueCache, typeReference); if (metadata2 != null) { List<AtomPersonMetadata> contributors = (List<AtomPersonMetadata>) this.entryMetadata.Contributors; if (contributors == null) { contributors = new List<AtomPersonMetadata>(); this.entryMetadata.Contributors = contributors; } contributors.Add(metadata2); } } }
/// <summary> /// Used for creating non-root nodes in the syndication/custom trees. /// </summary> /// <param name="segmentName">Name of xml element/attribute</param> /// <param name="segmentNamespaceUri">URI of the namespace for <paramref name="segmentName"/></param> /// <param name="segmentNamespacePrefix">Namespace prefix to be used for <paramref name="segmentNamespaceUri"/></param> /// <param name="parentSegment">Reference to the parent node if this is a sub-node, useful for traversals in visitors</param> internal EpmTargetPathSegment(String segmentName, String segmentNamespaceUri, String segmentNamespacePrefix, EpmTargetPathSegment parentSegment) : this() { DebugUtils.CheckNoExternalCallers(); Debug.Assert(segmentName == null || segmentName.Length > 0, "Empty segment name is not allowed."); this.segmentName = segmentName; this.segmentNamespaceUri = segmentNamespaceUri; this.segmentNamespacePrefix = segmentNamespacePrefix; this.parentSegment = parentSegment; }
/// <summary> /// Writes a non-leaf segment which has sub segments. /// </summary> /// <param name="targetSegment">The segment being written</param> /// <param name="epmValueCache">EPM value cache to use to get property values, or a primitive value</param> /// <param name="typeReference">The type of the entry or collection item.</param> private void WriteParentSegment(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { Debug.Assert(targetSegment != null, "targetSegment != null"); if (targetSegment.SegmentName == AtomConstants.AtomAuthorElementName) { AtomPersonMetadata authorMetadata = this.WritePersonEpm(targetSegment, epmValueCache, typeReference); if (authorMetadata != null) { List<AtomPersonMetadata> authors = (List<AtomPersonMetadata>)this.entryMetadata.Authors; if (authors == null) { authors = new List<AtomPersonMetadata>(); this.entryMetadata.Authors = authors; } authors.Add(authorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomContributorElementName) { AtomPersonMetadata contributorMetadata = this.WritePersonEpm(targetSegment, epmValueCache, typeReference); if (contributorMetadata != null) { List<AtomPersonMetadata> contributors = (List<AtomPersonMetadata>)this.entryMetadata.Contributors; if (contributors == null) { contributors = new List<AtomPersonMetadata>(); this.entryMetadata.Contributors = contributors; } contributors.Add(contributorMetadata); } } else { // Unhandled EpmTargetPathSegment.SegmentName. throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteParentSegment_TargetSegmentName)); } }
internal void Add(EntityPropertyMappingInfo epmInfo) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmInfo != null, "epmInfo != null"); string targetPath = epmInfo.Attribute.TargetPath; string namespaceUri = epmInfo.Attribute.TargetNamespaceUri; string namespacePrefix = epmInfo.Attribute.TargetNamespacePrefix; EpmTargetPathSegment currentSegment = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot; IList<EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!string.IsNullOrEmpty(targetPath), "Must have been validated during EntityPropertyMappingAttribute construction"); string[] targetSegments = targetPath.Split('/'); EpmTargetPathSegment foundSegment = null; for (int i = 0; i < targetSegments.Length; i++) { string targetSegment = targetSegments[i]; if (targetSegment.Length == 0) { throw new ODataException(Strings.EpmTargetTree_InvalidTargetPath_EmptySegment(targetPath)); } if (targetSegment[0] == '@' && i != targetSegments.Length - 1) { throw new ODataException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } foundSegment = activeSubSegments.SingleOrDefault( segment => segment.SegmentName == targetSegment && (epmInfo.IsSyndicationMapping || segment.SegmentNamespaceUri == namespaceUri)); if (foundSegment != null) { currentSegment = foundSegment; } else { currentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, namespacePrefix, currentSegment); if (targetSegment[0] == '@') { activeSubSegments.Insert(0, currentSegment); } else { activeSubSegments.Add(currentSegment); } } activeSubSegments = currentSegment.SubSegments; } if (currentSegment.EpmInfo != null) { // Two EpmAttributes with same TargetName in the inheritance hierarchy throw new ODataException(Strings.EpmTargetTree_DuplicateEpmAttributesWithSameTargetName(currentSegment.EpmInfo.DefiningType.ODataFullName(), EpmTargetTree.GetPropertyNameFromEpmInfo(currentSegment.EpmInfo), currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath)); } // Increment the number of properties for which KeepInContent is false if (!epmInfo.Attribute.KeepInContent) { this.countOfNonContentV2Mappings++; } currentSegment.EpmInfo = epmInfo; // Mixed content is dis-allowed. List<EntityPropertyMappingAttribute> conflictingAttributes = new List<EntityPropertyMappingAttribute>(2); if (EpmTargetTree.HasMixedContent(this.NonSyndicationRoot, conflictingAttributes)) { Debug.Assert(conflictingAttributes.Count == 2, "Expected to find exactly two conflicting attributes."); throw new ODataException(Strings.EpmTargetTree_InvalidTargetPath_MixedContent(conflictingAttributes[0].TargetPath, conflictingAttributes[1].TargetPath)); } }