Использование Html Agility Pack для анализа узлов контекстно-зависимым способом - PullRequest
1 голос
/ 10 апреля 2011
<div class="mvb"><b>Date 1</b></div>
<div class="mxb"><b>Header 1</b></div>
<div>
   inner hmtl 1
</div>

<div class="mvb"><b>Date 2</b></div>
<div class="mxb"><b>Header 2</b></div>
<div>
inner html 2
</div>

Я бы хотел проанализировать внутренний HTML-код между тегами таким образом, чтобы я мог

Другими словами, во время анализа внутреннего html 1 я хотел бы знать, что html-узлы, содержащие «Date 1» и «Header 1», были проанализированы (но узлы, содержащие «Date 2» и «Header 2 "не было разобрано)

Если бы я делал это с помощью обычного анализа текста, я бы читал по одной строке за раз и записывал последние «Дата» и «Заголовок», которые я проанализировал. Затем, когда пришло время проанализировать внутренний html 1, я мог обратиться к последнему проанализированному объекту «Date» и «Header», чтобы связать их вместе.

Ответы [ 2 ]

1 голос
/ 18 апреля 2011

Используя Html Agility Pack, вы можете использовать возможности XPATH - и забыть об этом подробном дерьме xlinq :-).Функция XPATH position () является контекстно-зависимой.Вот пример кода:

    HtmlDocument doc = new HtmlDocument();
    doc.Load("your html file");

    // select all DIV without a CLASS attribute defined
    foreach (HtmlNode div in doc.DocumentNode.SelectNodes("//div[not(@class)]"))
    {
        Console.WriteLine("div=" + div.InnerText.Trim());
        Console.WriteLine("  header=" + div.SelectSingleNode("preceding-sibling::div[position()=1]/b").InnerText);
        Console.WriteLine("  date=" + div.SelectSingleNode("preceding-sibling::div[position()=2]/b").InnerText);
    }

Это напечатает это с вашим образцом:

div=inner hmtl 1
  header=Header 1
  date=Date 1
div=inner html 2
  header=Header 2
  date=Date 2
0 голосов
/ 16 апреля 2011

Ну, вы можете сделать это несколькими способами ...

Например, если HTML-код, который вы хотите проанализировать, является тем, который вы написали в своем вопросе, простой способ может быть:

  1. Сохранение всех дат в коллекции HtmlNodeCollection
  2. Сохранить все заголовки в коллекции HtmlNodeCollection
  3. Сохранить все внутренние тексты в другой коллекции HtmlNodeCollection

Если все в порядке и HTML имеет такой макет, у вас будет одинаковое количество элементов в обеих 3 коллекциях.

Тогда вы можете легко сделать:

for (int i = 0; i < innerTexts.Count; i++) {
    //Get Date, Headers and Inner Texts at position i
}

Должно работать следующее:

var document = new HtmlWeb().Load("http://www.url.com"); //Or load it from a Stream, local file, etc.

var dateNodes = document.DocumentNode.SelectNodes("//div[@class='mvb']/b");
var headerNodes = document.DocumentNode.SelectNodes("//div[@class='mxb']/b");

var innerTextNodes = (from node in document.DocumentNode.SelectNodes("//div")
                        let previous = node.PreviousSibling
                        where previous.Name == "div" && previous.GetAttributeValue("class", "") == "mxb"
                        select node).ToList();

//Check here if the number of elements of the 3 collections are the same

for (int i = 0; i < dateNodes.Count; i++) {
    var date = dateNodes[i].InnerText;
    var header = headerNodes[i].InnerText;
    var innerText = innerTextNodes[i].InnerText;

    //Now you have the set you want: You have the Date, Header and Inner Text
}

Это способ сделать это. Конечно, вы должны проверить наличие исключений (метод .SelectNodes(..) не возвращает null), проверить ошибки в выражении LINQ при сохранении innerTextNodes и выполнить рефакторинг for (...), возможно, в метод, который получает HtmlNode и возвращает его InnerText свойство.

Примите во внимание, что единственный способ узнать в размещенном вами HTML-коде, что такое тег <div>, содержащий внутренний текст, - это предположить, что он находится рядом с тегом <div>. который содержит заголовок. Вот почему я использовал выражение LINQ.

Другой способ узнать это может быть, если <div> имеет какой-то определенный атрибут (например, class="___") или аналогичный, или если он содержит некоторые теги внутри, а не только текст. При разборе HTML-кода нет никакой магии:)

Edit:
Я не проверял этот код. Проверьте это сами и дайте мне знать, если это сработало.

...