C# 如何使用C搜索连续XML节点的值?
我想从具有连续子节点的XML中选择节点,这些子节点的值与搜索词中的相应单词匹配 下面是一个示例XML:C# 如何使用C搜索连续XML节点的值?,c#,xml,linq,xpath,linq-to-xml,C#,Xml,Linq,Xpath,Linq To Xml,我想从具有连续子节点的XML中选择节点,这些子节点的值与搜索词中的相应单词匹配 下面是一个示例XML: <book name="Nature"> <page number="4"> <line ln="10"> <word wn="1">a</word> <word wn="2">whi
<book name="Nature">
<page number="4">
<line ln="10">
<word wn="1">a</word>
<word wn="2">white</word>
<word wn="3">bobcat</word>
<word wn="3">said</word>
</line>
<line ln="11">
<word wn="1">Hi</word>
<word wn="2">there,</word>
<word wn="3">Bob.</word>
</line>
</page>
请注意,之所以选择第ln=10行,是因为它包含两个与搜索词匹配的顺序正确的连续单词。白色=%Hi%bobcat=%Bob%
但是,由于匹配节点不连续,因此未选择下一行ln=11
请注意,搜索词中的所有单词都应匹配,以便将其视为匹配词
谢谢大家!
[编辑]
我尝试了下面的解决方案,得到了预期的结果。有没有更好或更有效的方法来实现这一点?该程序每天必须搜索100000个XML文件,每个文件的大小为300KB到50MB
XDocument xDoc = XDocument.Load(@"C:\dummy.xml");
var xLines = xDoc
.Descendants("page")
.Descendants("line");
foreach (var xLine in xLines)
{
var xFirstWords = xLine
.Descendants("word")
.Where(item => item.Value.ToUpper().Contains("HI"));
foreach (var xFirstWord in xFirstWords)
{
var xNextWord = xFirstWord.NodesAfterSelf().OfType<XElement>().First();
if(xNextWord.Value.ToUpper().Contains("BOB"))
{
MessageBox.Show(xLine.FirstAttribute.Value + " " + xFirstWord.FirstAttribute.Value + " " + xNextWord.FirstAttribute.Value);
}
}
}
我可以即兴编写代码。如果您有更好的解决方案,请告诉我
XDocument xDoc = XDocument.Load(@"C:\dummy.xml");
var xLines = xDoc
.Descendants("page")
.Descendants("line");
foreach (var xLine in xLines)
{
var xFirstWords = xLine
.Descendants("word")
.Where(item => item.Value.ToUpper().Contains("HI"))
.Where(item => item.ElementsAfterSelf("word").First().Value.ToUpper().Contains("BOB"));
foreach (var xFirstWord in xFirstWords)
{
var xNextWord = xFirstWord.ElementsAfterSelf("word").First();
MessageBox.Show(xLine.FirstAttribute.Value + " " + xFirstWord.FirstAttribute.Value + " " + xNextWord.FirstAttribute.Value);
}
}
我不知道这段代码的性能是更好还是更差,但我很确定它会有所不同,所以可能值得一试。重新构造行的文本,然后使用正则表达式进行匹配
Regex re = new Regex(@"^.*Hi\s+\S+\s+Bob$*", RegexOptions.IgnoreCase);
XDocument xDoc = XDocument.Load(@"C:\Users\user\Documents\temp.xml");
foreach (XElement xLine in xDoc.Root.Descendants("line")) {
string text = string.Join(" ", xLine.Elements("word").Select(x => x.Value));
if (re.IsMatch(text)) {
Console.WriteLine(text);
}
}
在性能方面,您会想到以下事项: .Nodes将比.Descendants快,因为它只获取直接子级。 将IndexOf与OrdinalIgnoreCase一起使用,而不是与ToUpper.Contains一起使用。 在foreach而不是NodesAfterSelf中,您可以只保留上一个节点。 变量xLines=xDoc.genderantsline; foreach var xLine在xLine中 { XNode-prevWord=null; xLine.Nodesword中的每个变量字 { ifprevWord==null&&word.Value.IndexOfHI,StringComparison.ordinallingorecase { 单词==单词; } else ifprevWord!=null&&word.Value.IndexOfBOB,StringComparison.OrdinalIgnoreCase { MessageBox.ShowxLine.FirstAttribute.Value++prevWord.FirstAttribute.Value++word.FirstAttribute.Value; } } }
不是我的反对票,而是。。。这不是免费的编码服务。如果你需要帮助,你需要表现出真诚的努力,试图自己解决问题。你试过什么?结果和你想要的有什么不同?非常感谢你,尼古拉斯。这完全有道理。我编辑了问题并添加了代码。它给出了预期的结果。然而,我不确定这是否是最有效的方法。我必须搜索数千个XML,每个XML都以MBs运行。
Regex re = new Regex(@"^.*Hi\s+\S+\s+Bob$*", RegexOptions.IgnoreCase);
XDocument xDoc = XDocument.Load(@"C:\Users\user\Documents\temp.xml");
foreach (XElement xLine in xDoc.Root.Descendants("line")) {
string text = string.Join(" ", xLine.Elements("word").Select(x => x.Value));
if (re.IsMatch(text)) {
Console.WriteLine(text);
}
}