OptionWriteEmptyNodes使用HtmlAgilityPack破坏XML声明

本文关键字:XML 声明 破坏 HtmlAgilityPack 使用 OptionWriteEmptyNodes | 更新日期: 2023-09-27 18:37:22

这是我拥有的超级简单的代码:

HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.OptionWriteEmptyNodes = true;
htmlDoc.Load("sourcefilepath");
htmlDoc.Save("destfilepath", Encoding.UTF8);

输入:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/>
    <link rel="stylesheet" href="main.css" type="text/css"/>
  </head>
  <body>lots of text here, obviously not relevant to this problem</body>
</html>

输出:

<?xml version="1.0" encoding="UTF-8" />
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
    <link rel="stylesheet" href="main.css" type="text/css" />
  </head>
  <body>lots of text here, obviously not relevant to this problem</body>
</html>

您可以看到在第一行中有一个错误:/> 而不是 ?>如果我将 OptionWriteEmptyNodes 设置为 true 值,就会发生这种情况。它已设置为 true,因为否则元/链接标签(以及文档正文中的其他一些标签)将不会关闭。

有人知道如何解决这个问题吗?

OptionWriteEmptyNodes使用HtmlAgilityPack破坏XML声明

似乎是一个错误。您应该向 http://htmlagilitypack.codeplex.com 报告。

不过,您可以像这样解决该错误:

HtmlNode.ElementsFlags.Remove("meta");
HtmlNode.ElementsFlags.Remove("link");
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.Load("sourcefilepath");
htmlDoc.Save("destfilepath", Encoding.UTF8);

只需从 metalink 标记中删除指示 Html Agility Pack 不要自动关闭它们的标志,并且不要将OptionWriteEmptyNodes设置为 true

它将产生这个(注意这略有不同):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"></meta>
    <link rel="stylesheet" href="main.css" type="text/css"></link>
  </head>
  <body>lots of text here, obviously not relevant to this problem</body>
</html>
设法

做了另一种解决此问题的方法。在我的情况下,这比上面的效果略好。基本上,我们正在替换 DocumentNode 的第一个子项,即 xml 声明。(请注意,输入必须包含XML声明,在我的例子中是100%)

HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.OptionWriteEmptyNodes = true;
htmlDoc.Load("sourcepath");
var newNodeStr = "<?xml version='"1.0'" encoding='"UTF-8'"?>";
var newNode = HtmlNode.CreateNode(newNodeStr);
htmlDoc.DocumentNode.ReplaceChild(newNode, htmlDoc.DocumentNode.FirstChild);

htmlDoc.Save("destpath", Encoding.UTF8);
请注意,Simon 的解决方法

也有效,因此请选择更适合您的方案的解决方法。

我的页面中也有<br/>标签,删除htmlDoc.OptionWriteEmptyNodes = true;会通过用<br>替换它们来破坏这些标签。我找到了一种类似于 Alex 答案的方法,但更通用一些,以便保留大部分原始值,并且不依赖于页面中始终存在 xml 标签:

HtmlDocument doc= new HtmlDocument();
doc.OptionWriteEmptyNodes = true;
doc.Load("pathToFile");
if (doc.DocumentNode.FirstChild.OriginalName.Equals("?xml"))
{
    var fixedOuterHtml = doc.DocumentNode.FirstChild.OuterHtml.Replace('/', '?');
    var newNode = HtmlNode.CreateNode(fixedOuterHtml);
    doc.DocumentNode.ReplaceChild(newNode, doc.DocumentNode.FirstChild);
}