0

ここで解決できない問題があります。ここに解析したい html のようなものがいくつかあるとしましょう。このすべての html は、ページ上の 1 つのリスト内にあります。そして、私が書いた例のように名前が繰り返されます。

<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 packを使用して、すべての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 オブジェクトの数が異なる可能性があることです。したがって、ある日、Web ページの日付 1 の下に 1 つの lol オブジェクトがあり、次の日には 10 個の lol オブジェクトがある場合があります。したがって、区切り記号の間にある lol オブジェクトの数をどうにかして数えるためのスマートで簡単な方法があれば、私はうんざりしています。または、これを理解する別の方法がある場合は?たとえば、htmlagilitypack 内。はい、最初のオブジェクトの前だけでなく、すべての lol オブジェクトの前に正しい日付が必要です。セパレータークラスが最後の lol オブジェクトの下で終了していれば、これは簡単なことでしたが、残念ながらそうではありません...ここにコードを貼り付ける必要はないと思いますが、基本的にはページを解析し、seperators オブジェクトと lol オブジェクトを抽出してリストに追加します。そこでそれらを seperator オブジェクトと lol オブジェクトに分割します。

4

1 に答える 1

0

これが計画です。すべてのseperator要素を選択してから、目的のクラスを持つ連続した兄弟要素をすべて見つけます。

残念ながら、現在のバージョンの HTML Agility Pack で兄弟のコレクションを取得する簡単な方法はありません。(1 つの) 次の兄弟にしかアクセスできません。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(),
    };
于 2012-10-07T03:12:58.450 に答える