c# Retrieve multiple XML child nodes

1.1k views Asked by At

I've managed to link up a single XElement successfully into my program though I'm not having any luck with the other two I have in place, I've tried using;

IEnumerable query = from booking in doc.Descendants("Booking")

Though I've haven't had much luck placing the values into list box.

Here's the code for function:

    private void btnimport_Click(object sender, EventArgs e)
    {
        OpenFileDialog open = new OpenFileDialog();
        open.CheckFileExists = true;
        open.InitialDirectory = "@C:\\";
        open.Filter = "XML Files (*.xml)|*.xml|All Files(*.*)|*.*";
        open.Multiselect = false;

        if (open.ShowDialog() == DialogResult.OK)
        {
            try
            {
                XDocument doc = XDocument.Load(open.FileName);

                //Grabs the customer elements
                var query = from booking in doc.Descendants("Booking")
                select new
                {
                    //Customer Elements
                    CustomerId = booking.Element("CustomerId").Value,
                    Title = booking.Element("Title").Value,
                    Firstname = booking.Element("FirstName").Value,
                    Lastname = booking.Element("LastName").Value,
                    DateofBirth = booking.Element("DateofBirth").Value,
                    Email = booking.Element("Email").Value,
                    HouseNo = booking.Element("HouseNo").Value,
                    Street = booking.Element("Street").Value,
                    Postcode = booking.Element("Postcode").Value,
                    Town = booking.Element("Town").Value,
                    County = booking.Element("County").Value,
                    ContactNo = booking.Element("ContactNo").Value,

                    //Holiday Elements
                    HolidayId = booking.Element("HolidayId").Value,
                    HotelName = booking.Element("HotelName").Value,
                    Location = booking.Element("Location").Value,
                    BookFrom = booking.Element("BookFrom").Value,
                    BookTo = booking.Element("BookTo").Value,
                    CheckInTime = booking.Element("CheckInTime").Value,
                    CheckOutTime = booking.Element("CheckOutTime").Value,
                    NoOfRoomsBooked = booking.Element("NoOfRoomsBooked").Value,
                    RoomType = booking.Element("RoomType").Value,
                    RoomServices = booking.Element("RoomServices").Value,
                    Parking = booking.Element("Parking").Value,
                    Pet = booking.Element("Pet").Value,

                    //TravelInfo Elements
                    TravelInfoId = booking.Element("TravelInfoId").Value,
                    TravellingFrom = booking.Element("TravellingFrom").Value,
                    Destination = booking.Element("Destination").Value,
                    Fare = booking.Element("Fare").Value,
                    TravelInsurance = booking.Element("TravelInsurance").Value,
                    InFlightMeals = booking.Element("In-FlightMeals").Value,
                    LuggageAllowance = booking.Element("LuggageAllowance").Value,
                    ExtraLuggage = booking.Element("ExtraLuggage").Value,
                    CarHire = booking.Element("CarHire").Value,
                    ReturnTransfer = booking.Element("ReturnTransfer").Value,
                };

                //Inputs all of the values in bookings
                foreach (var booking in query)
                {
                    //Customer values
                    txtCustomerId.Text = txtCustomerId.Text + booking.CustomerId;
                    txttitle.Text = txttitle.Text + booking.Title;
                    txtfname.Text = txtfname.Text + booking.Firstname;
                    txtlname.Text = txtlname.Text + booking.Lastname;
                    txtdob.Text = txtdob.Text + booking.DateofBirth;
                    txtemail.Text = txtemail.Text + booking.Email;
                    txthouseno.Text = txthouseno.Text + booking.HouseNo;
                    txtstreet.Text = txtstreet.Text + booking.Street;
                    txtpostcode.Text = txtpostcode.Text + booking.Postcode;
                    txttown.Text = txttown.Text + booking.Town;
                    txtcounty.Text = txtcounty.Text + booking.County;
                    txtcontactno.Text = txtcontactno.Text + booking.ContactNo;

                    //Holiday Values
                    txtHolidayId.Text = txtHolidayId.Text + booking.HolidayId;
                    txthname.Text = txthname.Text + booking.HotelName;
                    txtl.Text = txtl.Text + booking.Location;
                    txtbf.Text = txtbf.Text + booking.BookFrom;
                    txtbt.Text = txtbt.Text + booking.BookTo;
                    txtcit.Text = txtcit.Text + booking.CheckInTime;
                    txtcot.Text = txtcot.Text + booking.CheckOutTime;
                    txtnorb.Text = txtnorb.Text + booking.NoOfRoomsBooked;
                    txtrt.Text = txtrt.Text + booking.RoomType;
                    txtrs.Text = txtrs.Text + booking.RoomServices;
                    txtpark.Text = txtpark.Text + booking.Parking;
                    txtpet.Text = txtpet.Text + booking.Pet;

                    //TravelInfo Values
                    txtTravelInfoId.Text = txtTravelInfoId.Text + booking.TravelInfoId;
                    txttf.Text = txttf.Text + booking.TravellingFrom;
                    txtd.Text = txtd.Text + booking.Destination;
                    txtf.Text = txtf.Text + booking.Fare;
                    txtti.Text = txtti.Text + booking.TravelInsurance;
                    txtifi.Text = txtifi.Text + booking.InFlightMeals;
                    txtla.Text = txtla.Text + booking.LuggageAllowance;
                    txtel.Text = txtel.Text + booking.ExtraLuggage;
                    txtch.Text = txtch.Text + booking.CarHire;
                    txtrtrans.Text = txtrtrans.Text + booking.ReturnTransfer;
                }

                MessageBox.Show("XML has been imported");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

If anyone knows where I've gone wrong or what I need to add / change please let me know :)

Many thanks, 10gez10

1

There are 1 answers

1
dbc On BEST ANSWER

You have several problems:

  1. Firstly, your data elements are not immediate children of the booking element, there are intermediate elements <Customer>, <Holiday> and <TravelInfo>. Thus you need to do something like

            var query = from booking in doc.Descendants("Booking")
                        let customer = booking.Element("Customer")
                        let holiday = booking.Element("Holiday")
                        let travelInfo = booking.Element("TravelInfo")
                        select new
                        {
                            //Customer Elements
                            CustomerId = customer.Element("CustomerId").Value,
                            Title = customer.Element("Title").Value,
                            HolidayId = holiday.Element("HolidayId").Value,
                            TravelInfoId = travelInfo.Element("TravelInfoId").Value,
                        }
    
  2. Secondly, several elements are misspelled:

    • CheckOutTime should be CheckoutTime
    • In-FlightMeals should be InFlightMeals.
    • CarHire should be CareHire (yes "CareHire" is what's in the XML.)

    Thus, when you do (e.g.) Element("In-FlightMeals").Value, Element() is returning null so you get a null reference exception and your code is aborted.

  3. Thirdly, the element BookTo is completely missing, so BookTo = holiday.Element("BookTo").Value generates a null reference exception.

More generally, I do not recommend this coding approach. If any of your XML elements are missing, your query will throw an exception because element.Element("name") will be null. What's worse, Visual Studio doesn't seem to report an accurate line number on which the null reference occurs, instead giving the line number of the select new statement. And (on my version at least), it's not possible to step into the constructor for an anonymous type either. This makes debugging well-nigh impossible.

Instead, skip the intermediate anonymous type and do things in a more direct, traditional manner:

            foreach (var booking in doc.Descendants("Booking"))
            {
                var customer = booking.Element("Customer");
                var holiday = booking.Element("Holiday");
                var travelInfo = booking.Element("TravelInfo");

                XElement element;

                if (customer != null)
                {
                    if ((element = customer.Element("CustomerId")) != null)
                        txtCustomerId.Text = txtCustomerId.Text + element.Value;
                }
                // And so on.
            }