测试场景与代码 测试HTML内容 $Html = @'
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Some header elements</h1>
<aside>
<p>huge text in between aside</p>
</aside>
<div>
<p>huge text in between div</p>
</div>
<p>Some other elements</p>
</body>
</html>
'@
HTML解析函数 function ParseHtml($String) {
$Unicode = [System.Text.Encoding]::Unicode.GetBytes($String)
$Html = New-Object -Com 'HTMLFile'
if ($Html.PSObject.Methods.Name -Contains 'IHTMLDocument2_Write') {
$Html.IHTMLDocument2_Write($Unicode)
}
else {
$Html.write($Unicode)
}
$Html.Close()
$Html
}
$Document = ParseHtml $Html
测试结果 $Document.getElementsByTagName('aside') | ForEach-Object { $_.OuterHTML }
<ASIDE>
元素的OuterHTML输出
$Document.getElementsByTagName('div') | ForEach-Object { $_.OuterHTML }
<DIV><P>huge text in between div</P></DIV>
问题解答 1. 是HTML5新增的**语义化块级容器元素**,而你使用的`HTMLFile` COM组件基于旧版IE的HTML解析引擎,默认采用旧标准/怪异模式解析,对HTML5新元素的支持不完善。旧引擎会将未识别的HTML5元素当作**空元素**处理,不会解析其内部内容,也不会生成对应的闭合标签——这就是它和这类传统容器元素表现差异的核心原因。
2. 正确获取完整 有两种可靠的解决思路:
方法一:添加HTML5文档声明,强制解析引擎进入标准模式 在HTML内容开头添加<!DOCTYPE html>声明,让旧解析引擎尝试按HTML5标准解析元素:
$Html = @'
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Some header elements</h1>
<aside>
<p>huge text in between aside</p>
</aside>
<div>
<p>huge text in between div</p>
</div>
<p>Some other elements</p>
</body>
</html>
'@
重新解析后,
的OuterHTML会正常返回完整内容:<ASIDE><P>huge text in between aside</P></ASIDE>。
方法二:使用HtmlAgilityPack替代旧COM组件 HtmlAgilityPack是对HTML5支持更完善的.NET解析库,完全规避旧引擎的兼容性问题:
先安装NuGet包: Install-Package HtmlAgilityPack
解析并获取完整OuterHTML: $Html = @'
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Some header elements</h1>
<aside>
<p>huge text in between aside</p>
</aside>
<div>
<p>huge text in between div</p>
</div>
<p>Some other elements</p>
</body>
</html>
'@
$Doc = New-Object HtmlAgilityPack.HtmlDocument
$Doc.LoadHtml($Html)
$Doc.DocumentNode.SelectSingleNode("//aside").OuterHtml
执行后会返回完整的<aside><p>huge text in between aside</p></aside>。
内容的提问来源于stack exchange,提问作者iRon