gpt4 book ai didi

.net - 使用 XPath(在 .NET 中)在两个标记之间选择(兄弟)

转载 作者:行者123 更新时间:2023-12-03 15:56:22 26 4
gpt4 key购买 nike

我正在使用 .NET 3.5 (C#) 和 HTML Agility Pack做一些网页抓取。我需要提取的一些字段结构为段落,其中的组件由换行标记分隔。我希望能够选择换行符之间的各个组件。每个组件都可以由多个元素组成(即,它可能不仅仅是一个字符串)。例子:

<h3>Section title</h3>
<p>
<b>Component A</b><br />
Component B <i>includes</i> <strong>multiple elements</strong><br />
Component C
</p>

我想选择
<b>Component A</b>

然后:
Component B <i>includes</i> <strong>multiple elements</strong>

进而:
Component C

也可能有更多( <br /> 分隔的)组件。

我可以很容易地得到第一个组件:
p/br[1]/preceding-sibling::node()

我还可以通过以下方式轻松获取最后一个组件:
p/br[2]/following-sibling::node()

但是我无法弄清楚如何提取节点集/在/两个其他标记之间(即,是兄弟节点但在节点 X 之前并在节点 Y 之后的节点)。

另一种方法是手动扫描元素——如果这是最简单的方法,那我就是这样做的,但到目前为止,XPath 的简洁给我留下了深刻的印象,所以我希望有一种方法可以做到这一点,也。

编辑

由于我需要处理拥有超过 3 个组件的情况,似乎答案至少需要多次 XPath 调用,所以我将继续基于此的解决方案(这是我“接受”的答案)。 AakashM 的回答也帮助我理解了 XPath,因此我投了赞成票。

感谢大家的帮助!我希望有一天我能返回这个人情。

编辑 2

Dimitre Novatchev 提供的新答案经过一些调整,确实可以正常工作。

解决方案:
int i = 0;
do
{
yield return para.SelectNodes(String.Format(
"node()[not(self::br) and count(preceding-sibling::br) = {0}]", i));
++i;
} while (para.SelectSingleNode(String.Format("br[{0}]", i)) != null);

我应该注意到,由于重复 XPath 查询以确定是否还有更多 br,因此该循环效率有些低。标签。在我的情况下,效率低下不是问题,但是请注意是否要在其他情况下使用此答案(再说一次,如果您确实想在对性能敏感的情况下执行此操作,则无论如何都应该手动扫描而不是使用 XPath)。

以及完整的测试代码(AakashM 包含的测试代码的修改版本):
using System;
using System.Collections.Generic;
using System.Xml;

namespace TestXPath
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(@"
<x>
<h3>Section title</h3>
<p>
<b>Component A</b><br />
Component B <i>includes</i> multiple <strong>elements</strong><br />
Component C
</p>
</x>
");


foreach (var nodes in SplitOnLineBreak(doc.SelectSingleNode("x/p")))
{
Dump(nodes);
Console.WriteLine();
}

Console.ReadLine();
}

private static IEnumerable<XmlNodeList> SplitOnLineBreak(XmlNode para)
{
int i = 0;
do
{
yield return para.SelectNodes(String.Format(
"node()[not(self::br) and count(preceding-sibling::br) = {0}]", i));
++i;
} while (para.SelectSingleNode(String.Format("br[{0}]", i)) != null);
}

private static void Dump(XmlNodeList nodes)
{
foreach (XmlNode node in nodes)
{
Console.WriteLine(string.Format("-->{0}<---",
node.OuterXml));
}
}
}
}

最佳答案

如果在您的情况下,您总是正好有三个“部分”,用 br 分隔s,你可以使用这个 XPath 来获得中间的“片断”:

//node()[preceding::br and following::br]

它使用 precedingfollowing轴返回两个 br 之间的所有节点s,任何地方。

编辑这是我的测试应用程序(请原谅 XmlDocument,我仍在使用 .NET 2.0...)
using System;
using System.Xml;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(@"
<x>
<h3>Section title</h3>
<p>
<b>Component A</b><br />
Component B <i>includes</i> <strong>multiple elements</strong><br />
Component C
</p>
</x>
");

XmlNodeList nodes = doc.SelectNodes(
"//node()[preceding::br and following::br]");

Dump(nodes);

Console.ReadLine();
}

private static void Dump(XmlNodeList nodes)
{
foreach (XmlNode node in nodes)
{
Console.WriteLine(string.Format("-->{0}<---",
node.OuterXml));
}
}
}
}

这是输出:
-->
Component B <---
--><i>includes</i><---
-->includes<---
--><strong>multiple elements</strong><---
-->multiple elements<---

如您所见,您得到一个 XmlNodeListbr 之间的所有内容s。

我的想法是:这个XPath返回任何地方的任何节点,只要对于那个节点,前面的轴包含一个 br , 以下轴包含 br .

关于.net - 使用 XPath(在 .NET 中)在两个标记之间选择(兄弟),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1302163/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com