HtmlAgilityPack设置节点InnerText。

32

我想要用另一段文本替换HTML标签内的文本。

我正在使用HtmlAgilityPack


我使用以下代码提取所有文本

HtmlDocument doc = new HtmlDocument();
doc.Load("some path")

foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//text()[normalize-space(.) != '']")) {
    // How to replace node.InnerText with some text ?
}

但是InnerText是只读的。我该如何用另一个文本替换文本并将它们保存到文件中?


元素的内部文本是所有子标签的内部文本的组合。您是否想用文本节点替换所有子标签? - Yuriy Rozhovetskiy
@YuriyRozhovetskiy 我想用一些文本替换每个元素的文本,实际上我想将一个网站翻译成另一种语言。我想从页面中提取所有文本,然后进行翻译、替换和保存。 - Shahin
3
XML文档称该属性“获取或设置对象起始标记和结束标记之间的文本”,但只提供了一个“获取”方法,这很奇怪。 - BrainSlugs83
3个回答

23

尝试以下代码。它选择所有没有子节点的节点并过滤掉脚本节点。也许您需要添加一些额外的筛选条件。除了您的XPath表达式,这个表达式还寻找叶节点并过滤掉<script>标记的文本内容。

var nodes = doc.DocumentNode.SelectNodes("//body//text()[(normalize-space(.) != '') and not(parent::script) and not(*)]");
foreach (HtmlNode htmlNode in nodes)
{
    htmlNode.ParentNode.ReplaceChild(HtmlTextNode.CreateNode(htmlNode.InnerText + "_translated"), htmlNode);
}

非常好,谢谢。我该如何将翻译后的HTML覆盖到之前的文件中? 我从文件中加载节点。 - Shahin
如果可能的话,请描述一下我的代码XPath和你的有什么区别? - Shahin
只是为了额外澄清,将文本设置到节点的正确方法是通过用“HtmlTextNode.CreateNode(“text here ...”)”创建的新节点替换“HtmlTextNode”。 - KFL
我知道这是一个老问题,但你在这里救了我的命,谢谢! - Paulo Hgo

16

很奇怪,我发现 InnerHtml 并不是只读的。当我试图像这样设置它时:

aElement.InnerHtml = "sometext";

InnerText 的值也更改为 "sometext"


2
但是您运行的风险是同时更改HTML标记。 - jnoreiga
4
InnerHtml 不是只读的,而 InnerText 是只读的。有关 InnerText 不是只读的文档似乎是错误的。 - liang
1
虽然 InnerHtml 支持获取/设置,但在某些情况下,它似乎并没有真正改变文档内容。如果您设置了它,然后查看文档的 OuterHtml,则内容并不总是会被更改。 - Memetican
截至本评论时(2021年01月04日),它仅支持获取操作。 - mrbitzilla

5
HtmlTextNode类有一个Text属性*,非常适合此目的。

这是一个示例:

var textNodes = doc.DocumentNode.SelectNodes("//body/text()").Cast<HtmlTextNode>();
foreach (var node in textNodes)
{
    node.Text = node.Text.Replace("foo", "bar");
}

如果我们有一个 HtmlNode,想要更改它的 直接 文本,可以执行以下操作:

HtmlNode node = //...
var textNode = (HtmlTextNode)node.SelectSingleNode("text()");
textNode.Text = "new text";

如果它包含多个文本节点,我们可以使用 node.SelectNodes("text()")


* 不要与只读的 InnerText 属性混淆。


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