AngleSharp Html 解析器配置
HTML 解析器附带了一些选项,这些选项可能有助于覆盖特定场景。
IsNotConsumingCharacterReferences
如果启用了 IsNotConsumingCharacterReferences
,那么每个 &
符号都将被视为普通的 &
。对于序列化,这仍然意味着 &
会被表示为 &
,但我们知道可以简单地用 &
替换 &
。
或者,我们可以使用自己的格式化器。
来看一个例子:
var formatter = new MyFormatter();
var parser = new HtmlParser(new HtmlParserOptions
{
IsNotConsumingCharacterReferences = true,
});
var html = "<html><head></head><body><p>&foo</p></body></html>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.DocumentElement.ToHtml(formatter));
在这里我们使用了一个自定义格式器,如:
class MyFormatter : IMarkupFormatter
{
public string CloseTag(IElement element, bool selfClosing) => HtmlMarkupFormatter.Instance.CloseTag(element, selfClosing);
public string Comment(IComment comment) => HtmlMarkupFormatter.Instance.Comment(comment);
public string Doctype(IDocumentType doctype) => HtmlMarkupFormatter.Instance.Doctype(doctype);
public string LiteralText(ICharacterData text) => HtmlMarkupFormatter.Instance.LiteralText(text);
public string OpenTag(IElement element, bool selfClosing) => HtmlMarkupFormatter.Instance.OpenTag(element, selfClosing);
public string Processing(IProcessingInstruction processing) => HtmlMarkupFormatter.Instance.Processing(processing);
public string Text(ICharacterData text) => HtmlMarkupFormatter.Instance.LiteralText(text);
}
现在输出如下:
<html>
<head></head>
<body>
<p>&foo</p>
</body>
</html>
相比之下,将 IsNotConsumingCharacterReferences
设置为 false
的结果是:
<html>
<head></head>
<body>
<p>&foo</p>
</body>
</html>
总结一下:
此选项影响了 &
字符的解析。当设为 false
(默认)时,我们开始消费字符引用,这是规范行为,但可能会“吃掉”你希望稍后处理的信息。设为 true
时,我们从不消费 &
字符,而是将其发射到 DOM(就像在规范兼容模式下看到 &
一样)。
对于序列化(例如,使用 InnerHtml
或更明确地通过 ToHtml
),然而,我们将任何见到的 &
解释为 &
(这样它就可以循环使用,且符合序列化规范)。所以在上面的例子中,我们使用自定义格式器来直接使用字符节点数据。
IsKeepingSourceReferences
IsKeepingSourceReferences
选项决定是否保持文本源的位置信息或引用以便序列化。如果不保持源引用,在序列化时,我们无法获取文档中任何选定元素的源引用响应。
这个选项的一个示例是:
var parser = new HtmlParser(new HtmlParserOptions
{
IsKeepingSourceReferences = false
});
var html = "<html><head></head><body><p>foo</p></body></html>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.QuerySelector("a").SourceReference?.Position.ToString());
结果将是无,SourceReference
会因解析器给定而为 null
。将该选项设为 true
后,我们将按预期获得位置信息:
Ln 1, Col 26, Pos 26
我们也可以格式化 HTML 使其更美观,并得到更漂亮的输出,添加代码:
document = parser.ParseDocument(document.Prettify());
然后我们将得到 Ln 4, Col 3, Pos 33
IsSupportingProcessingInstructions
IsSupportingProcessingInstructions
选项导致解析器在遇到 <? ... >
令牌时发出 ProcessingInstruction
节点,这些是用于向应用程序传递指令的 SGML 和 XML 节点类型。
SGML PI 由 <?
和 >
包围,而 XML PI 由 <?
和 ?>
包围。
以以下情况为例:
var parser = new HtmlParser(new HtmlParserOptions
{
IsSupportingProcessingInstructions = true
});
var html = "<html><head></head><body><p><?xml version=\"1.0\" encoding=\"UTF - 8\" ?></p></body></html>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.DocumentElement.ToHtml());
由于启用了 PI 支持选项,这将给出 <html><head></head><body><p><??xml version=\"1.0\" encoding=\"UTF - 8\" ?></p></body></html>
的响应。
否则,我们会得到一个注释节点包围发出的 PI 节点:"<html><head></head><body><p><!--<?xml version=\"1.0\" encoding=\"UTF - 8\" ?>--></p></body></html>"
OnCreated
OnCreated
功能基于新元素被创建和在文档中的位置执行动作,该动作随后由格式器相应地解析。具体来说,可以在元素被创建时重新定位、更改其属性并执行其他操作。
例如,我们可以执行以下操作:
var parser = new HtmlParser(new HtmlParserOptions
{
OnCreated = (element, position) =>
{
if (25 <= position.Index && position.Index < 35)
element.TextContent += " bar";
}
});
var html = "<html><head></head><body><p>foo</p></body></html>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.DocumentElement.ToHtml());
这将根据位置范围 [25, 35) 和该范围内的 <p>
元素格式化输出 <html><head></head><body><p>foo bar</p></body></html>
。
一般来说,对于足够大的文本,不期望在一次解析中传递这个选项,因为它需要更多时间来处理。
IsStrictMode
JavaScript 的 ES5 中的 "严格模式" 指令在此处由 IsStrictMode
选项表示。简而言之,将此选项设置为 true
在 $HtmlParserOptions$
中通知解析器,它包含的任何 JS 代码都将应用 "严格模式"。
以下代码将给我们一个 HtmlParseException
:
var parser = new HtmlParser(new HtmlParserOptions
{
IsStrictMode = true
});
var html = "<html><head></head><body><script>x = 0;</script><p>foo</p></body></html>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.DocumentElement.ToHtml());
在这种情况下,因为我们启用了严格模式,所以我们必须声明 x
为 let x
,例如。
默认情况下,严格模式为 false
,我们将按预期获得响应。
IsEmbedded
、IsNotSupportingFrames
和 IsScripting
IsEmbedded
选项允许您使用 HTML 解析器,假设内容已经被嵌入到一个有效的 HTML 文档中。这用于确定是否需要文档类型声明。在嵌入模式下,即使缺少文档类型声明也不会进入怪异模式。
同样,IsNotSupportingFrames
选项可用于表现得好像不允许框架一样。当实际遇到 frameset
或类似标签时,像 noframes
这样的标签会被不同地解释(即,就好像它们不存在一样)。目前,大多数浏览器仍然支持框架——尽管它们不应再被使用。注意,框架不包括 <iframe>
,此标志不受影响。
IsScripting
选项模拟浏览器在解析 innerHTML
时的行为。没有脚本的情况下,noscript
和 script
标签会互换位置。在这里,noscript
标签将被评估(而不是被忽略)。此外,script
标签的内容将被忽略。启用 IsScripting
以从解析的角度来看页面,就像 JavaScript 启用的浏览器所做的那样。
备注:开启 IsScripting
选项和集成 JavaScript 引擎(例如,来自 AngleSharp.Js)不是一回事。AngleSharp 实际上会在发现已包含 JavaScript 引擎时自动开启 IsScripting
。
IsAcceptingCustomElementsEverywhere
选项
IsAcceptingCustomElementsEverywhere
选项允许在通常禁止使用自定义元素(如 my-element
)的位置使用它们。
考虑以下 HTML:
<html>
<head>
<my-element foo="bar"></my-element>
</head>
</html>
实际上,DOM 会将 my-element
节点置于 body
中。看起来原始 HTML 被重排成了这样:
<html>
<head> </head>
<body>
<my-element foo="bar"></my-element>
</body>
</html>
如果你想允许自定义元素出现在任何地方,只需提供该标志:
var parser = new HtmlParser(new HtmlParserOptions
{
IsAcceptingCustomElementsEverywhere = true
});
var html = @"<html><head><my-element foo=""bar""></my-element></head></html>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.DocumentElement.ToHtml());
这将使 my-element
保持在头部。但请记住,自定义元素的内容,即子元素,需要遵循外部上下文的规则。
IsPreservingAttributeNames
选项
此选项允许你保留原始属性名称。通常,属性名称会被规范化为只使用小写字母。
以下是非标准的 Angular 模板 HTML:
<div *ngIf="condition">当条件为真时渲染的内容。</div>
如果不使用此选项,HTML DOM 看起来会像是原始源码为:
<div *ngif="condition">当条件为真时渲染的内容。</div>
相比之下,你可以这样使用这个选项:
var parser = new HtmlParser(new HtmlParserOptions
{
// 保留属性名原样
IsPreservingAttributeNames = true
});
var html = @"<div *ngIf=""condition"">当条件为真时渲染的内容。</div>";
IDocument document = parser.ParseDocument(html);
Console.WriteLine(document.DocumentElement.ToHtml());
这将保持属性原样,即为 *ngIf
而不是 *ngif
。