質問

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

役に立ちましたか?

解決 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.

他のヒント

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top