2

次の構造の 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>

RecommendedRetailPriceand/orはすべてのPriceAmountに存在しない場合がありますItemItemsそれでも、すべてをそれぞれので並べ替えたいと思いますRecommendedRetailPrices。そのため、うまく機能する次のコードになりましたが、ネストされた if ステートメントのすべての段階で null をチェックする必要があります。

//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 レベル下のオプションの子ノードでソートすることを検討してください。

どんな助けでも感謝します。

4

3 に答える 3

0

ゼロまたは 1 つの要素が存在できる場合Elements()Element()FirstOrDefault. 次に、明示的なキャスト演算子を使用しXElementて値を取得します。

このようなもの

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();
于 2013-06-11T09:34:44.523 に答える
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);
于 2013-06-11T11:11:32.917 に答える
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();

このメソッドは、価格を取得する必要がある他の場所でも再利用できると確信しているため、後で便利なコードになります。

必要に応じて、三項演算子を使用してメソッドを短くすることもできます

private static double GetPrice(XElement retail, string priceElement)
{
    return (retail != null && retail.Element(priceElement) != null) ?
            Convert.ToDouble(retail.Element(priceElement).Value) : 0.0;
}
于 2013-06-11T09:42:53.577 に答える