4

我正在读取一堆 XML 文件,对其进行转换并将数据加载到另一个系统中。

以前我使用 ThreadPool 完成了这项工作,但是文件的提供者和结构已经改变,所以我现在正在尝试 Aysync-Await 并得到一个奇怪的结果。

当我处理文件时,我得到一个 xmlNodes 列表并循环它们

foreach (XmlNode currentVenue in venueNodes)
{
      Console.WriteLine(currentVenue.OuterXml);
      Console.WriteLine(currentVenue.SelectSingleNode(@"//venueName").InnerText);
}

但是第二个 WriteLine 总是返回第一个节点的预期结果,例如:

<venue venueID="xartrix" lastModified="2012-08-20 10:49:30"><venueName>Artrix</venueName></venue>
Artrix
<venue venueID="xbarins" lastModified="2013-04-29 11:39:07"><venueName>The Barber Institute Of Fine Arts, University Of Birmingham</venueName></venue>
Artrix
<venue venueID="xbirmus" lastModified="2012-11-13 16:41:13"><venueName>Birmingham Museum &amp; Art Gallery</venueName></venue>
Artrix

这是完整的代码:

public async Task ProcessFiles()
{
    string[] filesToProcess = Directory.GetFiles(_filePath);
    List<Task> tasks = new List<Task>();

    foreach (string currentFile in filesToProcess)
    {
        tasks.Add(Task.Run(()=>processFile(currentFile)));
    }

    await Task.WhenAll(tasks);

}

private async Task processFile(string currentFile)
{
    try
    {
         XmlDocument currentXmlFile = new XmlDocument();
         currentXmlFile.Load(currentFile);

         //select nodes for processing
         XmlNodeList venueNodes = currentXmlFile.SelectNodes(@"//venue");

         foreach (XmlNode currentVenue in venueNodes)
         {
              Console.WriteLine(currentVenue.InnerXml);
              Console.WriteLine(currentVenue.SelectSingleNode(@"//venueName").InnerText);                 
         }
     }
     catch (Exception e)
     {
         Console.WriteLine(e.Message);
     }
 }

显然我错过了一些东西,但我看不到什么,有人可以指出吗?

4

2 回答 2

10

SelectSingleNode从文档中按文档顺序仅返回单个节点。@jbl 是正确的,//venueName从文档根目录开始。//xpath 运算符是“后代选择器”运算符。

我经常使用 XML 和 XPath,这是一个常见的错误。调用时需要确保上下文节点正确SelectSingleNode。所以,就像我们刚才所说的那样, using从文档的根目录开始获取文档顺序中//venueName的第一个节点。<venueName />

为了获取<venueName />您正在迭代的当前节点的子节点,您需要使用以下代码:

foreach (XmlNode currentVenue in venueNodes)
{
    Console.WriteLine(currentVenue.OuterXml);
    Console.WriteLine(currentVenue.SelectSingleNode(@".//venueName").InnerText); // The '.' means from the current node. Without it, searching starts from the document root, not currentVenue.
}

那应该可以解决您的问题。

于 2013-05-20T14:51:11.430 回答
1

//venueName从文档根目录搜索?

我猜想,结合SelectSingleNode, 将始终在同一个结果节点(venueName文档的第一个节点)上结束

您可以尝试替换//venueNamevenueName

于 2013-05-20T13:38:32.427 回答