使用 htmldocument/HtmlAgilityPack 获取所有节点及其内容
get all nodes and its content using htmldocument/HtmlAgilityPack
我需要从 html 获取所有节点,然后我需要从该节点获取文本和子节点,同样的事情是从子节点获取。
例如,我有这个 HTML:
<p>This <b>is a <a href="">Link</a></b> with <b>bold</b></p>
所以我需要一种方法来获取 p 节点,然后是非格式化文本 (this),唯一的粗体文本 (is a), 粗体 link (Link) 和其余格式化和未格式化的文本。
我知道使用 html 文档我可以 select 所有节点和子节点,但是,我怎样才能得到子节点之前的文本,然后是子节点,和它的 text/sub-nodes 所以我可以制作 html ("This is a Link with bold")?
的渲染版本
请注意,上面的例子很简单。 HTML 会有更复杂的东西,如列表、框架、编号列表、三重格式文本等。还要注意渲染的东西不是问题。我已经这样做了,但是是以另一种方式。我需要的是仅获取节点及其内容的部分。
另外,我不能忽略任何节点,所以我不能什么都不过滤。主节点可以以p、div、frame、ul等开头
查看 htmldoc 及其属性后,感谢@HungCao 的观察,我得到了一种解释 HTML 代码的简单工作方法。
我的代码有点复杂,无法添加它作为示例,所以我将 post 它的精简版。
首先,必须加载 htmlDoc。它可以在任何函数上:
HtmlDocument htmlDoc = new HtmlDocument();
string html = @"<p>This <b>is a <a href="""">Link</a></b> with <b>bold</b></p>";
htmlDoc.LoadHtml(html);
然后我们需要解释每个 "main" 节点(在本例中为 p),并且根据其类型,我们需要加载 LoopFunction (InterNode)
HtmlNodeCollection nodes = htmlDoc.DocumentNode.ChildNodes;
foreach (HtmlNode node in nodes)
{
if(node.Name.ToLower() == "p") //Low the typeName just in case
{
Paragraph newPPara = new Paragraph();
foreach(HtmlNode childNode in node.ChildNodes)
{
InterNode(childNode, ref newPPara);
}
richTextBlock.Blocks.Add(newPPara);
}
}
请注意,有一个名为 "NodeType" 的 属性,但它 return 不是正确的类型。因此,请改用 "Name" 属性(另请注意,htmlNode 中的名称 属性 与 HTML 中的名称属性不同)。
最后,我们有 InterNode 函数,它将内联添加到引用的 (ref) 段落
public bool InterNode(HtmlNode htmlNode, ref Paragraph originalPar)
{
string htmlNodeName = htmlNode.Name.ToLower();
List<string> nodeAttList = new List<string>();
HtmlNode parentNode = htmlNode.ParentNode;
while (parentNode != null) {
nodeAttList.Add(parentNode.Name);
parentNode = parentNode.ParentNode;
} //we need to get it multiple types, because it could be b(old) and i(talic) at the same time.
Inline newRun = new Run();
foreach (string noteAttStr in nodeAttList) //with this we can set all the attributes to the inline
{
switch (noteAttStr)
{
case ("b"):
case ("strong"):
{
newRun.FontWeight = FontWeights.Bold;
break;
}
case ("i"):
case ("em"):
{
newRun.FontStyle = FontStyle.Italic;
break;
}
}
}
if(htmlNodeName == "#text") //the #text means that its a text node. Like <i><#text/></i>. Thanks @HungCao
{
((Run)newRun).Text = htmlNode.InnerText;
} else //if it is not a #text, don't load its innertext, as it's another node and it will always have a #text node as a child (if it has any text)
{
foreach (HtmlNode childNode in htmlNode.ChildNodes)
{
InterNode(childNode, ref originalPar);
}
}
return true;
}
注意:我知道我说过我的应用程序需要以 Webview 的另一种方式呈现 HTML,而且我知道此示例代码生成与 Webview 相同的内容,但是,我之前说过,这只是我最终代码的精简版。事实上,我的 original/full 代码正在按我的需要工作,这只是基础。
我需要从 html 获取所有节点,然后我需要从该节点获取文本和子节点,同样的事情是从子节点获取。 例如,我有这个 HTML:
<p>This <b>is a <a href="">Link</a></b> with <b>bold</b></p>
所以我需要一种方法来获取 p 节点,然后是非格式化文本 (this),唯一的粗体文本 (is a), 粗体 link (Link) 和其余格式化和未格式化的文本。
我知道使用 html 文档我可以 select 所有节点和子节点,但是,我怎样才能得到子节点之前的文本,然后是子节点,和它的 text/sub-nodes 所以我可以制作 html ("This is a Link with bold")?
的渲染版本请注意,上面的例子很简单。 HTML 会有更复杂的东西,如列表、框架、编号列表、三重格式文本等。还要注意渲染的东西不是问题。我已经这样做了,但是是以另一种方式。我需要的是仅获取节点及其内容的部分。 另外,我不能忽略任何节点,所以我不能什么都不过滤。主节点可以以p、div、frame、ul等开头
查看 htmldoc 及其属性后,感谢@HungCao 的观察,我得到了一种解释 HTML 代码的简单工作方法。
我的代码有点复杂,无法添加它作为示例,所以我将 post 它的精简版。
首先,必须加载 htmlDoc。它可以在任何函数上:
HtmlDocument htmlDoc = new HtmlDocument();
string html = @"<p>This <b>is a <a href="""">Link</a></b> with <b>bold</b></p>";
htmlDoc.LoadHtml(html);
然后我们需要解释每个 "main" 节点(在本例中为 p),并且根据其类型,我们需要加载 LoopFunction (InterNode)
HtmlNodeCollection nodes = htmlDoc.DocumentNode.ChildNodes;
foreach (HtmlNode node in nodes)
{
if(node.Name.ToLower() == "p") //Low the typeName just in case
{
Paragraph newPPara = new Paragraph();
foreach(HtmlNode childNode in node.ChildNodes)
{
InterNode(childNode, ref newPPara);
}
richTextBlock.Blocks.Add(newPPara);
}
}
请注意,有一个名为 "NodeType" 的 属性,但它 return 不是正确的类型。因此,请改用 "Name" 属性(另请注意,htmlNode 中的名称 属性 与 HTML 中的名称属性不同)。
最后,我们有 InterNode 函数,它将内联添加到引用的 (ref) 段落
public bool InterNode(HtmlNode htmlNode, ref Paragraph originalPar)
{
string htmlNodeName = htmlNode.Name.ToLower();
List<string> nodeAttList = new List<string>();
HtmlNode parentNode = htmlNode.ParentNode;
while (parentNode != null) {
nodeAttList.Add(parentNode.Name);
parentNode = parentNode.ParentNode;
} //we need to get it multiple types, because it could be b(old) and i(talic) at the same time.
Inline newRun = new Run();
foreach (string noteAttStr in nodeAttList) //with this we can set all the attributes to the inline
{
switch (noteAttStr)
{
case ("b"):
case ("strong"):
{
newRun.FontWeight = FontWeights.Bold;
break;
}
case ("i"):
case ("em"):
{
newRun.FontStyle = FontStyle.Italic;
break;
}
}
}
if(htmlNodeName == "#text") //the #text means that its a text node. Like <i><#text/></i>. Thanks @HungCao
{
((Run)newRun).Text = htmlNode.InnerText;
} else //if it is not a #text, don't load its innertext, as it's another node and it will always have a #text node as a child (if it has any text)
{
foreach (HtmlNode childNode in htmlNode.ChildNodes)
{
InterNode(childNode, ref originalPar);
}
}
return true;
}
注意:我知道我说过我的应用程序需要以 Webview 的另一种方式呈现 HTML,而且我知道此示例代码生成与 Webview 相同的内容,但是,我之前说过,这只是我最终代码的精简版。事实上,我的 original/full 代码正在按我的需要工作,这只是基础。