Ваша проблема в этом бите кода:
.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);
}