How do I manipulate an XML document one parent element at a time?

前端 未结 2 1819
暗喜
暗喜 2021-01-24 09:46

I am trying to take an XML file containing multiple orders from an online shopping cart, parse it and output the values of each order as its own text file (not XML) using C# and

相关标签:
2条回答
  • 2021-01-24 09:59

    You can make this super simple. Object oriented programming is the way to go.

    So say you create a class Order that takes an XElement. I'll write a couple lines for you.

    public class Order
    {
        XElement self;
        public Order(XElement order)
        {
            self = order;
        }
    
        public XElement Element { get { return self; } }
    
        public string OrderNumber 
        { 
            // if your xml looks like <Order OrderNumber="somenumber" />
            get { return (string)(self.Attribute("OrderNumber") ?? (object)"some default value/null"); } 
            // but if it looks like: <Order><OrderNumber>somenumber</OrderNumber></Order>
            // get { return (string)(self.Element("OrderNumber") ?? (object)"some default value/null"); }
        }
    }
    

    You'll have to fill in the rest of the Order's properties yourself. For each Order value, make a property like the OrderNumber I made above. Having properties for each Order value makes accessing the data super simple.

    So for your main code you'd have:

    XElement file = XElement.Load(@"C:\onlinesales\neworders.xml");
    Order[] orders = file.Elements("Order").Select(e => new Order(e)).ToArray();
    

    Now that you have all your orders as individual Order objects, read the data from the list of properties as you output to the file. There's no need now to store the values in StringBuilder's because the values are in the Order objects.

    foreach(Order order in orders)
    {
       // write order.OrderNumber  etc. / do whatever you want with the orders.
    }
    
    0 讨论(0)
  • 2021-01-24 10:24

    Chuck has a good approach. Sometimes, you don't want to retain the reference to the underlying xml data structure in the model object you are loading. In this case, I often use a pattern like this:

    public interface IXmlReadable
    {
        void Clear();
        void Read(XPathNavigator xmlNav);
    }
    
    public class ModelBase : IXmlReadable
    {
        public void Clear()
        {
            DoClear();
        }
    
        public void Read(XPathNavigator xmlNav)
        {
            DoRead(xmlNav);
        }
    
    
        protected virtual void DoClear()
        {
            throw new NotImplementedException();
        }
    
        protected virtual void DoRead(XPathNavigator xmlNav)
        {
            throw new NotImplementedException();
        }
    }
    

    Read can be overloaded to accept XmlDocument, XmlNode, XElement, etc.

    Now you can implement specific models.

    public sealed class Order : ModelBase
    {
        public Order() { }
    
        public string OrderNumber { get; private set; }
    
        protected override void DoClear()
        {
            OrderNumber = string.Empty;
        }
    
        protected override void DoRead(XPathNavigator xmlNav)
        {
            DoClear();
    
            XPathNavigator node;
    
            node = xmlNav.SelectSingleNode("OrderNumber");
    
            if (node != null)
                OrderNumber = node.InnerXml;
    
            // implement other properties here
        }
    
    }
    

    With the XPathDocument and XPathNavigator approach, you can then do something like this:

    XPathDocument xml = new XPathDocument(@"C:\onlinesales\neworders.xml");
    
    xmlNav = xml.CreateNavigator();
    
    XPathNodeIterator iterator = xmlNav.Select("Order");
    
    while (iterator.MoveNext())
    {
        Order order = new Order();
        order.Read(iterator.Current);
    
        // do something with the Order - add to list or process
    }
    
    0 讨论(0)
提交回复
热议问题