假设我有一个XML文件,我用作本地数据库,就像这样):
<root>
<address>
<firstName></firstName>
<lastName></lastName>
<phone></phone>
</address>
</root>
我有几个问题:
1. 在first中包含'er'的XML中查找地址(或地址)的最快方法是什么?
2. 是否可以在内存中没有完整加载XML文件?
P.S。我不是在寻找XML文件替代品,理想情况下我需要一个不依赖于XML文件中地址数的搜索。但我是现实主义者,在我看来,这是不可能的。
更新
我正在使用.net 4
感谢您的建议,但它比实际更科学。我可能正在寻找比linq和xmltextreader更快的方法。
答案 0 :(得分:9)
LINQ to Xml非常好用:
XDocument doc = XDocument.Load("myfile.xml");
var addresses = from address in doc.Root.Elements("address")
where address.Element("firstName").Value.Contains("er")
select address;
更新:尝试在StackOverflow上查看此问题:Best way to search data in xml files?。
Marc Gravell接受的答案使用SQL索引:
首先:xml文件有多大? XmlDocument不会扩展为“巨大”......但可以处理“大”OK。
第二:你可以把数据放一下吗? 进入常规数据库结构 (也许是SQL Server Express Edition), 索引它,并通过常规TSQL访问? 这通常会胜过xpath 搜索。同样,如果它是结构化的, SQL Server 2005及更高版本支持 xml数据类型,粉碎数据 - 这允许您索引和查询xml 没有数据库中的数据 内存中的整个DOM(它 将xpath转换为关系 查询)。
更新2:另请阅读上一个问题所采用的另一个链接,该链接解释了XML结构如何影响效果:http://www.15seconds.com/issue/010410.htm
答案 1 :(得分:2)
如果您使用的是.NET 3.5+,请考虑使用LINQ To XML。
一些示例代码可以让您有所了解:(以下代码从文章中解放/修改)
IEnumerable<string> addresses =
from inv in customer.Descendants("Invoice")
where inv.Attribute("ProductName").StartsWith("er")
select (string) inv.Attribute("StreetAddress");
答案 2 :(得分:2)
那么XmlReader呢? 我认为这可能是最快的方式......
我尝试了大约110 MB的文件,花了大约1,1秒。 与LinqToXML(上面)相同的文件大约需要3秒。
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
XmlReader reader = XmlReader.Create("C:\\Temp\\items.xml", settings);
String firstName = "", lastName = "", phone = "";
String lastTagName = "";
Boolean bItemFound = false;
long nCounter = 0;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
reader.MoveToContent();
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
//Console.Write("<{0}>", reader.Name);
lastTagName = reader.Name;
if (lastTagName == "address")
nCounter++;
break;
case XmlNodeType.Text:
//Console.Write(reader.Value);
switch (lastTagName)
{
case "firstName":
firstName = reader.Value.ToString();
bItemFound = firstName.Contains("97331");
break;
case "lastName":
lastName = reader.Value.ToString();
break;
case "phone":
phone = reader.Value.ToString();
break;
}
break;
case XmlNodeType.CDATA:
//Console.Write("<![CDATA[{0}]]>", reader.Value);
break;
case XmlNodeType.ProcessingInstruction:
//Console.Write("<?{0} {1}?>", reader.Name, reader.Value);
break;
case XmlNodeType.Comment:
//Console.Write("<!--{0}-->", reader.Value);
break;
case XmlNodeType.XmlDeclaration:
//Console.Write("<?xml version='1.0'?>");
break;
case XmlNodeType.Document:
case XmlNodeType.DocumentType:
//Console.Write("<!DOCTYPE {0} [{1}]", reader.Name, reader.Value);
break;
case XmlNodeType.EntityReference:
//Console.Write(reader.Name);
break;
case XmlNodeType.EndElement:
//Console.Write("</{0}>", reader.Name);
break;
}
if (bItemFound)
{
Console.Write("{0}\n{1}\n{2}\n", firstName, lastName, phone);
bItemFound = false;
}
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
Console.WriteLine("Searched items: {0}", nCounter);
Console.ReadKey();
答案 3 :(得分:1)
如果您不想将整个文件读入内存,可以使用XmlTextReader。这样的解决方案可能运行得更快,但它将涉及更多编码。
答案 4 :(得分:1)
我担心你可能想要优化可能不需要它的东西。我们在谈论多少个电子邮件地址?大多数情况下,您将阅读输入并构建一个支持您将运行的查询类型的结构。
有些树可以在log(n)时间内获得您正在寻找的那种结果。而且你甚至可以在少量内存中存储大量地址。
答案 5 :(得分:1)
如果您真的不需要在服务器端执行此操作,则可以使用正则表达式执行此操作。但是我认为在memmory上加载XML会更快......