我有一个问题,我似乎无法在这里解决。让我说我有一些喜欢beneth的html,我想解析。所有这些html都在页面上的一个列表中。这些名字就像我写的例子一样重复自己。
<li class = "seperator"> a date </li>
<li class = "lol"> some text </li>
<li class = "lol"> some text </li>
<li class = "lol"> some text </li>
<li class = "seperator"> a new date </li>
<li class = "lol"> some text </li>
<li class = "seperator"> a nother new date </li>
<li class = "lol"> some text </li>
<li class = "lol"> some text </li>
我确实设法使用htmlagility包来解析每个li对象的分离,并且几乎按照我想要的方式形成它。我的print atm看起来像这样:
"a date" "some text"
"some text"
"some text"
"some text"
"a new date" "some text"
"a nother new date " "some text"
"some text"
"some text"
我想要实现的目标:
"a date" "some text"
"a date" "some text"
"a date" "some text"
"a date" "some text"
"a new date" "some text"
"a nother new date " "some text"
"a nother new date " "some text"
"a nother new date " "some text"
但问题是在每个分隔符下面,每个lol对象的数量可能会有所不同。所以有一天,网页可能有一个lol对象beneth日期1,第二天它可能有10个lol对象。所以我想知道是否有一种聪明/简单的方法以某种方式计算分隔符之间的lol对象的数量。或者,如果有另一种方法来解决这个问题?例如htmlagilitypack。是的,我需要在每个lol对象前面的正确日期,而不仅仅是在第一个对象面前。如果分离器类会在最后一个lol对象下面结束,这本来就是一块蛋糕,但遗憾的是情况并非如此......我不认为我需要在这里粘贴我的代码,但基本上我做的是解析页面,提取分隔符和lol对象,并将它们添加到列表中,然后将其拆分为分隔符和lol对象。然后我将它打印到一个文件,因为分隔符只出现3次(在示例中)我将只出3个单独的日期。
答案 0 :(得分:0)
这是计划,选择所有seperator
元素,然后找到具有所需类的所有连续兄弟元素。
不幸的是,在当前版本的HTML Agility Pack中没有简单的方法来获取兄弟姐妹的集合,您只能访问(下一个)兄弟姐妹。很难使用LINQ从链接结构中收集数据。由于HTML中没有真正的层次结构,这将是一个挑战。
如果您有XPath可用,则可以使用following-sibling
轴将所有后续兄弟元素与TakeWhile()
方法结合使用,以执行以下操作:
var htmlStr = @"<li class = ""seperator""> a date </li>
<li class = ""lol""> some text </li>
<li class = ""lol""> some text </li>
<li class = ""lol""> some text </li>
<li class = ""seperator""> a new date </li>
<li class = ""lol""> some text </li>
<li class = ""seperator""> a nother new date </li>
<li class = ""lol""> some text </li>
<li class = ""lol""> some text </li>";
var doc = new HtmlDocument();
doc.LoadHtml(htmlStr);
var data =
from li in doc.DocumentNode.SelectNodes("li[@class='seperator']")
select new
{
Separator = li.InnerText,
Content = li.SelectNodes("following-sibling::li")
.TakeWhile(sli => sli.Attributes["class"].Value == "lol")
.Select(sli => sli.InnerText)
.ToList(),
};
否则,如果您没有可用的XPath,则可以使用以下内容从任何链接结构创建可枚举:
public static class Extensions
{
public static IEnumerable<TSource> ToLinkedEnumerable<TSource>(
this TSource source,
Func<TSource, TSource> nextSelector,
Func<TSource, bool> predicate)
{
for (TSource current = nextSelector(source);
predicate(current);
current = nextSelector(current))
yield return current;
}
public static IEnumerable<TSource> ToLinkedEnumerable<TSource>(
this TSource source, Func<TSource, TSource> nextSelector)
where TSource : class
{
return ToLinkedEnumerable(source, nextSelector, src => src != null);
}
}
然后您的查询现在变为:
var data =
from li in doc.DocumentNode.Elements("li")
where li.Attributes["class"].Value == "seperator"
select new
{
Separator = li.InnerText,
Content = li.ToLinkedEnumerable(sli => sli.NextSibling)
.Where(sli => sli.Name == "li")
.TakeWhile(sli => sli.Attributes["class"].Value == "lol")
.Select(sli => sli.InnerText)
.ToList(),
};