HtmlAgilityPack как извлечь html между некоторыми тегами

c# html-agility-pack

Вопрос

Мне нужно извлечь весь абзац из одного html, а также весь текст между этими тегами.

этот код не работает, когда текст, обработанный в HtmlDocument, будет изменен с исходного. В образце

some <br />text

изменено в

some <br>text

эс:

string s = "<p>firt paragraph</p>some <br />text<p>another paragraph</p><span>some text between span</span><p>hellow word</p>";
        HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
        doc.LoadHtml(s);
var nodes = doc.DocumentNode.SelectNodes("//p");
int lastPos = -1;
foreach (HtmlAgilityPack.HtmlNode n in nodes)
{
  if (lastPos > -1)
  {
      string textNotInP = Doc.DocumentNode.OuterHtml.Substring(lastPos, n.StreamPosition - lastPos);
                System.Diagnostics.Debug.WriteLine(textNotInP);
 }
 System.Diagnostics.Debug.WriteLine(n.OuterHtml);
 lastPos = n.StreamPosition + n.OuterHtml.Length;
}

правильным результатом будет:

<p>firt paragraph</p>
some <br>text
<p>second paragraph</p>
<span>some text between span</span>
<p>third paragraph</p>

но приведенный выше код вернет это:

<p>firt paragraph</p>
some <br>text<p
<p>second paragraph</p>
pan>some text between span</span><p
<p>third paragraph</p>

причина заключается в том, что steamPosition возвращает позицию узла, связанную с исходным текстом, а не один парсерд в htmlDocument.

Есть ли способ вернуть позицию одного узла, связанного с анализируемым html?

Принятый ответ

Вы можете использовать свойство OuterHtml для каждого элемента <p> для получения желаемого HTML:

string s = "<p>firt paragraph</p>some <br />text<p>another paragraph</p><span>some text between span</span><p>hellow word</p>";
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(s);
var nodes = doc.DocumentNode.SelectNodes("//p");
foreach (var item in nodes)
{
    Console.WriteLine(item.OuterHtml);
}

вывод :

<p>firt paragraph</p>
<p>another paragraph</p>
<p>hellow word</p>

Или если вы хотите получить все между первым <p> и последним <p> элементами, включительно, вы можете использовать следующий XPath:

var query = "//node()[preceding-sibling::p or self::p][following-sibling::p or self::p]";

XPath захватывает все узлы (или элемент или текстовый узел), которые: имеют предшествующий родной брат p и следующий sibling p , или сам узел является p элементом.

var nodes = doc.DocumentNode.SelectNodes(query);
foreach (var item in nodes)
{
    Console.WriteLine(item.OuterHtml);
}

вывод :

<p>firt paragraph</p>
some
<br />
text
<p>another paragraph</p>
<span>some text between span</span>
<p>hellow word</p>


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему