【问题标题】:How to read two XML files simultaneously in an efficient way如何以有效的方式同时读取两个 XML 文件
【发布时间】:2012-04-17 14:45:19
【问题描述】:

我有一个复杂的案例:我有三个 XML 文件,我需要同时读取它们并根据匹配获取结果。下面是一个有效的(但假的)示例,与我正在做的几乎相似。

例如,我有两个 xml 文件,两者相似,但在标签和属性方面,但内容(语言)不同。我正在同时阅读两种语言,就像在 C# 文件中的代码中一样:

XElement x1 = XElement.Load (@"abc.xml");
XElement x2 = XElement.Load (@"xyz.xml");


var ch = from var1 in x1.Elements("language1") 
         where var1.Attribute("index").Value == "1"
         from var2 in x2.Elements("language2")
         where var2.Attribute("index").Value == var1.Attribute("index").Value
         select dictChapter as new
         {  
             sentenceNumber = var1.Attribute("index").Value,
             SentenceInLanguage1 = var1.Attribute("text").Value,
             SentenceInLanguage2 = var2.Attribute("text").Value,
         };

ListBox.DataContext = ch;

这里的问题是,x1 包含 1000 个句子,所以 x2。上面的逻辑就像一个嵌套循环一样工作,这大大减慢了处理速度。它像

x1.1 -> x2.1:1000
x1.2 -> x2.1:1000

for i in x1
  for j in x2

有没有更好更有效的方法从x1和x2中选择句子,其中x1的句子id等于x2的句子id?

【问题讨论】:

  • 您是否对此进行了调试或分析以查看繁重的处理发生在哪里?如果较重的处理来自将文件数据读入内存或进行匹配,那么了解可能会有好处。
  • 我对调试工具了解不多。但是当我使用简单的调试,但是执行以下语句时需要时间lstBox.DataContext = ch
  • 同上,当我只用一种语言从一个文件中读取时,几乎不需要时间,但是当我从两个文件中读取时,如上所述,时间呈指数增长。
  • 如果有两个列表框,您可能希望尝试在每个列表框上并行分配 DataContext。您的代码没有显示您在所有过滤后所做的事情,所以我不确定挂断之后是什么。它可能与未被访问/读取的数据有关,然后分配给列表框,直到它被实际使用。 LINQ 就是这样做的。
  • 这正是问题所在,我只有一个ListBox,无法将两个dataItems绑定到一个List box。

标签: c# .net performance linq linq-to-xml


【解决方案1】:

据我了解你想要的,

您可以使用join 来执行此操作。

这是一个很好的示例链接LINQ to XML : Join Xml Data (Wriju's BLOG)

...或类似的东西...

var root = (from var1 in x1.Elements("language1")
            join var2 in x2.Elements("language2") on (string)var1.Attribute("index") equals (string)var2.Attribute("index")
            select new
            {
                SentenceNumber = (string)var1.Attribute("index"),
                SentenceInLanguage1 = (string)var1.Element("text"),
                SentenceInLanguage2 = (string)var2.Element("text")
            });

【讨论】:

  • 我需要再添加一个条件 "and var1.something >= '10' ",我该怎么做?
  • 试试where var1.Attribute("somehting").ToInt() > 10 - 如果这是你想要的
  • 是的,我添加了 WHERE,它可以工作......而且它确实有效!高效!
  • 现在我真的需要了解 JOIN 子句是如何工作的?我的版本和使用 JOIN 有什么区别
  • from fromSelectMany 其中 for each 的第一个经过 each 的第二个 - 即你有 O(n^2) (或 m x n) - 虽然优化了连接,但不确定确切的实施,但可能是两次传递或其他东西。
【解决方案2】:

在 Linq 中,以下语句是等效的,并且将提供相同的结果:

from i1 in items1
from i2 in items2
where i1 == i2

from i1 in items1
join i2 in items2 on i1 equals i2

它们甚至会被翻译成相同的 SQL(使用 Linq to SQL)。对于 MS SQL,在这两种情况下,结果 SQL 都将包含 join 子句(这就是为什么在查询数据库时不需要使用不太灵活的join

但是对于 Linq to ObjectsLinq to XML 两者将以不同的方式执行。第一个将导致嵌套循环,第二个不会。

因此,您只需按照@NSGaga 的建议更改您的实现以使用join

另一个优化是添加.ToList():

ListBox.DataContext = ch;

我不确定数据绑定,但由于 linq 的延迟性质,您的表达式可能会被多次重新评估。

【讨论】:

  • 快完成了,但我无法使用“and”语句 x1.inex equals x2.index “and”x1.sss >= 10... 谷歌搜索答案
  • 这就是为什么join 不酷:) 几乎你无法做到and x1.sss >= 10 部分。我建议为这种情况添加另一个 where
  • 所以你的意思是 join 只支持一个条件?
  • 是的。你可以通过使用匿名对象来实现and '等于':on new {i1.prop1, i1.prop2} equals new {i2.prop1, i2.prop2},但是像>= 这样的东西更复杂
【解决方案3】:

简单!只需按顺序浏览每个文件。第一遍:创建sentenceNumber > SentenceInlanguage1 的字典。

在您的第二次传递中,按照您显示的代码创建您的可枚举,并粘贴第一次传递中的数据以用于 SentenceInLanguage1 变量。

如果您希望同时检查这两个,只需获取一个枚举器 (GetEnumerator) 并在一个普通的旧 while 循环中检查那些,移动到下一个 XElement 末尾的两个枚举器循环体。

【讨论】:

  • 我会试试这个,另一个答案的解决方案,根据我对效率的观察,我会进一步让你知道。但是,在读取两个单独的 dataItem 中的数据后,如何绑定到单个 ListBox?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 2022-10-04
  • 1970-01-01
相关资源
最近更新 更多