HTML敏捷包错误解析和返回XElement。

6
我可以解析文档并生成输出,但由于p标签,输出无法解析为XElement,字符串中的其他内容都被正确解析。
我的输入:
var input = "<p> Not sure why is is null for some wierd reason!<br><br>I have implemented the auto save feature, but does it really work after 100s?<br></p> <p> <i>Autosave?? </i> </p> <p>we are talking...</p><p></p><hr><p><br class=\"GENTICS_ephemera\"></p>";

我的代码:

public static XElement CleanupHtml(string input)
    {  


    HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();

    htmlDoc.OptionOutputAsXml = true;
    //htmlDoc.OptionWriteEmptyNodes = true;             
    //htmlDoc.OptionAutoCloseOnEnd = true;
    htmlDoc.OptionFixNestedTags = true;

    htmlDoc.LoadHtml(input);

    // ParseErrors is an ArrayList containing any errors from the Load statement
    if (htmlDoc.ParseErrors != null && htmlDoc.ParseErrors.Count() > 0)
    {

    }
    else
    {

        if (htmlDoc.DocumentNode != null)
        {
            var ndoc = new HtmlDocument(); // HTML doc instance
            HtmlNode p = ndoc.CreateElement("body");  

            p.InnerHtml = htmlDoc.DocumentNode.InnerHtml;
            var result = p.OuterHtml.Replace("<br>", "<br/>");
            result = result.Replace("<br class=\"special_class\">", "<br/>");
            result = result.Replace("<hr>", "<hr/>");
            return XElement.Parse(result, LoadOptions.PreserveWhitespace);
        }
    }
    return new XElement("body");

}

我的输出:

<body>
   <p> Not sure why is is null for some wierd reason chappy!
   <br/>
   <br/>I have implemented the auto save feature, but does it really work after 100s?
   <br/>
   </p> 
   <p> 
   <i>Autosave?? </i> 
   </p> 
   <p>we are talking...</p>
   **<p>**
   <hr/>
   <p>
   <br/>
   </p>
</body>

粗体的p标签是没有正确输出的...有什么办法可以解决吗?我在代码方面做错了什么吗?

2个回答

9
你想要做的基本上是将HTML输入转换为XML输出。
当你使用OptionOutputAsXml选项时,Html Agility Pack可以实现这一点,但在这种情况下,你不应该使用InnerHtml属性,而是让Html Agility Pack为你完成基础工作,使用HtmlDocument的一个Save方法。
以下是将HTML文本转换为XElement实例的通用函数:
public static XElement HtmlToXElement(string html)
{
    if (html == null)
        throw new ArgumentNullException("html");

    HtmlDocument doc = new HtmlDocument();
    doc.OptionOutputAsXml = true;
    doc.LoadHtml(html);
    using (StringWriter writer = new StringWriter())
    {
        doc.Save(writer);
        using (StringReader reader = new StringReader(writer.ToString()))
        {
            return XElement.Load(reader);
        }
    }
}

如您所见,您不必自己做太多的工作!请注意,由于您的原始输入文本没有根元素,Html Agility Pack将自动添加一个包含SPAN的元素以确保输出是有效的Xml。

在您的情况下,您想要额外处理一些标签,因此,以下是如何处理您的示例:

    public static XElement CleanupHtml(string input)
    {
        if (input == null)
            throw new ArgumentNullException("input");

        HtmlDocument doc = new HtmlDocument();
        doc.OptionOutputAsXml = true;
        doc.LoadHtml(input);

        // extra processing, remove some attributes using DOM
        HtmlNodeCollection coll = doc.DocumentNode.SelectNodes("//br[@class='special_class']");
        if (coll != null)
        {
            foreach (HtmlNode node in coll)
            {
                node.Attributes.Remove("class");
            }
        }

        using (StringWriter writer = new StringWriter())
        {
            doc.Save(writer);
            using (StringReader reader = new StringReader(writer.ToString()))
            {
                return XElement.Load(reader);
            }
        }
    }

正如你所看到的,你不应该使用原始字符串函数,而应该使用Html Agility Pack DOM函数(SelectNodes、Add、Remove等)。


这个可以运行,很奇怪为什么我必须保存才能得到正确的输出,不管怎样 - 如果输入中包含 nbsp;,我该如何处理?您建议我同时使用 anti.xss 库吗? - Haroon
+1 我甚至不知道 OptionOutputAsXml(以及它的用例)存在。 - BrokenGlass
HtmlAgilityPack似乎在转换方面不是特别可靠,例如我会得到这个错误:6XmlException
'', 十六进制值0x03,是无效的字符。行2081,位置822。 行号2081 行位置822
- Bent Rasmussen
2
如果您遇到了新的问题,请发布一个新的问题。 - Simon Mourier
同时使用 StringWriterStringReader 会产生太多的开销。只需使用 MemoryStream 并重置位置即可。这比使用 ToString() 分配临时字符串更好。 - Baccata

2
如果您查看关于OptionFixNestedTags的文档注释,您会看到以下内容:
//     Defines if LI, TR, TH, TD tags must be partially fixed when nesting errors
//     are detected. Default is false.

我认为这不会帮助您处理未关闭的HTML p 标签。但根据一个旧的SO问题(C#清理html的库)HTML Tidy可能适用于此目的。


感谢提供信息... 我的输入问题在于我有一个有效的< p >< /p>标签,但它没有被正确处理,它们只是空元素!< p >< /p>会变成< p >。 - Haroon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接