2011-03-24 43 views
8

我最近開始與HtmlAgilityPack試驗。我不熟悉它的所有選項,我認爲我做錯了什麼。在HtmlAgilityPack失去了「小於」的標誌loadhtml

我有以下內容的字符串:

string s = "<span style=\"color: #0000FF;\"><</span>"; 

你看,在我的跨度我有一個「小於」的標誌。 我處理這個字符串用下面的代碼:

HtmlDocument htmlDocument = new HtmlDocument(); 
htmlDocument.LoadHtml(s); 

但是當我做一個快速和骯髒的外觀在跨度是這樣的:

htmlDocument.DocumentNode.ChildNodes[0].InnerHtml 

我看到,跨度爲空。

什麼選擇,我需要設置維持「小於」的標誌。我已經試過這個:

htmlDocument.OptionAutoCloseOnEnd = false; 
htmlDocument.OptionCheckSyntax = false; 
htmlDocument.OptionFixNestedTags = false; 

但沒有成功。

我知道它是無效的HTML。我用這來解決無效的HTML和使用的HTMLEncode對「小於」跡象

請直接與我在正確的方向。提前

+2

這是無效的HTML,所以所有的賭注都關閉 - 你應該''<被 – 2011-03-24 15:28:02

+1

比編碼各種標誌的,我知道它是無效的HTML。我正在使用它來修復無效的HTML,並在'less than'符號上使用HTMLEncode – TurBas 2011-03-24 15:34:15

+0

我原以爲計算機確實是一件很難的事情,以確定給定的角括號是否爲破碎的HTML標記的一部分,或者一個不正確的轉角支架。 HTML的解析位是否有其他標籤?如果它完全摧毀它,而不是將其轉換爲其他內容,我可能會含糊其詞,但我可能是錯的... – Chris 2011-03-24 15:37:08

回答

4

的HTML敏捷包檢測出這是一個錯誤,並創建一個HtmlParseError實例爲了它。您可以使用HtmlDocument類的ParseErrors讀取所有錯誤。所以,如果你運行該代碼:

string s = "<span style=\"color: #0000FF;\"><</span>"; 
    HtmlDocument doc = new HtmlDocument(); 
    doc.LoadHtml(s); 
    doc.Save(Console.Out); 

    Console.WriteLine(); 
    Console.WriteLine(); 

    foreach (HtmlParseError err in doc.ParseErrors) 
    { 
     Console.WriteLine("Error"); 
     Console.WriteLine(" code=" + err.Code); 
     Console.WriteLine(" reason=" + err.Reason); 
     Console.WriteLine(" text=" + err.SourceText); 
     Console.WriteLine(" line=" + err.Line); 
     Console.WriteLine(" pos=" + err.StreamPosition); 
     Console.WriteLine(" col=" + err.LinePosition); 
    } 

它會顯示這個(第一修正文本,並詳細描述有關錯誤,則):

<span style="color: #0000FF;"></span> 

Error 
code=EndTagNotRequired 
reason=End tag </> is not required 
text=< 
line=1 
pos=30 
col=31 

所以,你可以嘗試修復這個錯誤,因爲您擁有所有必需的信息(包括行,列和流位置),但修復(不檢測)HTML錯誤的一般過程非常複雜。

2

由於固定的標記,因爲你的HTML字符串無效:

string s = "<span style=\"color: #0000FF;\">&lt;</span>"; 
+0

我知道這是無效的HTML。我正在使用它來修復無效的HTML,並在'less than'符號上使用HTMLEncode – TurBas 2011-03-24 15:33:48

+0

@TurBas:如果文本是'a 2011-03-24 16:04:03

+0

這是一個<> ...所以他認爲它是一個開標籤並關閉它?刪除b? – TurBas 2011-03-24 16:22:26

0

字符串 「s」 是壞的HTML。

string s = "<span style=\"color: #0000FF;\">&lt;</span>"; 

這是真的。

2

雖然這是事實,在指定的HTML是無效的,應該HtmlAgilityPack仍然能夠解析它。在網絡上忘記編碼「<」並不罕見,如果HtmlAgilityPack被用作抓取工具,那麼它應該預見到錯誤的html。我測試的例子在IE,Chrome和Firefox,他們都表現出額外的<爲文本。

我寫了下面的方法,你可以使用預處理的HTML字符串,並將"&lt;"替換所有「未閉合的」 '<'字符:

static string PreProcess(string htmlInput) 
{ 
    // Stores the index of the last unclosed '<' character, or -1 if the last '<' character is closed. 
    int lastGt = -1; 

    // This list will be populated with all the unclosed '<' characters. 
    List<int> gtPositions = new List<int>(); 

    // Collect the unclosed '<' characters. 
    for (int i = 0; i < htmlInput.Length; i++) 
    { 
     if (htmlInput[i] == '<') 
     { 
      if (lastGt != -1) 
       gtPositions.Add(lastGt); 

      lastGt = i; 
     } 
     else if (htmlInput[i] == '>') 
      lastGt = -1; 
    } 

    if (lastGt != -1) 
     gtPositions.Add(lastGt); 

    // If no unclosed '<' characters are found, then just return the input string. 
    if (gtPositions.Count == 0) 
     return htmlInput; 

    // Build the output string, replace all unclosed '<' character by "&lt;". 
    StringBuilder htmlOutput = new StringBuilder(htmlInput.Length + 3 * gtPositions.Count); 
    int start = 0; 

    foreach (int gtPosition in gtPositions) 
    { 
     htmlOutput.Append(htmlInput.Substring(start, gtPosition - start)); 
     htmlOutput.Append("&lt;"); 
     start = gtPosition + 1; 
    } 

    htmlOutput.Append(htmlInput.Substring(start)); 
    return htmlOutput.ToString(); 
} 
3

正如另一個答案中提到的,我發現的最佳解決方案是預解析HTML以將孤立的<符號轉換爲其HTML編碼值&lt;

return Regex.Replace(html, "<(?![^<]+>)", "&lt;");