O que é uma maneira mais rápida de fazer a pesquisa através de xml

suponha que eu tenho um arquivo XML, que eu uso como base de dados local, Assim):

<root>
 <address>
  <firstName></firstName>
  <lastName></lastName>
  <phone></phone>
 </address>
</root>
Tenho algumas perguntas: 1. Qual será a forma mais rápida de encontrar o endereço(ou endereços) em XML onde o primeiro nome contém 'er', por exemplo?
2. é possível passar sem carregar todo o ficheiro XML em memória?

P. S. não estou à procura de alternativas de ficheiros XML, idealmente preciso de uma pesquisa que não dependa da contagem de endereços no ficheiro XML. Mas eu sou realista, e parece-me que não é possível.

actualização: Estou a usar. net 4
Obrigado por sugestões, mas é uma tarefa mais científica do que prática.. Provavelmente procuro maneiras mais rápidas do que linq e xmltextreader.

Author: John Saunders, 2011-03-02

6 answers

O LINQ para Xml funciona muito bem:

XDocument doc = XDocument.Load("myfile.xml");
var addresses = from address in doc.Root.Elements("address")
                where address.Element("firstName").Value.Contains("er")
                select address;

UPDATE: tente ver esta questão no StackOverflow: a melhor maneira de procurar dados em ficheiros xml?.

A resposta aceite de Marc Gravell funciona usando a indexação SQL:

Primeiro: de que tamanho são os ficheiros xml? XmlDocument não escala para "enorme"... mas pode lidar com "grande" OK.

Segundo, pode colocar os dados? numa estrutura de base de dados regular (talvez SQL Server Express Edition), indexá-lo e aceder através do TSQL normal? Que normalmente supera-executar um xpath pesquisa. De igual modo, se estiver estruturado, O SQL Server 2005 e superior suporta o tipo de dados xml, que desfaz os dados - isto permite-lhe indexar e consultar o xml dados na base de dados sem ter todo o DOM na memória (it traduz o xpath para relacional consulta).

UPDATE 2: Leia também outro link tomado pela pergunta anterior que explica como a estrutura do XML afeta performances: http://www.15seconds.com/issue/010410.htm

 7
Author: as-cii, 2017-05-23 12:34:15

Se tiver. net 3. 5+, considere a utilização de LINQ para XML .

Algum código de amostra para lhe dar uma ideia: (código abaixo retirado/modificado liberalmente do artigo)

IEnumerable<string> addresses =
    from inv in customer.Descendants("Invoice")
    where inv.Attribute("ProductName").StartsWith("er")
    select (string) inv.Attribute("StreetAddress");
 2
Author: p.campbell, 2011-03-02 23:05:29

Pode usar o XmlTextReader se não quiser ler o ficheiro inteiro na memória. Essa solução provavelmente funcionará mais rápido, mas envolverá mais codificação.

 1
Author: Miroslav Bajtoš, 2011-03-02 20:37:14
Preocupa-me que queiras optimizar algo que pode não precisar. De quantos endereços de E-mail estamos a falar? Na maioria das vezes você iria ler na entrada e construir uma estrutura que suporta o tipo de consultas que você estará executando.

Existem árvores que podem chegar ao tipo de resultados que você está procurando em ordem log(n) Tempo. E você pode armazenar uma tonelada de endereços em uma pequena quantidade de memória.

 1
Author: madmik3, 2011-03-02 21:01:12

Se você realmente não precisa fazer isso no lado do servidor, você pode fazê-lo com expressões regulares. Mas carregar o XML na memória seria mais rápido, acho eu...

 1
Author: David Diez, 2011-03-02 23:12:37

E quanto a XmlReader? Acho que pode ser a maneira mais rápida...

Tentei um ficheiro de cerca de 110 MB e demorou cerca de 1,1 segundos. O mesmo ficheiro com o LinqToXML (acima) demora cerca de 3 segundos.

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();
 1
Author: Pavel Jablonský, 2018-02-08 13:55:12