2009-12-18 26 views
2

以及我有以下问题。
我的html格式不正确,当遇到这种情况时,我选择使用html敏捷包的节点时遇到问题。
代码是下面:有没有可能修复HtmlAgilityPack中的问题,当有一个不封闭的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包在lststrText中返回5个字符串而不是4个。
所以有可能让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" 
+0

您是否知道要包含的标签的名称,还是想要将所有打开的标签保留为文本? – 2009-12-23 15:34:58

+0

我想将所有打开的标签保留为文字 – Karim 2009-12-23 18:37:55

+1

Html Agility Pack无法做到这一点。它一次解析一个角色,并没有真正的回溯概念。但是,它会关闭需要的标签,但这是因为您经历了与您想要的不同输出的结果。 最好的办法是做一些预处理。 如果您知道要保留的标签的名称或模式,可以很容易地修改解析代码以保持标签类似于:,稍后可以将其替换为您的输出。 也许修复您正在处理的格式错误的html更容易? – 2009-12-23 22:12:28

回答

2

大多数html解析器都试图构建一个可工作的DOM,这意味着悬挂标签不被接受。他们会被转换,或以某种方式关闭。

如果只选择节点是很重要的你,速度和巨大的数据量不是问题,你可以抓住所有的<p>标签用正则表达式来代替:

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

这正则表达式假设标签格式良好并且关闭。

如果您运行此正则表达式很多程序,你应该把它声明为:

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

[编辑:敏捷包更改]

如果你想使用HtmlAgility包你可以修改在HtmlDocument.cs的PushNodeEnd功能:

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,跨度,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 
+1

正则表达式不是parsehtml的选项。 – Karim 2009-12-26 06:58:50

+0

我添加了我的代码更改作为示例。它可能有帮助。 – 2009-12-26 14:18:12

+0

谢谢,我会看看,看看是否能解决这个问题。 – Karim 2009-12-26 22:38:49

2

你可以使用TidyNet做预/后处理你暗示。你可以编辑你的答案来解释为什么这不适用于你的情况?

+0

以及我没有尝试TidyNet因为我无法让它工作。 但我试过SgmlReader http://developer.mindtouch.com/SgmlReader,但我也没有工作。 – Karim 2009-12-23 18:40:36

相关问题