Недавно я столкнулся с ситуацией, когда мне пришлось использовать XPath как часть запроса Linq to XML и обнаружил, что он действует немного странно. Я уверен, что есть другие способы решения проблемы с использованием собственных методов XElement API, но в этой ситуации XPath был намного лучше подходит для определения конкретных текстовых значений XML, которые мне нужны, поскольку структура документа была довольно сложной. В конце концов я нашел способ заставить его работать (см. Ниже), но это было не очень красиво, что обычно означает, что я что-то пропустил.Использование XPathEvaluate для получения значения текстового узла в запросе Linq-to-Xml
Мой вопрос в том, как вы можете использовать XPathEvalute или какой-либо другой метод XPath для возврата строкового значения, которое может использоваться в инструкции where или как часть нового объекта в методе select. Я нашел решение, которое использует много литья и Null coalesing operator in LINQ, но должен быть более чистый способ. Корень проблемы заключается в том, что метод XPathEvaluate обычно возвращает элемент XText (отлитый от общего объекта), но Linq преобразует его в IEnumerable, чтобы он мог задержать выполнение. Это вызывает проблемы при попытке получить доступ к значению этого объекта, так как оно не будет реализовано до тех пор, пока запрос не будет выполнен.
Вот пример: Используя следующий документ XML, найдите всех родителей, у которых есть мальчик и девочка с тем же именем. Это ДОЛЖНО выполняться с использованием запроса XPath, так как в моей ситуации структура документа была очень сложной.
//Use C# Program Language type in LinqPad
void Main()
{
var xml = XElement.Parse(@"<Root>
<Parent>
<Boy>Anne</Boy>
</Parent>
<Parent>
<Boy>Alex</Boy>
<Girl>Alex</Girl>
</Parent>
<Parent>
<Boy>Jay</Boy>
</Parent>
</Root>");
var q1 = from e in xml.XPathSelectElements("/Parent")
select e;
q1.Dump();
var q2 = from e in q1
let boy = ((IEnumerable<Object>)e.XPathEvaluate("Boy/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("")
let girl = ((IEnumerable<Object>)e.XPathEvaluate("Girl/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("")
select new {t=boy.GetType(), b=boy, g=girl, same=(boy.Value==girl.Value)};
q2.Dump();
}
Результаты:
Вы можете видеть, что второй элемент идентифицируется как имеющий мальчик и девочка с таким же именем. Есть ли более чистый способ сделать это, все еще используя XPath или я застрял, используя код сверху.
Вы могли бы упростить XPath, чтобы получить все родители с критериями, которые вы ищете: // Родитель [Boy/текст() = девушка/текст()] – JWiley