protected virtual SemanticSchemaField ValidateField(Validation validation, FieldSemantics fieldSemantics) { Log.Debug($"Field {fieldSemantics} is validated over the main {validation.MainSchema}."); SemanticSchemaField field = validation.MainSchema.FindFieldBySemantics(fieldSemantics); if (field == null) { foreach (SemanticSchema semanticSchema in validation.InheritedSchemas) { Log.Debug( $"Field {fieldSemantics} is validated over the inherited {semanticSchema}."); field = semanticSchema.FindFieldBySemantics(fieldSemantics); if (field != null) { break; } } } if (field == null) { Log.Debug($"Field {fieldSemantics} has not been found."); } return(field); }
protected virtual object FindFieldValue(SemanticSchemaField semanticSchemaField, ContentModelData fields, int embedLevel) { string[] pathSegments = semanticSchemaField.Path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); object fieldValue = null; foreach (string pathSegment in pathSegments.Skip(embedLevel + 1)) { if ((fields == null) || !fields.TryGetValue(pathSegment, out fieldValue)) { return(null); } if (fieldValue is ContentModelData[]) { fields = ((ContentModelData[])fieldValue)[0]; } else { fields = fieldValue as ContentModelData; } } return(fieldValue); }
protected virtual object MapEmbeddedFields(ContentModelData embeddedFields, Type targetType, SemanticSchemaField semanticSchemaField, string contextXPath, MappingData mappingData) { MappingData embeddedMappingData = new MappingData { ModelType = targetType, PropertyValidation = mappingData.PropertyValidation, EmbeddedSemanticSchemaField = semanticSchemaField, EmbedLevel = mappingData.EmbedLevel + 1, SourceViewModel = mappingData.SourceViewModel, Fields = embeddedFields, MetadataFields = embeddedFields, ContextXPath = contextXPath, Localization = mappingData.Localization }; return(CreateViewModel(embeddedMappingData)); }
protected virtual object MapField(object fieldValues, Type modelPropertyType, SemanticSchemaField semanticSchemaField, MappingData mappingData) { Type sourceType = fieldValues.GetType(); bool isArray = sourceType.IsArray; if (isArray) { sourceType = sourceType.GetElementType(); } bool isListProperty = modelPropertyType.IsGenericList(); Type targetType = modelPropertyType.GetUnderlyingGenericListType() ?? modelPropertyType; // Convert.ChangeType cannot convert non-nullable types to nullable types, so don't try that. Type bareTargetType = modelPropertyType.GetUnderlyingNullableType() ?? targetType; IList mappedValues = targetType.CreateGenericList(); if (typeof(EntityModel).IsAssignableFrom(targetType) && sourceType != typeof(EntityModelData) && (sourceType == typeof(string) && string.IsNullOrEmpty((string)fieldValues))) { return(isListProperty ? mappedValues : null); } switch (sourceType.Name) { case "String": if (isArray) { foreach (string fieldValue in (string[])fieldValues) { mappedValues.Add(MapString(fieldValue, bareTargetType)); } } else { mappedValues.Add(MapString((string)fieldValues, bareTargetType)); } break; case "DateTime": case "Single": case "Double": if (isArray) { foreach (object fieldValue in (Array)fieldValues) { mappedValues.Add(Convert.ChangeType(fieldValue, bareTargetType)); } } else { mappedValues.Add(Convert.ChangeType(fieldValues, bareTargetType)); } break; case "RichTextData": if (isArray) { foreach (RichTextData fieldValue in (RichTextData[])fieldValues) { mappedValues.Add(MapRichText(fieldValue, targetType, mappingData.Localization)); } } else { mappedValues.Add(MapRichText((RichTextData)fieldValues, targetType, mappingData.Localization)); } break; case "ContentModelData": string fieldXPath = semanticSchemaField.GetXPath(mappingData.ContextXPath); if (isArray) { int index = 1; foreach (ContentModelData embeddedFields in (ContentModelData[])fieldValues) { string indexedFieldXPath = $"{fieldXPath}[{index++}]"; mappedValues.Add(MapEmbeddedFields(embeddedFields, targetType, semanticSchemaField, indexedFieldXPath, mappingData)); } } else { string indexedFieldXPath = $"{fieldXPath}[1]"; mappedValues.Add(MapEmbeddedFields((ContentModelData)fieldValues, targetType, semanticSchemaField, indexedFieldXPath, mappingData)); } break; case "EntityModelData": if (isArray) { foreach (EntityModelData entityModelData in (EntityModelData[])fieldValues) { mappedValues.Add(MapComponentLink(entityModelData, targetType, mappingData.Localization)); } } else { mappedValues.Add(MapComponentLink((EntityModelData)fieldValues, targetType, mappingData.Localization)); } break; case "KeywordModelData": if (isArray) { foreach (KeywordModelData keywordModelData in (KeywordModelData[])fieldValues) { mappedValues.Add(MapKeyword(keywordModelData, targetType, mappingData.Localization)); } } else { mappedValues.Add(MapKeyword((KeywordModelData)fieldValues, targetType, mappingData.Localization)); } break; default: throw new DxaException($"Unexpected field type: '{sourceType.Name}'."); } return(isListProperty ? mappedValues : ((mappedValues.Count == 0) ? null : mappedValues[0])); }
protected virtual void MapSemanticProperties(ViewModel viewModel, MappingData mappingData) { Type modelType = viewModel.GetType(); IDictionary <string, List <SemanticProperty> > propertySemanticsMap = ModelTypeRegistry.GetPropertySemantics(modelType); IDictionary <string, string> xpmPropertyMetadata = new Dictionary <string, string>(); Validation validation = mappingData.PropertyValidation; foreach (KeyValuePair <string, List <SemanticProperty> > propertySemantics in propertySemanticsMap) { PropertyInfo modelProperty = modelType.GetProperty(propertySemantics.Key); List <SemanticProperty> semanticProperties = propertySemantics.Value; bool isFieldMapped = false; string fieldXPath = null; foreach (SemanticProperty semanticProperty in semanticProperties) { if (semanticProperty.PropertyName == SemanticProperty.AllFields) { modelProperty.SetValue(viewModel, GetAllFieldsAsDictionary(mappingData)); isFieldMapped = true; break; } if ((semanticProperty.PropertyName == SemanticProperty.Self) && validation.MainSchema.HasSemanticType(semanticProperty.SemanticType)) { try { object mappedSelf = MapComponentLink((EntityModelData)mappingData.SourceViewModel, modelProperty.PropertyType, mappingData.Localization); modelProperty.SetValue(viewModel, mappedSelf); isFieldMapped = true; break; } catch (Exception ex) { Log.Debug($"Self mapping failed for {modelType.Name}.{modelProperty.Name}: {ex.Message}"); continue; } } FieldSemantics fieldSemantics = new FieldSemantics( semanticProperty.SemanticType.Vocab, semanticProperty.SemanticType.EntityName, semanticProperty.PropertyName, null); SemanticSchemaField semanticSchemaField = (mappingData.EmbeddedSemanticSchemaField == null) ? ValidateField(validation, fieldSemantics) : mappingData.EmbeddedSemanticSchemaField.FindFieldBySemantics(fieldSemantics); if (semanticSchemaField == null) { // No matching Semantic Schema Field found for this Semantic Property; maybe another one will match. continue; } // Matching Semantic Schema Field found fieldXPath = IsFieldFromMainSchema(validation, fieldSemantics) ? semanticSchemaField.GetXPath(mappingData.ContextXPath) : null; ContentModelData fields = semanticSchemaField.IsMetadata ? mappingData.MetadataFields : mappingData.Fields; object fieldValue = FindFieldValue(semanticSchemaField, fields, mappingData.EmbedLevel); if (fieldValue == null) { // No field value found; maybe we will find a value for another Semantic Property. continue; } try { object mappedPropertyValue = MapField(fieldValue, modelProperty.PropertyType, semanticSchemaField, mappingData); modelProperty.SetValue(viewModel, mappedPropertyValue); } catch (Exception ex) { throw new DxaException( $"Unable to map field '{semanticSchemaField.Name}' to property {modelType.Name}.{modelProperty.Name} of type '{modelProperty.PropertyType.FullName}'.", ex); } isFieldMapped = true; break; } if (fieldXPath != null) { xpmPropertyMetadata.Add(modelProperty.Name, fieldXPath); } else if (!isFieldMapped && Log.IsDebugEnabled) { string formattedSemanticProperties = string.Join(", ", semanticProperties.Select(sp => sp.ToString())); Log.Debug( $"Property {modelType.Name}.{modelProperty.Name} cannot be mapped to a CM field of {validation.MainSchema}. Semantic properties: {formattedSemanticProperties}."); } } EntityModel entityModel = viewModel as EntityModel; if ((entityModel != null) && mappingData.Localization.IsXpmEnabled) { entityModel.XpmPropertyMetadata = xpmPropertyMetadata; } }