重复一个只出现几次并且与htmlagilitypack c#具有不同值的对象。

时间:2012-10-07 02:33:15

标签: html-agility-pack

我有一个问题,我似乎无法在这里解决。让我说我有一些喜欢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个单独的日期。

1 个答案:

答案 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(),
    };