我正在处理以下结构的XML文件:
<vco:ItemDetail>
<cac:Item>
...
<cac:RecommendedRetailPrice>
<cbc:PriceAmount amountCurrencyID="EUR">4.95</cbc:PriceAmount>
<cbc:BaseQuantity quantityUnitCode="EA">1</cbc:BaseQuantity>
</cac:RecommendedRetailPrice>
...
</cac:Item>
...
</vco:ItemDetail>
每个RecommendedRetailPrice
可能不存在PriceAmount
和/或Item
。
不过,我想按各自Items
对所有RecommendedRetailPrices
进行排序。
所以我最终得到了以下代码可以正常工作,但必须在一些可怕的嵌套if语句的每个阶段检查空值:
//full_xml is of type XDocument
var most_expensive = full_xml
.Element("ItemDetails")
.Elements(vco + "ItemDetail")
.Elements(cac + "Item")
.OrderBy(el =>
{
var rrp = el.Element(cac + "RecommendedRetailPrice");
string val = null;
if(rrp != null) {
var pa = rrp.Element(cbc + "PriceAmount");
if(pa != null) {
val = rrp.Value;
}
}
if (val != null) {
return Convert.ToDouble(val);
}
else {
return 0.0;
}
}
)
.Last();
在这种情况下,这可能不是那么糟糕,但我想有必要采用更惯用的方式来做到这一点。考虑通过8级向下的可选子节点对事物进行排序。
任何帮助表示感谢。
答案 0 :(得分:0)
如果可以存在零个或一个元素,那么我将使用Elements()
而不是Element()
,然后选择FirstOrDefault
。然后使用XElement
的{{3}}来获取您的价值。
像这样的东西
var most_expensive = full_xml
.Element("ItemDetails")
.Elements(vco + "ItemDetail")
.Elements(cac + "Item")
.OrderBy(el =>
el.Elements(cac + "RecommendedRetailPrice")
.Select(rrp => (double?) rrp.Elements(cbc + "PriceAmount"))
.FirstOrDefault() ?? 0.0
).Last();
答案 1 :(得分:0)
创建一个执行操作的方法(我知道我知道我们都想制作漂亮的Lambda表达式而不是制作新方法)
private static double GetPrice(XElement retail, string priceElement)
{
// short circuting will stop as soon as the statement is false
if (retail != null && retail.Element(priceElement) != null)
{
return Convert.ToDouble(retail.Element(priceElement).Value);
}
return 0.0;
}
你的linq现在看起来很棒......
var most_expensive = full_xml
.Element("ItemDetails")
.Elements(vco + "ItemDetail")
.Elements(cac + "Item")
.OrderBy(el => GetPrice(el.Element(cac + "RecommendedRetailPrice"), cbc + "PriceAmount"))
.Last();
我确信这个方法可以在其他需要付出代价的地方重复使用,以便以后可以使用这段代码。
如果需要,也可以使用Ternary运算符缩短方法
private static double GetPrice(XElement retail, string priceElement)
{
return (retail != null && retail.Element(priceElement) != null) ?
Convert.ToDouble(retail.Element(priceElement).Value) : 0.0;
}
答案 2 :(得分:0)
没有命名空间:
var doc = XDocument.Parse(@"
<ItemDetails>
<ItemDetail>
<Item>
<RecommendedRetailPrice>
<PriceAmount>4.95</PriceAmount>
</RecommendedRetailPrice>
</Item>
</ItemDetail>
</ItemDetails>
");
var result = doc
.Element("ItemDetails")
.Elements("ItemDetail")
.Elements("Item")
.OrderBy(item =>
item.Elements("RecommendedRetailPrice")
.Elements("PriceAmount")
.Select(pa => Convert.ToDouble(pa.Value,
CultureInfo.InvariantCulture))
.FirstOrDefault())
.Last();
Console.WriteLine(result);