C# 使用XPath在不同标记之间搜索文本
我正在使用HtmlAgilityPack,我需要在Html文档中找到一个短语。例如,我有一份文件:C# 使用XPath在不同标记之间搜索文本,c#,html,xpath,html-agility-pack,C#,Html,Xpath,Html Agility Pack,我正在使用HtmlAgilityPack,我需要在Html文档中找到一个短语。例如,我有一份文件: <!DOCTYPE html> <html> <body> <h1>aaa Heading ilo araferi</h1> Thats <p>My <b>first</b> paragraph.</p> <p>My second paragraph.</p> &
<!DOCTYPE html>
<html>
<body>
<h1>aaa Heading ilo araferi</h1>
Thats <p>My <b>first</b> paragraph.</p>
<p>My second paragraph.</p>
<p>My third paragraph.</p>
</body>
</html>
aaa标题ilo araferi
这是我的第一段
我的第二段
我的第三段
我想把“那是我的第一段。”
放在span
里。为此,我需要找到所有只包含文本的事件(没有html标记)。比如说
这是我的第一段
换句话说,我希望短语那是我的第一段。
与那是我的第一段相匹配。
问题是,我不知道如何为这个特定任务执行XPath查询。任何帮助都将不胜感激。谢谢编辑:已更新,因此替换span后html仍然有效
using System.Collections.Generic;
using System.IO;
using System.Text;
using HtmlAgilityPack;
using System;
namespace Test {
class Program {
static void Main(string[] args) {
var markup = @"<!DOCTYPE html>
<html>
<body>
<h1>aaa Heading ilo araferi</h1>
Thats <p>My <b>first</b> paragraph.</p>
<p>My second paragraph.</p>
<p>My third paragraph.</p>
</body>
</html>";
var doc = new HtmlDocument();
doc.LoadHtml(markup);
var map = new List<HtmlNode>();
var nodes = doc.DocumentNode.SelectNodes("//text()");
var builder = new StringBuilder(markup.Length);
for (var j = 0; j < nodes.Count; j++) {
var node = nodes[j];
builder.Append(node.InnerHtml);
for (var i = 0; i < node.InnerHtml.Length; i++) {
map.Add(node);
}
}
var keyword = "Thats My first paragraph.";
int index = builder.ToString().IndexOf(keyword);
if (index >= 0) {
var firstNode = map[index];
var lastNode = map[index + keyword.Length - 1];
var ancestor = Ancestor(firstNode, lastNode);
if (ancestor != null) {
while (firstNode != null && Level(firstNode) - Level(ancestor) > 1) {
firstNode = firstNode.ParentNode;
}
while (lastNode != null && Level(lastNode) - Level(ancestor) > 1) {
lastNode = lastNode.ParentNode;
}
if (firstNode != null && lastNode != null && ancestor == Ancestor(firstNode, lastNode)) {
var span = doc.CreateElement("span");
ancestor.ChildNodes.Insert(ancestor.ChildNodes.IndexOf(firstNode), span);
int start = ancestor.ChildNodes.IndexOf(firstNode);
int end = ancestor.ChildNodes.IndexOf(lastNode);
for (var i = start; i <= end; i++) {
var node = ancestor.ChildNodes[start];
ancestor.ChildNodes.Remove(start);
span.ChildNodes.Append(node);
}
}
}
}
var writer = new StringWriter();
doc.Save(writer);
markup = writer.ToString();
}
public static HtmlNode Ancestor(HtmlNode a, HtmlNode b) {
if (a == null) {
throw new ArgumentNullException("a");
}
if (b == null) {
throw new ArgumentNullException("b");
}
var parentsOfA = new List<HtmlNode>();
while (a != null) {
parentsOfA.Add(a);
a = a.ParentNode;
}
while (b != null) {
if (parentsOfA.Contains(b)) {
return b;
}
b = b.ParentNode;
}
return null;
}
public static int Level(HtmlNode node) {
int level = 0;
while (node != null) {
level++;
node = node.ParentNode;
}
return level;
}
}
}
使用System.Collections.Generic;
使用System.IO;
使用系统文本;
使用HtmlAgilityPack;
使用制度;
名称空间测试{
班级计划{
静态void Main(字符串[]参数){
var标记=@“
aaa标题ilo araferi
这是我的第一段
我的第二段
我的第三段
";
var doc=新的HtmlDocument();
doc.LoadHtml(标记);
var map=新列表();
var nodes=doc.DocumentNode.SelectNodes(“//text()”);
var builder=新的StringBuilder(markup.Length);
对于(var j=0;j=0){
var firstNode=map[index];
var lastNode=map[索引+关键字.Length-1];
var祖先=祖先(firstNode,lastNode);
if(祖先!=null){
while(firstNode!=null&&Level(firstNode)-Level(祖先)>1){
firstNode=firstNode.ParentNode;
}
while(lastNode!=null&&Level(lastNode)-Level(祖先)>1){
lastNode=lastNode.ParentNode;
}
if(firstNode!=null&&lastNode!=null&&祖先==祖先(firstNode,lastNode)){
var span=doc.CreateElement(“span”);
祖先.ChildNodes.Insert(祖先.ChildNodes.IndexOf(firstNode),span);
int start=祖先.ChildNodes.IndexOf(firstNode);
int end=祖先.ChildNodes.IndexOf(lastNode);
对于(var i=start;i对于此,我需要查找所有出现的文本不清楚的情况,谢谢。我更新了问题。我不是以英语为母语的人,很抱歉给您带来不便:)您可能无法在HTML中的span标记内包装段落标记。请改用div标记。谢谢Ondrej。我感谢您的帮助。但是有一个小问题,将span中的内容包装在span中会破坏标记。span将在p标记之前打开,在p标记之前关闭。问题并不像看上去那么简单:(@Davita-你是对的,要让替换后的html有效,你需要找到共同的祖先,并用HtmlNode而不是简单的文本方式替换跨度。我已经相应地更新了我的答案。