gpt4 book ai didi

c# - 将 HTML 抓取为对象,然后将 AutoMapper 抓取为模型

转载 作者:行者123 更新时间:2023-11-30 21:58:36 25 4
gpt4 key购买 nike

我很确定我已经讨论过的这个过程有很多不足之处,所以请随时指出您在此过程中看到的任何问题。

我有一封传入的 HTML 电子邮件,我需要从中提取大量信息。我将这些信息放入一个非常简单的列表中,但我想将其映射到一个我可以使用的特定模型中。

HTML 电子邮件如下所示:

<tr>
<td>Name: </td>
<td>Larry Smith</td>
</tr>
<tr>
<td>Email: </td>
<td>larry@cucumber.com</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 构建 map 以将所有内容对齐。

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

但是当然......在 RawData 对象中大约有 80 个属性是字段......而 RawData 是一个要启动的列表。

我是否应该放弃我的 RawData 对象和映射,而是在电子邮件抓取解析方法中找到它所属的 FullData 属性并填充它?

欢迎提出其他想法和意见

谢谢

最佳答案

认为我理解这一点,并希望您拥有的代码只是您尝试过的一种方法(但显然没有按预期工作)。话虽如此:

从我的角度来看,您似乎想要 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: ")));

(请注意我是如何传递“名称”值的,以便 e 可以执行比较并接收回“值”)。

这将提供:

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

结果是:

new FullModel {
Email = "larry@cucumber.com",
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 = "larry@cucumber.com",
FirstName = "Larry",
LastName = "Smith",
PhoneNumber = "(101)123-4567 (Mobile)
};

同样可以应用于解析 PhoneNumber(删除 (mobile) 或只是对其进行规范化)。另外,请记住这不是“生产就绪”。我强烈建议您不要只使用 .Split()[0] 并将其分解成更可靠的东西(与我没有执行检查的其他地方一样)。

关于c# - 将 HTML 抓取为对象,然后将 AutoMapper 抓取为模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29956538/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com