XML only read the first element

Hi All,

I have an issue where I cannot figure out how to only get the first element where there are more with the same name. I need to get the customer Order number, Email, First and Lastname and product ordered.

The XML file has one or more and I only need the first item the rest needs to be ignored for that order number.

With my script I get 5 items in my list, Order Number, Mail, First and Last Name, but I get 8 items in productOrdered.

Now I need to get the first for that is this possible?

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;
using UnityEngine;
using Xml2CSharp;

public class PreOrderManager : MonoBehaviour
{
    public TextAsset xml;
    public List<int> orderNumber = new List<int>();
    public List<string> mailAddress = new List<string>();
    public List<string> customerFirstName = new List<string>();
    public List<string> customerLastName = new List<string>();
    public List<string> productOrdered = new List<string>();

    void Start()
    {
        var xd = XDocument.Load(@"C:\tmp\Data2.xml");
  
        // Order Numbers
        var orderNumbers = xd.Root
            .Elements("order")
            .Elements("orderno")
            .Select(x => x.Value);

        foreach (var x in orderNumbers)
        {
            orderNumber.Add(int.Parse(x));
        }

        // Email Adresses
        var email = xd.Root
            .Elements("order")
            .Elements("mailaddress")
            .Select(y => y.Value);

        foreach (var y in email)
        {
            mailAddress.Add(y);
        }
             
        // First Name
        var customerNameOne = xd.Root
            .Elements("order")
            .Elements("firstname")
            .Select(z => z.Value);

        foreach (var z in customerNameOne)
        {
            customerFirstName.Add(z);
        }
            
        // Last Name
        var customerNameTwo = xd.Root
            .Elements("order")
            .Elements("name")
            .Select(n => n.Value);

        foreach (var n in customerNameTwo)
        {
            customerLastName.Add(n);
        }

       
// Ordered Products
        var customerItems = xd.Root
            .Elements("order")
            .Elements("rowprodname")
            .Select(p => p.Value);

        foreach (var p in customerItems)
        {
            //if (p.Contains("Preorder"))
                productOrdered.Add(p);
        }

    }
}
<orders>
    <order>
        <orderno><![CDATA[2020001]]></orderno>
        <firstname><![CDATA[Roy]]></firstname>
        <name><![CDATA[Jansen]]></name>
        <mailaddress><![CDATA[roy@jansen.commm]]></mailaddress>
        <orderrow>
            <rowprodname><![CDATA[PreOrder 1x Product One]]></rowprodname>
        </orderrow>
    </order>
        <order>
        <orderno><![CDATA[2020002]]></orderno>
        <firstname><![CDATA[Dennis]]></firstname>
        <name><![CDATA[Hope]]></name>
        <mailaddress><![CDATA[dennis@gmail.com]]></mailaddress>
        <orderrow>
            <rowprodname><![CDATA[PreOrder 1x Product Two]]></rowprodname>
        </orderrow>
        <orderrow>
            <rowprodname><![CDATA[Do Not Get this value! Two]]></rowprodname>
        </orderrow>
    </order>
        <order>
        <orderno><![CDATA[2020003]]></orderno>
        <firstname><![CDATA[Jeroen]]></firstname>
        <name><![CDATA[Vliet]]></name>
        <mailaddress><![CDATA[jeroen@gmail.commm]]></mailaddress>
        <orderrow>
            <rowprodname><![CDATA[PreOrder 1x Product Three]]></rowprodname>
        </orderrow>
        <orderrow>
            <rowprodname><![CDATA[Do Not Get this value! Three]]></rowprodname>
        </orderrow>
    </order>
        <order>
        <orderno><![CDATA[2020004]]></orderno>
        <firstname><![CDATA[Ilse]]></firstname>
        <name><![CDATA[Vis]]></name>
        <mailaddress><![CDATA[ilse@gmail.commm]]></mailaddress>
        <orderrow>
            <rowprodname><![CDATA[PreOrder 1x Product Four]]></rowprodname>
        </orderrow>
    </order>
        <order>
        <orderno><![CDATA[2020005]]></orderno>
        <firstname><![CDATA[Eef]]></firstname>
        <name><![CDATA[Reef]]></name>
        <mailaddress><![CDATA[eef@gmail.commm]]></mailaddress>
        <orderrow>
            <rowprodname><![CDATA[PreOrder 1x Product Five]]></rowprodname>
        </orderrow>
        <orderrow>
            <rowprodname><![CDATA[Do Not Get this value! Five]]></rowprodname>
        </orderrow>
    </order>
</orders>

I think you can do it like this (not tested):

        var customerItem = xd.Root
            .Elements("order")
            .Descendants()
            .Elements("rowprodname")
            .FirstOrDefault();

      productOrdered.Add(customerItem?.Value ?? null);

However, I would recommend creating a dedicated Order-class which contains all the entries of an order and storing them into one single List<Order>. This will make your life working with that data much easier.

1 Like

Yes, I get only the first now great.

But I need to get the first for every . I don’t know much about XML but can I check by and then get that single item for that order?

thanks for your help :slight_smile:

make dedicated order elements… it will be easier to handle:

public class PreOrderManager : MonoBehaviour
{
    public List<Order> orders = new List<Order>();

    void Start()
    {
        var xd = XDocument.Load(@"C:\tmp\Data2.xml");

        foreach(var orderElement in xd.Root.Elements())
        {
            Order order = Order.ParseXml(orderElement);
            orders.Add(order);
        }
    }
}

[Serializable]
public class Order
{
    public int Number { get; private set; }
    public string MailAddress { get; private set; }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }

    public List<string> OrderedProducts { get; private set; }
    public string FirstOrderedProduct => OrderedProducts?.FirstOrDefault();

    public static Order ParseXml(XElement xmlOrderNode)
    {
        var order = new Order();
      
        // parse the order no.
        int num = -1;
        int.TryParse(xmlOrderNode.Element("orderno")?.Value, out num);
      
        // set basic properties
        order.Number = num;
        order.MailAddress = xmlOrderNode.Element("mailaddress")?.Value;
        order.FirstName = xmlOrderNode.Element("firstname")?.Value;
        order.LastName = xmlOrderNode.Element("name")?.Value;

        // create product orders and add xml values
        order.OrderedProducts = new List<string>();

        foreach(var row in xmlOrderNode.Descendants("orderrow"))
        {
            foreach(var prod in row.Descendants("rowprodname"))
            {
                order.OrderedProducts.Add(prod.Value);
            }
        }

        return order;
    }
}

The code above should convert the xml file into a list of orders containing every value of the xml file.
This is not tested.

Note that you will not be able to see the Properties inside the order in Unity’s inspector. You can remove the { get; private set; } part from them to convert them to member variables and see them in the inspector.

1 Like

Thanks a lot for your time! Got it working. :slight_smile: