2015-04-29 3 views
2

Я уверен, что этот процесс, который у меня есть, имеет много недостатков, поэтому не стесняйтесь указывать на все, что вы видите на этом пути.Скребок HTML для объекта, а затем AutoMapper для модели

У меня есть входящий HTML-адрес электронной почты, который мне нужно очистить от большой информации. У меня есть эта информация, которая входит в действительно простой список, но затем я хотел бы сопоставить ее с определенной моделью, с которой я смогу работать.

HTML, электронная почта выглядит следующим образом:

<tr> 
    <td>Name: </td> 
    <td>Larry Smith</td> 
</tr> 
<tr> 
    <td>Email: </td> 
    <td>[email protected]</td> 
</tr> 
<tr> 
    <td>Phone: </td> 
    <td>(101)123-4567 (Mobile)</td> 
</tr> 

Я использую HTMLAgilityPack разобрать его в этот объект:

public class RawData 
{ 
    public string Name { get; set; } 
    public string Value { get; set; } 
} 

Таким образом, объект после синтаксического анализа выглядит следующим образом

Моя модель очень похожа. ЗА ИСКЛЮЧЕНИЕМ, что свойства фактически названы не родовое:

public class FullModel 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    ...etc.... 
} 

Итак, теперь мы добраться до сути проблемы ... Попытка построить карту с AutoMapper, чтобы выровнять все.

Mapper.CreateMap<RawData, FullData>() 
    .ForMember(dest => dest.FullName, 
    opts => opts.MapFrom(src => src.Name)); 

но конечно .... Есть около 80 свойств в объекте RAWDATA, которые являются полями .... и RAWDATA является списком для загрузки.

Должен ли я отказаться от своего объекта и сопоставления RawData, а вместо этого в методе парсера электронной почты scrape найти свойство FullData, которому оно принадлежит, и заполнить его?

Другие идеи и вход Добро пожаловать

Спасибо

+0

Просто чтобы понять ... 'IEnumerable ' '' FullModel' (вы показываете только 'RawData'' Model', но вы пропустите множество разных значений ...) –

ответ

3

Я думаю Я понимаю это, и я в надежде, что код у вас есть только один метод, который вы бы пытались (но, очевидно, не работает, как ожидается). С учетом этого:

С моей точки зрения, это похоже на то, что вы хотите create a custom ValueResolver, который найдет подходящий «ключ» для этого свойства. Что-то вроде:

class RawDataNameResolver : ValueResolver<IEnumerable<RawData>, String> 
{ 
    private String _name; 

    public RawDataNameResolver(String name) 
    { 
     _name = name; 
    } 

    protected override String ResolveCore(IEnumerable<RawData> source) 
    { 
     if (source != null) 
     { 
      var match = source.SingleOrDefault(x => x.Name == _name); 
      if (match != null) 
      { 
       return match.Value; 
      } 
     } 
     return null; 
    } 
} 

Это держит его довольно общий, так что вы можете повторно использовать его в отображении:

Mapper.CreateMap<IEnumerable<RawData>, FullModel>() 
    .ForMember(d => d.Email, m => m.ResolveUsing(new RawDataNameResolver("Email: "))) 
    .ForMember(d => d.Name, m => m.ResolveUsing(new RawDataNameResolver("Name: "))) 
    .ForMember(d => d.PhoneNumber, m => m.ResolveUsing(new RawDataNameResolver("Phone: "))); 

(Обратите внимание, как я передаю «имя» значение в так е может выполнять сравнить и получить обратно «Значение»).

Это обеспечит:

var rawData = new[]{ // pretend this just read an email ;-) 
    new RawData { Name = "Name: ", Value = "Larry Smith" }, 
    new RawData { Name = "Email: ", Value = "[email protected]" }, 
    new RawData { Name = "Phone: ", Value = "(101)123-4567 (Mobile)" } 
} 
var fullModel = Mapper.Map<FullModel>(rawData); 

Какие результаты в:

new FullModel { 
    Email = "[email protected]", 
    Name = "Larry Smith",   // Yes, I've combined them! 
    PhoneNumber = "(101)123-4567 (Mobile) 
}; 

Теперь, если вы хотите, чтобы имя, фамилию можно модифицировать ValueResolver немного больше, так что вы можете выполнить некоторые пост -переработка.Может быть что-то вроде:

class RawDataNameResolver : ValueResolver<IEnumerable<RawData>, String> 
{ 
    private String _name; 
    private Func<String, String> _postProcessor; 

    public RawDataNameResolver(String name, Func<String, String> postProcessor = null) 
    { 
     _name = name; 
     _postProcessor = postProcessor; 
    } 

    protected override String ResolveCore(IEnumerable<RawData> source) 
    { 
     if (source != null) 
     { 
      var match = source.SingleOrDefault(x => x.Name == _name); 
      if (match != null) 
      { 
       return _postProcessor != null ? _postProcessor(match.Value) : match.Value; 
      } 
     } 
     return null; 
    } 
} 

(Примечание я добавил пост-процессор, поэтому мы можем выполнить манипуляции на значение, как только мы его)

Это меняет нашу процедуру отображения (но только слегка):

Mapper.CreateMap<IEnumerable<RawData>, FullModel>() 
    .ForMember(d => d.Email, m => m.ResolveUsing(new RawDataNameResolver("Email: "))) 
    .ForMember(d => d.FirstName, m => m.ResolveUsing(new RawDataNameResolver("Name: ", x => x.Split()[0]))) 
    .ForMember(d => d.LastName, m => m.ResolveUsing(new RawDataNameResolver("Name: ", x => x.Split()[1]))) 
    .ForMember(d => d.PhoneNumber, m => m.ResolveUsing(new RawDataNameResolver("Phone: "))); 

который теперь приводит:

new FullModel { 
    Email = "[email protected]", 
    FirstName = "Larry", 
    LastName = "Smith", 
    PhoneNumber = "(101)123-4567 (Mobile) 
}; 

То же самое можно было бы применить к Парс номер телефона (удалите (mobile) или просто нормализовать его). Кроме того, имейте в виду, что это не «готовность производства». Я настоятельно рекомендую вам не просто использовать .Split()[0] и на самом деле сломать это во что-то более пуленепробиваемое (как и в других местах, где я не выполнял проверки).

+0

Это было прекрасно. Не знаю, как дать вам больше очков, но если бы мог. СПАСИБО!! – GPGVM

+0

Не проблема, рада помочь! –

Смежные вопросы