можно ли исправить проблему в HtmlAgilityPack, когда есть закрытый тег html?

c# html-agility-pack xpath

Вопрос

хорошо, у меня есть следующая проблема.
html, котор я имею malformed и я имею проблемы с выбирать узлы использующ html пакет гибкости когда это будет случай.
код ниже:

string strHtml = @"
<html>
  <div>
    <p><strong>Elem_A</strong>String_A1_2 String_A1_2</p>
    <p><strong>Elem_B</strong>String_B1_2 String_B1_2</p>
  </div>
  <div>
    <p><strong>Elem_A</strong>String_A2_2 <String_A2_2> asdas</p>
    <p><strong>Elem_B</strong>String_B2_2 String_B2_2</p>
  </div>
</html>";
HtmlAgilityPack.HtmlDocument objHtmlDocument = new HtmlAgilityPack.HtmlDocument();
objHtmlDocument.LoadHtml(strHtml);
HtmlAgilityPack.HtmlNodeCollection colnodePs = objHtmlDocument.DocumentNode.SelectNodes("//p");
List<string> lststrText = new List<string>();
foreach (HtmlAgilityPack.HtmlNode nodeP in colnodePs)
{
  lststrText.Add(nodeP.InnerHtml);
}

проблема в том, что String_A2_2 заключен в скобки.
поэтому пакет htmlagility возвращает 5 строк вместо 4 в lststrText.
так можно ли позволить htmlagility pack возвращать элемент 3 как "<strong>Elem_A</strong>String_A2_2 <String_A2_2> asdas" ?
или, может быть, я могу сделать некоторую предварительную обработку, чтобы закрыть элемент?
текущее содержимое lststrText

lststrText[0] = "<strong>Elem_A</strong>String_A1_2 String_A1_2"  
lststrText[1] = "<strong>Elem_B</strong>String_B1_2 String_B1_2"  
lststrText[2] = ""  
lststrText[3] = ""  
lststrText[4] = "<strong>Elem_B</strong>String_B2_2 String_B2_2"

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

Большинство синтаксических анализаторов html пытаются создать рабочую DOM, что означает, что оборванные теги не принимаются. Они будут преобразованы или закрыты каким-то образом.

Если для вас важны только выбор узлов, а скорость и огромное количество данных не являются проблемой, вы можете взять все ваши теги <p> с помощью регулярного выражения:

Regex reMatchP = new Regex(@"<(p)>.*?</\1>");
foreach (Match m in reMatchP.Matches(strHtml))
{
   Console.WriteLine(m.Value);
}

Это регулярное выражение предполагает, что теги <p> хорошо сформированы и закрыты.

Если вы хотите запустить это Regex много в своей программе, вы должны объявить его как:

static Regex reMatchP = new Regex(@"<(p)>.*?</\1>", RegexOptions.Compiled);

[Изменить: изменение патча подвижности]

Если вы хотите использовать пакет HtmlAgility, вы можете изменить функцию PushNodeEnd в HtmlDocument.cs:

if (HtmlNode.IsCDataElement(CurrentNodeName()))
{
   _state = ParseState.PcData;
   return true;
}

// new code start
if ( !AllowedTags.Contains(_currentnode.Name) )
{
    close = true;
}
// new code end

где AllowedTags будет списком всех известных тегов: b, p, br, span, div и т. д.

выход не на 100%, что вы хотите, но, может быть, достаточно близко?

<strong>Elem_A</strong>String_A1_2 String_A1_2
<strong>Elem_B</strong>String_B1_2 String_B1_2
<strong>Elem_A</strong>String_A2_2 <ignorestring_a2_2></ignorestring_a2_2> asdas
<strong>Elem_B</strong>String_B2_2 String_B2_2

Популярные ответы

Вы можете использовать TidyNet для выполнения предварительной / постобработки, на которую вы ссылаетесь. Можете ли вы отредактировать свой ответ, чтобы объяснить, почему это не применимо в вашем случае?



Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow