Извлеките все элементы, которые удовлетворяют условию, из XELEMENT var + LINQ to XML - PullRequest
1 голос
/ 02 июня 2011

У меня есть два XELEMENTS XR и XTemp.

МОЙ XR Содержит:

     <result xmlns="http://abc.com/test">
           <report>
            <unit unit_number="1" id="S1">
                 <classification>Subject</classification>
                 <claim_reported count="0" status="No claims reported" />
            </unit>
           <unit unit_number="2" id="S2">
                <classification>Subject</classification>
                <claim_reported count="0" status="No claims reported" />
           </unit>
        <unit unit_number="3" id="V1">
          <classification>Vehicle</classification>
          <claim_reported count="1" status="Claims reported" />
        </unit>
    ......
     </report>
</result>

Мой XTemp содержит:

 <result xmlns="http://abc.com/test">
   <report>
        <unit unit_number="1" id="S3">
             <classification>Subject</classification>
             <claim_reported count="1" status="Claims reported" />
        </unit>
       <unit unit_number="2" id="S4">
            <classification>Subject</classification>
            <claim_reported count="4" status="Claims reported" />
       </unit>
      <unit unit_number="3" id="V2">
         <classification>Vehicle</classification>
         <claim_reported count="0" status="No claims reported" />
      </unit>
      <unit unit_number="3" id="V3">
         <classification>Vehicle</classification>
         <claim_reported count="2" status="Claims reported" />
      </unit>
         ......
    </report>
 </result>

Попытка извлечь все элементы <unit> из XTemp на основе определенного условия и добавить их к XR.

Условие: получить все элементы <unit>, чей идентификатор начинается с "V".

Ниже код был лучшим, что я смог придумать.

Но я получаю Object reference not set to an instance Ошибка.

XR.Descendants(xmlns + "unit").LastOrDefault().AddAfterSelf(XTemp.Descendants(xmlns + "unit")
  .Where(x => x.Element(xmlns + "unit").Attribute("id").Value.ToUpper().Contains("V")));

Заранее спасибо

BB

1 Ответ

2 голосов
/ 02 июня 2011

Ваша проблема в этом бите кода:

.Where(x => x.Element(xmlns + "unit").Attribute("id")...

На этом этапе запроса вы уже запрашиваете unit элементов.unit не содержит вложенного unit, поэтому вы получаете NullReferenceException.

Измените его на: .Where(x => x.Attribute("id")...

Лично я считаю ваш запрос сложнымчитать.Во-первых, LastOrDefault означает, что вы потенциально ожидаете существование нулевого значения, но вы продвигаетесь вперед с остальной частью запроса, не обращаясь к нему.Во-вторых, вам не нужно искать последний элемент unit и AddAfterSelf.Вместо этого вы можете напрямую Add к элементу report, и элементы будут добавлены в конец:

var query = xtemp.Descendants(xmlns + "unit")
                 .Where(e => e.Attribute("id").Value.StartsWith("V", StringComparison.InvariantCultureIgnoreCase));

xr.Element(xmlns + "report").Add(query);

Кроме того, обратите внимание, как я проверил "V", игнорируя регистр.Это считается лучшей практикой, в отличие от использования ToUpper.


РЕДАКТИРОВАТЬ: на основе комментариев, вот решение для сортировки всех узлов unit при сохранениисуществующий порядок не unit узлов.Этот код учитывает, встречается ли узел до и после существующих узлов или нет других узлов вообще.

Некоторые предположения:

  • XR всегда имеет unit узлов
  • Идентификаторы следуют за существующей буквой, за которой следует числовой формат.
  • unit узлы хранятся вместе и не пересекаются между всеми другими типами узлов.

Первые двадопущения - это тривиальные проблемы для кода, если они неверны.

var query = xtemp.Descendants(xmlns + "unit")
                 .Where(e => e.Attribute("id").Value.StartsWith("V", StringComparison.InvariantCultureIgnoreCase));

var units = xr.Element(xmlns + "report").Elements(xmlns + "unit");
var beforeUnit = units.First().ElementsBeforeSelf().FirstOrDefault();
var afterUnit = units.Last().ElementsAfterSelf().FirstOrDefault();

// order based on ID starting letter, then integer value
var orderedUnits = units.Concat(query)
                        .OrderBy(e => e.Attribute("id").Value[0])
                        .ThenBy(e => int.Parse(e.Attribute("id").Value.Substring(1)))
                        .ToList();

// remove original unit nodes
units.Remove();

// add ordered units based on their original position
if (beforeUnit != null)
{
    beforeUnit.AddAfterSelf(orderedUnits);
}
else if (afterUnit != null)
{
    afterUnit.AddBeforeSelf(orderedUnits);
}
else
{
    xr.Element(xmlns + "report").Add(orderedUnits);
}
...