2014-11-11 2 views
1

Я ОЧЕНЬ новичок в использовании LINQ. У меня есть следующий XML:Возвращаемые значения элементов по атрибуту с использованием C# и Linq

<?xml version="1.0" encoding="utf-8" ?> 
<root> 
    <RetentionValue code="NR" fullName="Normal Retention">Used for normal retention periods commonly expressed as only numbers (i.e. "25" for 25 years).</RetentionValue> 
    <RetentionValue code="SR" fullName="Short Retention">Used for short retention periods expressed in terms of months (i.e. "6 months").</RetentionValue> 
    <RetentionValue code="AR" fullName="Annual Review">Review annually and retain what is needed, dispose of what is not needed.</RetentionValue> 
    <RetentionValue code="PE" fullName="Permanent">Document is to be retained permanently.</RetentionValue> 
    <RetentionValue code="EX" fullName="Expiration">Disposal date is calculated from expiration of a contract, loan, or other such instrument.</RetentionValue> 
    <RetentionValue code="LI" fullName="Lifetime">Disposal date is calculated from the end-of-life date for a piece of equipment or other asset (e.g. software application).</RetentionValue> 
    <RetentionValue code="TE" fullName="Employee Termination">Disposal date is calculated from the date of termination or retirement of an employee.</RetentionValue> 
    <RetentionValue code="FR" fullName="Final Resolution">Disposal date is calculated from the date of final resolution for an issue.</RetentionValue> 
</root> 

В моем коде, я создаю объект, который имеет свойство RetentionEvent, который имеет значение одного из двух буквенных кодов выше. Я хочу найти элемент с соответствующим атрибутом, а затем вернуть fullName в одно текстовое поле и значение (многословное описание) в другое текстовое поле. До сих пор у меня есть следующий:

// Construct a RecordDisposal object by passing it a valid retention code. 
// An exception will be thrown if the code is not valid. 
_rd = new RecordDisposal(RetentionCode.Text); 
// Load up XML file with description of codes. 
XDocument rangeValues = XDocument.Load("DisposalRangeValues.xml"); 
XElement codeValue = rangeValues.Root.Elements().Single(x => (string)x.Attribute("code") == _rd.DisposalList[0].RetentionEvent); 
CodeName.Text = codeValue.Attribute("fullName").Value.ToString(); 
CodeDescription.Text = codeValue.Value.ToString(); 

Запроса является прямым модом из this кода (я думаю), но я получаю несколько ошибок я не понимаю: «Тело запроса должно заканчиваться с предложением select или групповым предложением « (я думал, что это то, что было для ToList()), и « Тип выражения в предложении select неверен. Ошибка ввода типа в вызове «Выбрать». » К сожалению, я не понимаю Linq достаточно хорошо, чтобы устранить эту проблему, и «Помощь по этой ошибке» не дает ничего полезного.

Что я сделал неправильно? Кроме того, я подозреваю, что функция ToList() вернет что-то, что плохо отображается в функции ToString(), но я ожидал, чтобы выяснить другие вещи, прежде чем обманывать это. Если у кого есть предложение, пожалуйста, предложите его.

EDIT: Измененный код для использования Одиночный, основанный на рекомендации ниже. Обнаружено, что rangeValues загружает все <root> как единый узел.

EDIT2: Выяснено. Изменен код для использования rangeValues.Root.Elements(). Обновленный код выше, чтобы отразить.

ответ

1

переформатирован немного, вы код выглядит следующим образом:

XElement codeValue = 
    from fullName 
    in rangeValues.Elements() 
        .Where(x => (string)x.Attribute("code") == _rd.DisposalList[0].RetentionEvent) 
        .ToList(); 
    // select ??? 

Так ToList() применяется к in части вашего запроса, но вам не хватает a select заявление.

На самом деле, так как вы хотите, чтобы вернуть один XElement, вы, вероятно, хотите что-то вроде этого, который выбирает единственный элемент в коллекции, которая соответствует пункт, указанный в Single():

XElement codeValue = 
    (from fullName in rangeValues.Elements() 
    where (string)fullName.Attribute("code") == _rd.DisposalList[0].RetentionEvent 
    select fullName).Single(); 

Альтернативный синтаксис (выше, является синтаксис запроса, следующим называется метод синтаксис):

XElement codeValue = 
    rangeValues.Elements().Single(x => (string)x.Attribute("code") == _rd.DisposalList[0].RetentionEvent); 

Если не может быть совпадением, или может быть больше, чем один, вы хотите исследовать SingleOrDefault(), First(), и FirstOrDefault() тоже.

+0

Мне нравится метод «Single()», и, как вы подозреваете, не хотите, чтобы «SingleOrDefault()» или любой другой предоставили.Тем не менее, я получаю исключение, сказанное «Последовательность не содержит соответствующего элемента», когда я это знаю. Ну, по крайней мере, я знаю, что значение представлено. Независимо от того, загружается ли XML и правильно разбирается, это совсем другое дело. –

+1

Понял. Необходимо использовать 'rangeValues.Root.Elements()'. –

1

Ваш .ToList() звонок правильный, но синтаксис запроса LINQ неверен.

Попробуйте это:

List<XElement> fullnames = (from fullName in rangeValues.Elements() 
          where fullName.Attribute("code") == _rd.DisposalList[0].RetentionEvent 
          select fullName).ToList(); 
+0

Это хорошо, но метод «Single()» работал лучше в моем случае. –

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