从XELEMENT var + LINQ中提取符合条件的所有元素到XML
我有两个XELEMENTS XR
和XTemp
。从XELEMENT var + LINQ中提取符合条件的所有元素到XML
MY 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>
试图基于某种condtion从XTemp
提取所有<unit>
元素,并将它们添加到XR
。
条件是:获取其ID为“V”开头的所有<unit>
元素。
下面的代码是我能够想到的最好的代码。
但是,我得到了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
你的问题是这段代码:
.Where(x => x.Element(xmlns + "unit").Attribute("id")...
在查询这一点你已经在查询元素unit
。 A 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);
}
@Ahmad非常感谢。感谢您提出宝贵的建议。我希望所有的ID以“S”开头的元素出现,然后是我的XR中以“V”开头的元素。我怎样才能做到这一点? – BumbleBee 2011-06-02 18:21:59
除了
@BumbleBee排序是可能的,但你的第二个评论使问题变得复杂一点。如果其他元素可以在'
您是否介意包含您正在使用的XML片段以及导致该行的其他代码?不要让我们更难了解你的情况,给我们提供我们需要的信息,不要指望我们必须解决它。 – 2011-06-02 01:21:45