C# 使用XPath在不同标记之间搜索文本

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> &

我正在使用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>
<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而不是简单的文本方式替换跨度。我已经相应地更新了我的答案。