C# - 查询XML并填充多维对象

时间:2016-12-21 21:10:48

标签: c# xml

我需要能够查询xml文档,以便我可以使用与其年份和日期对应的数据填充对象。 XML会不时变化,如果没有报告该年/月的数据点的值,那么它就不会出现在标记中。我仍然想在那个月填充我的对象,但为它插入一个0。

例如,如果xml包含2015年的值和2016年月份3,4,5,6的月份,我将需要一个可以处理这种可变性及其多维度的对象。我需要像[[Year:2015, Months:[1,2,4]],[Year:2016, Months: [3,4,5,6]]]

这样的东西

我想我的问题实际上是两个部分。

1)存储数据变化如此之大的最佳方法是什么。采集?名单?关键值对?多维数组? (我从python和JavaScript转了很多,所以我的术语可能不对)

2)如何查询xml并填充这样的对象。

OBJECT

public class obj1 
{
    public string[] years { get; set; }
    public string[] months { get; set; }


}

XML

<PRODUCTION_SET>
   <ENTITY>
       <METADATA>
       .
       .
       </METADATA>
       <HEADER>
       .
       .
       </HEADER>
       <PRODUCTION>
           <YEAR NUMBER = "2015">
               <MONTH NUMBER = "1">
                   <DATA1></DATA1>
                   <DATA2></DATA2>
               </MONTH>
               <MONTH NUMBER = "2">
                   <DATA1></DATA1>
                   <DATA2></DATA2>
               </MONTH>
               .
               . 
               . 
           </YEAR>
           <YEAR NUMBER = "2016">
               <MONTH NUMBER = "1">
                   <DATA1></DATA1>
                   <DATA2></DATA2>
               </MONTH>
               <MONTH NUMBER = "2">
                   <DATA1></DATA1>
                   <DATA2></DATA2>
               </MONTH>
               .
               . 
               . 
           </YEAR>
        </PRODUCTION>
    <ENTITY>
</PRODUCTION_SET>  

QUERY

    public IEnumerable<obj1> queryProduction()
    {
         return this.doc.Root.Elements("PRODUCING_ENTITY").Select(pe => new obj1{
            foreach(var year in pe.Element("PRODUCTION").Elements("YEAR") .....?){
            // do stuff to assign months to current year in object.
            }

        }

    }

4 个答案:

答案 0 :(得分:1)

试试xml linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;


namespace ConsoleApplication33
{

    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            obj1.obj1s = doc.Descendants("YEAR").Select(x => new obj1
            {
                year = (int)x.Attribute("NUMBER"),
                month = (int)x.Element("MONTH").Attribute("NUMBER")
            }).ToList();

        }

    }
    public class obj1
    {
        public static List<obj1> obj1s = new List<obj1>();
        public int year { get; set; }
        public int month { get; set; }


    }


}

答案 1 :(得分:1)

您可以将整个事物存储为List,其中Object是用户定义的类型(类),它将具有两个属性,即Year和Months。 Year属性可以是int类型,而Months可以是List。所以基本上它将如下所示:

public class YearStats
{
    public int Year { get; set; }

    public IList<int> Months { get; set; }

    public YearStats()
    {
        Months = new List<int>();
    }
}

如果您需要存储数天的数据,那么您可以将Months的类型更改为IList。同样,这里的对象将是类,其定义与YearStats的定义相同。

您可以使用以下代码段加载数据。

XElement doc = XElement.Load("Test.xml");
        IEnumerable<XElement> yearList =
                                 from el in doc.Elements("YEAR")
                                select el;
        List<YearStat> yearData = new List<YearStat>();

        foreach (XElement yearEle in yearList)
        {
            YearStat year = new YearStat();

            year.Year = int.Parse((string)yearEle.Attribute("NUMBER"));

            var monthList = yearEle.Elements("Month");

            List<int> monthData = new List<int>();

            foreach(XElement monthEle in monthList)
            {
                monthData.Add(int.Parse((string)monthEle.Attribute("NUMBER")));
            }

            year.Months = monthData;

            yearData.Add(year);
        }

答案 2 :(得分:1)

如果您正在寻找灵活性和可伸缩性,我会为Month和Year对象创建特定的类。此外,.NET使XML序列化和反序列化更容易,因此不需要大量代码。如果您正在寻找性能,那么更简单的对象数据类型可能是更好的选择。

所以,我会创建这样的东西(这可能充满了语法错误,在记事本上做了,对不起):

[Serializable()]
public class Production
{
    public Year[] Years {get;set;}
}

[Serializable()]
public class Year
{
    public int YearNumber {get;set;}

    public int SomeData1 {get;set;}

    public int SomeData2 {get;set;}

    public Month[] Months {get;set;}
}

[Serializable()]
public class Month
{
    public int MonthNumber {get;set;}

    public int SomeData1 {get;set;}

    public int SomeData2 {get;set}

    public Month()
    {
        // Default value for data - Although integer variables already default to 0,
        // so there is no need to do this explicitly
        this.SomeData1 = 0
        this.SomeData2 = 0
    }
}

两个评论:

1)我建议您将月份和年份数字作为数字类型处理,以便能够更轻松地从代码中使用它。

2)我使用[Serializable()]属性将我的类标记为可序列化,因此您应该使用XmlSerializer对象来实现对象的查询和填充。反序列化看起来像这样:

XmlSerializer serializer = new XmlSerializer(typeof(Production), new XmlRootAttribute ("Production"));
FileStream fs = new FileStream(filename, FileMode.Open);
Production prod = (Production) serializer.Deserialize(fs);

一般来看XML serialization with .NET,您可以根据需要轻松或复杂地使用它,它是.NET框架提供的一个非常强大的工具。

答案 3 :(得分:1)

似乎我们很多人都在考虑类似的解决方案......

using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace QueryingXML_41271961
{
    class Program
    {
        static void Main(string[] args)
        {
            string thePath = @"M:\StackOverflowQuestionsAndAnswers\QueryingXML_41271961\QueryingXML_41271961\sample.xml";

            XDocument theXMLDoc = XDocument.Load(thePath);
            List<XElement> theYears = theXMLDoc.Descendants("PRODUCTION").Elements("YEAR").ToList();
            List<InfoHolder> mylist = new List<InfoHolder>();

            foreach (XElement yearInXML in theYears)
            {
                InfoHolder ih = new InfoHolder();
                ih.years = yearInXML.Attribute("NUMBER").Value;

                foreach (XElement monthsInYear in yearInXML.Elements("MONTH"))
                {
                    if (ih.months == null)
                    {
                        ih.months = monthsInYear.Attribute("NUMBER").Value;
                    }
                    else
                    {
                        ih.months += "," + monthsInYear.Attribute("NUMBER").Value;
                    }
                }
                mylist.Add(ih);
            }
            System.Diagnostics.Debugger.Break();
        }
    }

    public class InfoHolder
    {
        public string years { get; set; }
        public string months { get; set; }
    }
}