Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用C搜索连续XML节点的值?_C#_Xml_Linq_Xpath_Linq To Xml - Fatal编程技术网

C# 如何使用C搜索连续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

我想从具有连续子节点的XML中选择节点,这些子节点的值与搜索词中的相应单词匹配

下面是一个示例XML:

<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);
    }
}