I can suggest the following solution:
You need to implement a custom field reader with a custom field converter:
using Sitecore.DataExchange.DataAccess;
namespace Example
{
public interface IBaseValueReader: IValueReader
{
string AttributeName { get; set; }
}
}
AddressFieldReader:
using System;
using Sitecore.DataExchange.DataAccess;
using Sitecore.DataExchange.Repositories;
namespace Example
{
public class AddressFieldReader : IBaseValueReader
{
public string AttributeName { get; set; }
public IItemModelRepository Repository { get; private set; }
public ExampleFieldReader(IItemModelRepository repository)
{
Repository = repository;
}
public CanReadResult CanRead(object source, DataAccessContext context)
{
return new CanReadResult()
{
CanReadValue = true
};
}
public ReadResult Read(object source, DataAccessContext context)
{
object result = (object)null;
var sourceObject = source as Microsoft.Xrm.Sdk.Entity;
if (sourceObject != null && AttributeName != null)
{
object value;
//Try to read attribute by the attribute name
if (sourceObject.Attributes.TryGetValue(AttributeName, out value))
{
//Then you need to cast it to the address field type
var searchObject = value as Microsoft.Xrm.Sdk.Money; //It is example. You need to debug and see which type you exactly get.
//Then you need to check if field is not null and have value.
if (searchObject != null && searchObject.Value != Decimal.Zero)
{
var fieldValue = searchObject.Value;
//Now, when you got a value of field, you can use any API to get GeoLocation.
// Your code here:
var geoLocation = fieldValue;
//Then you should return result:
return new ReadResult(DateTime.UtcNow)
{
WasValueRead = true,
ReadValue = geoLocation
};
}
}
}
return new ReadResult(DateTime.UtcNow)
{
WasValueRead = true,
ReadValue = String.Empty
};
}
}
}
AddressFieldReaderConverter:
using Sitecore.DataExchange.DataAccess;
using Sitecore.DataExchange.Extensions;
using Sitecore.DataExchange.Repositories;
using Sitecore.Services.Core.Model;
using System;
using Sitecore.DataExchange.Converters;
namespace Example
{
public class AddressFieldReaderConverter : BaseItemModelConverter<ItemModel, IValueReader>
{
private AddressFieldReader _reader = (AddressFieldReader)null;
private static readonly Guid TemplateId = Guid.Parse("{C3C9E93C-F197-4FBD-820D-DCB565707AF7}");
public AddressFieldReaderConverter(IItemModelRepository repository)
: base(repository)
{
this.SupportedTemplateIds.Add(TemplateId);
}
public override bool CanConvert(ItemModel source)
{
return true;
}
public override IValueReader Convert(ItemModel source)
{
if (source == null)
{
Sitecore.DataExchange.Context.Logger.Error("Cannot convert null item to value reader. (converter: {0})", (object)this.GetType().FullName);
return (IValueReader)null;
}
if (!this.CanConvert(source))
{
Sitecore.DataExchange.Context.Logger.Error("Cannot convert item to value reader. (item: {0}, converter: {1})", (object)source.GetItemId(), (object)this.GetType().FullName);
return (IValueReader)null;
}
if (_reader == null)
_reader = new AddressFieldReader(ItemModelRepository);
return (IValueReader)_reader;
}
}
}
You also need to implement a Value Accessor for passing the Attribute Name Value from the Value Accessor to the Field Reader:
using Sitecore.DataExchange.Converters.DataAccess.ValueAccessors;
using Sitecore.DataExchange.DataAccess;
using Sitecore.DataExchange.DataAccess.Writers;
using Sitecore.DataExchange.Providers.DynamicsCrm.DataAccess.Readers;
using Sitecore.DataExchange.Repositories;
using Sitecore.Services.Core.Model;
using System;
namespace Example
{
public class CustomValueAccessorConverter : ValueAccessorConverter
{
private static readonly Guid TemplateId = Guid.Parse("{C3C9E93C-F197-4FBD-820D-DCB565707AF7}");
public LookupValueAccessorConverter(IItemModelRepository repository)
: base(repository)
{
this.SupportedTemplateIds.Add(LookupValueAccessorConverter.TemplateId);
}
public override IValueAccessor Convert(ItemModel source)
{
IValueAccessor valueAccessor = base.Convert(source);
if (valueAccessor == null)
return (IValueAccessor)null;
string stringValue = this.GetStringValue(source, "AttributeName");
if (string.IsNullOrWhiteSpace(stringValue))
return (IValueAccessor)null;
bool boolValue = this.GetBoolValue(source, "UseValueProperty");
if (valueAccessor.ValueReader == null)
{
EntityAttributeValueReader attributeValueReader = new EntityAttributeValueReader(stringValue);
if (this.GetBoolValue(source, "UseValueProperty"))
attributeValueReader.UseValueProperty = true;
valueAccessor.ValueReader = (IValueReader)attributeValueReader;
}
else
{
//Custom part. Initialize attribute for read
var customFieldReader = valueAccessor.ValueReader as IBaseValueReader;
if (customFieldReader != null)
{
customFieldReader.AttributeName = stringValue;
}
}
if (valueAccessor.ValueWriter == null && !boolValue)
valueAccessor.ValueWriter = (IValueWriter)new IndexerPropertyValueWriter(new object[1]
{
(object) stringValue
});
return valueAccessor;
}
}
}
Then you need to create a template for AddressField Reader and inherit it from the Value Reader template (/sitecore/templates/Data Exchange/Framework/Data Access/Value Readers/Value Reader):

Then, based on this template, you need to create a Value Reader Item (make sure the converter is correct):

The next step is to create a Value Accessor for your import object (make sure the Converter type set to your custom implemented):

Then you can use this Value Accessor in your Value Mapping Set.
Then you need to run an import and see if it is works. Take into account that it is not exactly your solution. It is just an example. You need debug and correct this code.