Question

I solved the namespace problem but I still have error message. I think the problem is with getting informations into list

IEnumerable<XElement> InvoiceLines = from e in Document.Root
                                        .Element(P + "InvoiceLines")
                                        .Elements(P + "InvoiceLine")
                        select new XElement("InvoiceLine",
                    new XAttribute("LineNumber", e.Element(P + "ID").Value),
                    new XAttribute("ProductName", e.Element(P + "Item").Attribute(P + "Description").Value),
                    new XAttribute("UnitPriceTaxInclusive", e.Element(P + "UnitPriceTaxInclusive").Value),
                    new XAttribute("Quantity", e.Element(P + "InvoicedQuantity").Value),
                    new XAttribute("UnitCode", e.Element(P + "InvoicedQuantity").Attribute(P + "@unitCode").Value));  

then I try to save the document using this InvoiceLines, like this:

XDocument FinalDocument = new XDocument( 
            new XElement("Invoice",
            new XAttribute("BuyerName", BuyerName),
            new XAttribute("SellerName", SellerName),
            new XAttribute("IssueDate", IssueDate),
            new XAttribute("ID", InvoiceID),
            new XElement("InvoiceLines", InvoiceLines)
            ));
        FinalDocument.Save(name);
        FinalDocument.Save(Console.Out);

error tells me that the problem is int the line "select new XElement..." in InvoiceLines

Was it helpful?

Solution 2

That line of code has a lot of assumptions about the underlying data. For example, this:

e.Element(P + "Item").Attribute(P + "Description").Value

That segment of code assumes that:

  1. e is guaranteed to contain an element matching P + "Item"
  2. That element is guaranteed to contain an attribute matching P + "Description"

These assumptions are throughout that line. So if data is ever encountered which doesn't meet these assumptions, .Element() or .Attribute() might return null, in which case the next . (such as in .Value) would be trying to dereference a null value, resulting in that error.

To add some null value checking, you can either separate it into multiple lines of code or put it all in-line. The readability and maintainability of either approach is up to you. For example, with this segment:

new XAttribute("LineNumber", e.Element(P + "ID").Value)

You might add some error checking like this:

new XAttribute("LineNumber", 
    (e == null ? string.Empty : 
        (e.Element(P + "ID") == null ? string.Empty :
            e.Element(P + "ID").Value)))

I could see where that could be pretty unreadable. You can perhaps eliminate the first check, assuming that e itself will never be null. But your other segments are still going to have a handful of nested checks.

To break it apart, you'd have to loop over the values instead of using a single LINQ statement. A structure like this:

var InvoiceLines = new List<XElement>();
foreach (var e in Document.Root.Element(P + "InvoiceLines").Elements(P + "InvoiceLine"))
{
    // build an XElement object from e and add it to the list
}

This isn't 100% identical, since it eager-loads the entire set. So you might also separate the loop itself into another method which returns an IEnumerable<XElement> and use yield return to not have to eager-load the whole thing. It's up to you.

Come to think of it, your initial selector of data also makes assumptions:

Document.Root.Element(P + "InvoiceLines").Elements(P + "InvoiceLine")

You might want to add null checking there as well, just in case you ever receive data which doesn't match those predicates.

OTHER TIPS

Rather than using .Value, which can cause a NullReferenceException if no matching elements or attributes are found, I recommend a (string) cast, which will simply produce null if no valid value is found, and the null-coalescing operator ??:

IEnumerable<XElement> InvoiceLines = 
        from e in Document.Root
                          .Element(P + "InvoiceLines")
                          .Elements(P + "InvoiceLine")
        select new XElement("InvoiceLine",
                 new XAttribute("LineNumber", (string)e.Element(P + "ID") ?? ""),
                 new XAttribute("ProductName", (e.Element(P + "Item") != null) ? (string)e.Element(P + "Item").Attribute(P + "Description") ?? "" : ""),
                 new XAttribute("UnitPriceTaxInclusive", (string)e.Element(P + "UnitPriceTaxInclusive") ?? ""),
                 new XAttribute("Quantity", (string)e.Element(P + "InvoicedQuantity") ?? ""),
                 new XAttribute("UnitCode", (string)e.Element(P + "InvoicedQuantity").Attribute(P + "@unitCode") ?? ""));  

Probably some of your elements or attributes do not exist in the document. For example:

e.Element(P + "ID").Value

If there is no element P + "ID" the line above will throw a NullReferenceException as you are accessing the Value property of a null reference. You may need to do something like

e.Element(P + "ID") ?? 0

where 0 is the default value you want it to have. Or you can do this with a good old fashioned for loop and some if loops.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top