Linq to Xml - 空元素

发布于 2024-12-19 11:25:12 字数 737 浏览 0 评论 0原文

我正在使用 Linq 解析 xml 文档,但我遇到了一个不确定如何处理处理的场景。我发现/尝试过的一切似乎都不起作用。正如您在下面看到的(非常简单的场景),其中 OrderAmount 为空。这是一个小数字段。当我尝试在 LINQ 中处理这个问题时,它一直在轰炸。我尝试过使用 deimcal?、使用 null 检查等,但似乎没有任何效果(很可能是用户错误)。任何建议将不胜感激。

当元素是非字符串(如小数)且为空时,如何处理?

XML:

<Orders>
  <Order>
    <OrderNumber>12345</OrderNumber>
    <OrderAmount/>
  </Order>
</Orders>

LINQ:

List<Order> myOrders = from orders in xdoc.Descendants("Order")
                       select new Order{
                       OrderNumber = (int)orders.Element("OrderNumber"),
                       OrderAmount = (decimal?)orders.Element("OrderAmount"),


}.ToList<Order>();

I am parsing an xml doc with Linq, but i am running into a scenario where I am not sure how to handle the processing. Everything I have found / tried doesn't seem to work. As you can see below (very simple scenario) where the OrderAmount is empty. This is a decimal field. When I try to handle this in LINQ it keeps bombing. I have tried using deimcal?, using the null check, etc nothing seems to be working (Most likely user error). Any suggestions would be appreciated.

How do you handle when an element is a non string (like a decimal) and is empty ?

Xml:

<Orders>
  <Order>
    <OrderNumber>12345</OrderNumber>
    <OrderAmount/>
  </Order>
</Orders>

LINQ:

List<Order> myOrders = from orders in xdoc.Descendants("Order")
                       select new Order{
                       OrderNumber = (int)orders.Element("OrderNumber"),
                       OrderAmount = (decimal?)orders.Element("OrderAmount"),


}.ToList<Order>();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

放赐 2024-12-26 11:25:12

仅当元素实际上为 null 时,将 XElement 转换为 decimal? 才会返回 null

我认为最具可读性的解决方案是这样的:

elem.IsEmpty ? null : (decimal?)elem

如果您经常使用它,您可能希望将其放入扩展方法中。或者只需在 LINQ 查询中使用 let 即可不重复选择元素的代码。

from orders in xdoc.Descendants("Order")
let amountElem = orders.Element("OrderAmount")
select new Order
{
    OrderNumber = (int)orders.Element("OrderNumber"),
    OrderAmount = amountElem.IsEmpty ? null : (decimal?)amountElem
}

如果您可以更改 XML,另一种选择是简单地省略表示 null 的元素。它应该可以很好地与您已有的代码配合使用。

编辑:扩展方法看起来像这样:

static class XElementExtensions
{
    public static decimal? ToNullableDecimal(this XElement elem)
    {
        return elem.IsEmpty ? null : (decimal?)elem;
    }
}

并且您将像这样使用它:

OrderAmount = orders.Element("OrderAmount").ToNullableDecimal()

The cast of XElement to decimal? returns null only when the element is actually null.

I think the most readable solution is something like this:

elem.IsEmpty ? null : (decimal?)elem

You might want to put this into an extension method, if you use it often. Or just use let in your LINQ query to not repeat the code that selects the element.

from orders in xdoc.Descendants("Order")
let amountElem = orders.Element("OrderAmount")
select new Order
{
    OrderNumber = (int)orders.Element("OrderNumber"),
    OrderAmount = amountElem.IsEmpty ? null : (decimal?)amountElem
}

Another option, if you can change the XML, is simply omitting the element to represent null. It should work well with the code you already have.

EDIT: The extension method would look something like this:

static class XElementExtensions
{
    public static decimal? ToNullableDecimal(this XElement elem)
    {
        return elem.IsEmpty ? null : (decimal?)elem;
    }
}

And you would use it like this:

OrderAmount = orders.Element("OrderAmount").ToNullableDecimal()
花想c 2024-12-26 11:25:12

Per svick 的评论怎么样

OrderAmount = String.IsNullOrEmpty(orders.Element("OrderAmount").Value) ? 
                  default(decimal?) : Decimal.Parse(orders.Element("OrderAmount").Value),

,这可能更安全

OrderAmount = String.IsNullOrEmpty(orders.Element("OrderAmount").Value) ? 
                  default(decimal?) : (decimal)orders.Element("OrderAmount"),

How about

OrderAmount = String.IsNullOrEmpty(orders.Element("OrderAmount").Value) ? 
                  default(decimal?) : Decimal.Parse(orders.Element("OrderAmount").Value),

Per svick's comment, this might be safer

OrderAmount = String.IsNullOrEmpty(orders.Element("OrderAmount").Value) ? 
                  default(decimal?) : (decimal)orders.Element("OrderAmount"),
久随 2024-12-26 11:25:12

您如何在 Order 类中声明 OrderAmount?尝试声明

public decimal? OrderAmount { get; set; }

How have you declared OrderAmount in your Order class? Try declaring

public decimal? OrderAmount { get; set; }
岁月无声 2024-12-26 11:25:12

我认为您想要元素的值而不是元素本身。

编辑:如果您真的决定保留演员阵容,这里有一个通过的单元测试,您可以使用它来获得可能更令人赏心悦目的格式:(

    private XDocument BuildDocument()
    {
        var myAmount = new XElement("OrderNumber", 12345);
        var myNumber = new XElement("OrderAmount");
        var myOrder = new XElement("Order", myAmount, myNumber);
        var myOrders = new XElement("Orders", myOrder);
        return new XDocument(myOrders);
    }

    private class Order
    {
        public int OrderNumber { get; set; }
        public decimal? OrderAmount { get; set; }
    }

    [TestMethod]
    public void TestMethod()
    {
        var myDoc = BuildDocument();
        List<Order> myOrders = (from orders in myDoc.Descendants("Order")
                               select new Order
                               {
                                   OrderNumber = (int)orders.Element("OrderNumber"),
                                   OrderAmount = GetAmount(orders.Element("OrderAmount"))
                               }).ToList<Order>();
    }

    private static decimal? GetAmount(XElement e)
    {
        if (e == null || string.IsNullOrEmpty(e.Value))
        {
            return 0.0M;
        }
        return (decimal?)e;
    }

您仍然需要添加代码来处理这种情况其中 OrderAmount 的值类似于“Asdf”)

I think you want the element's value rather than the element itself.

Edit: If you're really set on keeping the cast, here is a passing unit test that you can work with to get in a format perhaps more pleasing to the eye:

    private XDocument BuildDocument()
    {
        var myAmount = new XElement("OrderNumber", 12345);
        var myNumber = new XElement("OrderAmount");
        var myOrder = new XElement("Order", myAmount, myNumber);
        var myOrders = new XElement("Orders", myOrder);
        return new XDocument(myOrders);
    }

    private class Order
    {
        public int OrderNumber { get; set; }
        public decimal? OrderAmount { get; set; }
    }

    [TestMethod]
    public void TestMethod()
    {
        var myDoc = BuildDocument();
        List<Order> myOrders = (from orders in myDoc.Descendants("Order")
                               select new Order
                               {
                                   OrderNumber = (int)orders.Element("OrderNumber"),
                                   OrderAmount = GetAmount(orders.Element("OrderAmount"))
                               }).ToList<Order>();
    }

    private static decimal? GetAmount(XElement e)
    {
        if (e == null || string.IsNullOrEmpty(e.Value))
        {
            return 0.0M;
        }
        return (decimal?)e;
    }

(You'll still have to add code for dealing with the case where the value of OrderAmount is something like "Asdf")

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文