2009-07-23 2 views
1

У нас есть файл XML с очень простой реализации XLink:Как реализовать простой XPath поиск

<root xmlns:xlink="http://www.w3.org/1999/xlink"> 
    <firstChild id="ID1" /> 
    ... 
    <ref xlink:href="#ID1" /> 
</root> 

Давайте предположим, что реализация XLink не получит какой-либо более сложным, чем это. Однако важным моментом является то, что упомянутый элемент (в данном случае firstChild) может появляться где угодно в документе, где угодно в иерархии.

В XPath Lookup можно найти элемент, упомянутый в < исх> узел, используя выражение типа:

//*[@id='ID1'] 

Какой самый лучший эквивалент использования LINQ to XML? Я бы подумал что-то в этом духе:

XDocument doc = XDocument.Load("file.xml"); 
var dest = xDoc.Descendants().Where(e => (string)e.Attribute("id") == "ID1").SingleOrDefault(); 

Я еще не проверял его. Но в общих чертах, если XML-документ достаточно велик, способ LINQ будет неэффективным (поскольку он использует перечисление всех потомков на XDocument)? Было бы лучше вернуться к XPathNavigator и просто использовать выражение XPath?

Если это возможно в LINQ, это лучший способ, чем то, что я написал? LINQ мне все еще всего несколько дней ... Это потрясающе, но мне интересно, имеет ли он ограничения эффективности для определенных операций.

ответ

3

XPathNavigator не будет более эффективным здесь, потому что ему все равно придется перечислять всех потомков, чтобы найти их - там нет волшебной пыли. Если вы хотите, чтобы он был более эффективным, вам понадобится индекс, и никакой встроенный XML API не предоставит их из коробки, поэтому вам придется развернуть свои собственные. Например:

XDocument doc = ...; 
var id2elem = (from e in doc.Descendants() 
       let id = e.Attribute("id") 
       where id != null 
       select new { Id = id.Value, Element = e }) 
       .ToDictionary(kv => kv.Id, kv => kv.Element); 

, а затем использовать этот словарь для поиска узлов по идентификатору, когда вам нужно. Очевидно, что это стоит того, если поиски относительно часты, а не если вам просто нужно сделать это один или два раза.

+0

Именно то, что я искал :) –

1

Если бы я был вами, я бы сделал это таким же образом. За исключением случаев, когда:

from e in xDoc.Descendants() 
let id = e.Attribute("id") ? e.Attribute("id").Value : null 
where (id == "ID") 
select e 

Таким образом, нет необходимости делать литье типа.

Что касается вашего первого вопроса, насколько я знаю, Microsoft остановила разработку в реализации XPath, поэтому я считаю, что даже на данный момент LINQ   до   XML будет иметь гораздо лучшую оптимизацию по сравнению с XPath.

+0

Это выбросит 'NullReferenceException' если какой-то узел в документе не будет иметь' @ id' –

+1

Кроме того, нет никакого «оптимизации» в любом XPath (как это реализовано в XPathNavigator) или LINQ! Это не волшебство. Он работает точно так, как вы ожидаете, это линейный сканирование повсюду. Он не может использовать индексы, потому что как он узнает, что вы собираетесь искать, и что индексировать? В любом случае XPathNavigator может быть быстрее для некоторых типов запросов, потому что его узлы имеют двойную связь, а XLINQ - односвязными (поэтому получение предшествующего брата в XPathDocument равно O (1), но в XLINQ это O (N)) , –

+0

Оптимизация означает, как MS реализует коды. Это то же самое, что и каждый браузер, реализующий JS-движок, и он появляется в настоящее время Safari, Chrome - скорость и IE.Все они тестировались с использованием одного JS-кода, и единственная разница в том, как стратегия и алгоритмы исполнения браузера внутри. Оптимизация, о которой я сказал, - одно и то же, MS приложит усилия для ускорения работы LINQ (er). – xandy

Смежные вопросы