I am parsing an XML file in C#, how I can make sure the code is not breaking if XML does not have one of these fields I am parsing? I don't want to through an exception as well.
StringBuilder output = new StringBuilder();
var xDocument = XDocument.Load(filePath);
string xml = xDocument.ToString();
XDocument doc = XDocument.Parse(xml);
var col = doc.Root.Elements("LineItems")
.Elements("LineItem")
.Elements("OrderLine")
.Select(e => new
{
PurchaseOrderNumber = doc.Root.Element("Header").Element("OrderHeader").Element("Purchase").Value,
InternalOrderNumber = doc.Root.Element("Header").Element("OrderHeader").Element("InternalOrderNumber").Value,
VendorPartNumber = e.Element("VendorPartNumber").Value,
ItemStatus = e.Element("ItemStatus").Value,
Date = e.Element("ExpectedDate").Value
});
For example, I removed ExpectedDate from XML and this is breaking. what can I add to this code that is not breaking when XML fields do not exist?
I added this and it works: ate = e.Element("ExpectedDate")?.Value,
But now if ExpectedDate is not existed this would be 1/1/0001 12:00:00 AM - How I can have an empty string so this line won't break:
OrderLine orderline = new OrderLine() { ItemStatus = item.ItemStatus, VendorPartNumber = item.VendorPartNumber, Date = Convert.ToDateTime(item.Date) };
This is XML sample:
<Purchase>
<Header>
<OrderHeader>
<TradingId>OPIE</TradingId>
</OrderHeader>
</Header>
<LineItems>
<LineItem>
<OrderLine>
<UnitPrice>1073.25</UnitPrice>
<ExtendedLineAmount>1073.25</ExtendedLineAmount>
<ItemStatus>Backorder</ItemStatus>
<ExpectedDate>2022-05-25</ExpectedDate>
</OrderLine>
</LineItem>
<LineItem>
<OrderLine>
<UnitPrice>292.410000</UnitPrice>
<ExtendedLineAmount>584.82</ExtendedLineAmount>
<ItemStatus>Released</ItemStatus>
<ExpectedDate>2022-06-29</ExpectedDate>
</OrderLine>
</LineItem>
</LineItems>
CodePudding user response:
Please try the following solution.
I saved your XML as a "e:\temp\alma.xml" file. And intentionally commented out
<!--<ExpectedDate>2022-06-29</ExpectedDate>-->
A question mark is standard way in the .Net Framework way to handle missing values as nulls:
ExpectedDate = e.Element("ExpectedDate")?.Value
Commented out ?? "default value"
should match an expected data type.
XML
<?xml version="1.0"?>
<Purchase>
<Header>
<OrderHeader>
<TradingId>OPIE</TradingId>
</OrderHeader>
</Header>
<LineItems>
<LineItem>
<OrderLine>
<UnitPrice>1073.25</UnitPrice>
<ExtendedLineAmount>1073.25</ExtendedLineAmount>
<ItemStatus>Backorder</ItemStatus>
<ExpectedDate>2022-05-25</ExpectedDate>
</OrderLine>
</LineItem>
<LineItem>
<OrderLine>
<UnitPrice>292.410000</UnitPrice>
<ExtendedLineAmount>584.82</ExtendedLineAmount>
<ItemStatus>Released</ItemStatus>
<!--<ExpectedDate>2022-06-29</ExpectedDate>-->
</OrderLine>
</LineItem>
</LineItems>
</Purchase>
c#
void Main()
{
const string filePath = @"e:\temp\alma.xml";
XDocument doc = XDocument.Load(filePath);
var col = doc.Descendants("OrderLine")
.Select(e => new
{
UnitPrice = e.Element("UnitPrice").Value,
ExtendedLineAmount = e.Element("ExtendedLineAmount").Value,
ItemStatus = e.Element("ItemStatus").Value,
ExpectedDate = e.Element("ExpectedDate")?.Value // ?? "default Value"
});
Console.WriteLine(col);
}
Output
------------ -------------------- ------------ --------------
| UnitPrice | ExtendedLineAmount | ItemStatus | ExpectedDate |
------------ -------------------- ------------ --------------
| 1073.25 | 1073.25 | Backorder | 2022-05-25 |
| 292.410000 | 584.82 | Released | null |
------------ -------------------- ------------ --------------
CodePudding user response:
What works for me is to make an extension for XElement
that returns true if the element exists (and then supply a default value if it doesn't):
public static class Extensions
{
public static bool TryGetElement(
this XElement pxel,
string name,
out XElement xel)
{
xel = pxel.Element(name);
return xel != null;
}
}
Using it like this:
var doc = XDocument.Parse(source);
var col = doc.Root.Elements("LineItems")
.Elements("LineItem")
.Elements("OrderLine")
.Select(e => new
{
PurchaseOrderNumber = doc.Root.Element("Header").Element("OrderHeader").Element("Purchase").Value,
VendorPartNumber = e.Element("VendorPartNumber").Value,
ItemStatus = e.Element("ItemStatus").Value,
Date = e.TryGetElement("ExpectedDate", out XElement xel) ?
xel.Value :
String.Empty
});
foreach (var orderline in col)
{
Console.WriteLine(orderline.ToString());
}
TESTING
Where test source XML (made pathological by removing the 2nd ExpectedDate
) is:
const string source =
@"<Purchase>
<Header>
<OrderHeader>
<Purchase>12345</Purchase>
</OrderHeader>
</Header>
<LineItems>
<LineItem>
<OrderLine>
<VendorPartNumber>1</VendorPartNumber>
<UnitPrice>1073.25</UnitPrice>
<ExtendedLineAmount>1073.25</ExtendedLineAmount>
<ItemStatus>Backorder</ItemStatus>
<ExpectedDate>2022-05-25</ExpectedDate>
</OrderLine>
</LineItem>
<LineItem>
<OrderLine>
<VendorPartNumber>2</VendorPartNumber>
<UnitPrice>292.410000</UnitPrice>
<ExtendedLineAmount>584.82</ExtendedLineAmount>
<ItemStatus>Released</ItemStatus>
</OrderLine>
</LineItem>
</LineItems>
</Purchase>";