0

I have a class called PurchaseOrderItem

public class PurchaseOrderItem { public Int64 PONumber { get; set; } public string Description { get; set; } public string UM { get; set; } public int QTY { get; set; } public double Cost { get; set; } } 

I'm trying to to read data from XML file by iterating sections from XML and populate data into PurchaseOrderItems which is List. But when i try the code below i'm getting an error message of "Object reference not set to an instance of an object." I'm pretty sure i'm missing something because my poor OOP knowledge. Would someone kindly explain to me what causes this problem?

 PurchaseOrderItems = (from purchaseOrderItem in PO.Descendants("PurchaseOrder").Elements("ProductLineItem") select new PurchaseOrderItem { PONumber = PONumber, Description = purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("comments").Value.Trim(), QTY = Convert.ToInt16(purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("OrderQuantity").Element("requestedQuantity").Element("ProductQuantity").Value.Trim()), UM = purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("GlobalProductUnitOfMeasureCode").Value.Trim(), Cost = Convert.ToDouble(purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("requestedUnitPrice").Element("FinancialAmount").Element("MonetaryAmount").Value.Trim()), }).ToList<PurchaseOrderItem>(); 

1 Answer 1

2

purchaseOrderItem is already a ProductLineItem element by the time you reach your select clause - so currently you're trying to find a PurchaseOrder element within ProductLineItem, which will return null if it isn't found. I suspect you just want:

PurchaseOrderItems = (from purchaseOrderItem in PO.Descendants("PurchaseOrder").Elements("ProductLineItem") select new PurchaseOrderItem { PONumber = PONumber, Description = purchaseOrderItem.Element("comments").Value.Trim(), QTY = (short) purchaseOrderItem.Element("OrderQuantity") .Element("requestedQuantity") .Element("ProductQuantity"), UM = purchaseOrderItem.Element("GlobalProductUnitOfMeasureCode") .Value.Trim(), Cost = (double) purchaseOrderItem.Element("requestedUnitPrice") .Element("FinancialAmount") .Element("MonetaryAmount") }).ToList(); 

Notes:

  • Using the explicit conversions from XElement to short, double etc is a more appropriate way of performing conversions for XML data
  • It looks like you're using double for currency values: don't do that - use decimal instead

Also, you may want to consider creating a static method in PurchaseOrderItem which knows how to deserialize one from an XElement; I often find that a pattern of:

class Foo { static Foo FromXElement(XElement element) { ... } XElement ToXElement() { ... } } 

works well.

Sign up to request clarification or add additional context in comments.

4 Comments

May i ask why i should use decimal for currency values instead of double?
@SiHyungLee: Do you like losing data? ;) Decimal is designed for values which are precisely representable in decimal - which financial values usually are. Double uses a binary representation instead, so something like "0.1" can't be represented exactly. See csharpindepth.com/Articles/General/FloatingPoint.aspx and csharpindepth.com/Articles/General/Decimal.aspx for more details.
I though double also could handle decimal point and had a bigger capacity than decimal. My mistake. Thank you.
@SiHyungLee: It depends what you mean by "handle" - it definitely has a bigger range, but its exact nature is very different to decimal.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.