Is Linq-XML always so messy?

2019-04-27 08:36发布

问题:

var subset = from item in document.Descendants("Id")
             where item.Value == itemId.ToString()
             select new PurchaseItem() {
                 Id = int.Parse(item.Parent.Element("Id").Value),
                 Name = item.Parent.Element("Name").Value,
                 Description = item.Parent.Element("Description").Value,
                 Price = int.Parse(item.Parent.Element("Price").Value)
             };

The structure of the XML is as follows:

<Items>
    <Item>
        <Id></Id>
        <Name></Name>
        <Description></Description>
        <Price></Price>
    </Item>
</Items>

Id, and price are both integer values. Name and description are strings.

I've found Linq to XML great for what I've used it for, this is just a snippet. But, on the other hand I get the feeling it should or could be cleaner. The casting seems the most obvious issue in this snippet.

Any advice?

回答1:

Actually it would be better IMO to cast than to call int.Parse. Here's how I would write your query:

string id = itemId.ToString(); // We don't need to convert it each time!

var subset = from item in document.Descendants("Id")
             where item.Value == id
             let parent = item.Parent
             select new PurchaseItem
             {
                 Id = (int) parent.Element("Id"),
                 Name = (string) parent.Element("Name"),
                 Description = (string) parent.Element("Description"),
                 Price = (int) parent.Element("Price")
             };


回答2:

I assume that you have an "Items" node as well?

You could do something like this, assuming that you are loading the document using XElement.Load()

var subset = from item in document.Elements("Item")
             where item.Element("Id").Value == itemId.ToString()
             select new PurchaseItem() {
                 Id = int.Parse(item.Element("Id").Value),
                 Name = item.Element("Name").Value,
                 Description = item.Element("Description").Value,
                 Price = int.Parse(item.Element("Price").Value)
             };

Not a lot better, but much easier to read!



回答3:

In your example you can tidy up a little bit by finding the <Item/> element rather than the <Id/> to avoid getting the Parent each time:

var subset = from item in document.Descendants("Item")
             where item.Element("Id").Value == itemId.ToString()
             select new PurchaseItem()
                        {
                            Id = int.Parse(item.Element("Id").Value),
                            Name = item.Element("Name").Value,
                            Description = item.Element("Description").Value,
                            Price = int.Parse(item.Element("Price").Value)
                        };


回答4:

Consider writing a new constructor for PurchaseItem that takes the XML element, so you can write:

select new PurchaseItem(item.Parent);