【问题标题】:Read XML file Attributes and Elements using C#使用 C# 读取 XML 文件属性和元素
【发布时间】:2020-07-30 11:11:57
【问题描述】:

我的 XML 文件如下所示:

<device name="dev. 1" nodes="16" scenarios="20">
  <package>Pack. 1</package>
  <info>info...</info>
  <picture>pic</picture>
  <nodes>
    <node no="1" name="OUT_1" type="source"/>
    <node no="2" name="OUT_2" type="source"/>
    <node no="3" name="OUT_3" type="source"/>
    <node no="4" name="OUT_4" type="source"/>
  </nodes>
  <scenario name="scenario 1">
    <zth m_node="1" d_node="1" model="table" points="190">
      <data time="1" value="0.1"/>
      <data time="2" value="2"/>
      <data time="2" value="4"/>
    </zth>
    <zth m_node="1" d_node="2" model="table" points="190">
      <data time="1" value="0.3"/>
      <data time="2" value="4"/>
    </zth>
  </scenario>
  <scenario name="scenario 2">
    <zth m_node="1" d_node="1" model="table" points="190">
      <data time="2" value="2"/>
      <data time="1" value="0.3"/>
      <data time="2" value="4"/>
    </zth>
    <zth m_node="1" d_node="2" model="table" points="190">
      <data time="1" value="0.3"/>
      <data time="2" value="4"/>
    </zth>
  </scenario>
</device>

我需要读取的数据是: Element 场景中的属性名称在&lt;data&gt; 中,我需要将数据中的时间和值获取到数组中,但前提是d_node="2"&lt;zth&gt; 中。

这是我尝试过的:

    public class Scenario {
        public string name { get; set; }
        public List<string> ZthList { get; set; }
    }

    public class Zth {
        public string m_node { get; set; }
        public string d_node { get; set; }
        public string time { get; set; }
        public string value { get; set; }
    }
    public class XMLReader
    {

        public void xmlReader()
        {

            string currentDir = Environment.CurrentDirectory;
            //getting the directory
            DirectoryInfo directory = new DirectoryInfo(
            Path.GetFullPath(Path.Combine(currentDir, @"..\..\" + @"utils\XML\XMLFile1.xml")));

            XDocument doc = XDocument.Load(Path.Combine(currentDir, @"..\..\" + @"utils\XML\XMLFile1.xml"));
            var scenarios = (from s in doc.Root.Elements("scenario")
                             select new Scenario{
                                 name = (string)s.Attribute("name"), 
                                 ZthList = s.Elements("zth")
                                            .Select(r => new Zth
                                            {
                                                m_node = (string)r.Attribute("m_node"),
                                                d_node = (string)r.Attribute("d_node"),
                                                time = (string)r.Element("data").Attribute("time"),
                                                value = (string)r.Element("data").Attribute("value"),
                                            }).ToList()
                             }).ToList();
            var zth_d_node = scenarios.Where(x => x.ZthList.Any(r => r.d_node == "1")).ToList();
            var s_names = scenarios.Where(x => x.Element("").Value.Equals("name")).toList();

            Console.WriteLine("List: ");
            Console.WriteLine(String.Join(", ", scenarios));
        }
    }

我收到错误:Severity Code Description Project File Line Suppression State Error CS0029 Cannot implicitly convert type 'System.Collections.Generic.List&lt;project1.utils.Zth&gt;' to 'System.Collections.Generic.List&lt;string&gt;'

timevalue 中的数据也是 double 类型,我将其更改为字符串,因为我遇到了类似的错误,但它仍然无法正常工作

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    您需要改进模型以适应 xml 数据的结构。见:

    public class Scenario {
        public string name { get; set; }
        public List<Zth> ZthList { get; set; }
    }
    
    public class Zth {
        public string m_node { get; set; }
        public string d_node { get; set; }
        public List<Data> data { get; set; }
    }
    
    public class Data {
        public string t { get; set; }
        public string v { get; set; }
    }
    

    然后:

    XDocument xdoc = XDocument.Load(...);
    List<Scenario> scenarios = xdoc.Descendants("scenario")
        .Select(x=> new Scenario()
            {
                name= x.Attribute("name").Value, 
                ZthList= x.Descendants("zth")
                    .Select(y=> new Zth()
                    {
                        m_node = y.Attribute("m_node").Value,
                        d_node = y.Attribute("d_node").Value, 
                        data = y.Descendants("data")
                            .Select(z => new Data()
                            {
                                t =  z.Attribute("time").Value,
    enter code here
    
                                v = z.Attribute("value").Value,
                            })
                            .ToList()
                    }).ToList()
            }).ToList();
    

    编辑

    如果您只想获取d_node 等于1 的那些zth 节点,您可以更改此行:

    ...
    ZthList= x.Descendants("zth")
        .Where(n=> n.Attribute("d_node").Value == "1")  //condition was added
        .Select(y=> new Zth()
    ...
    

    然后结果将如下所示:

    【讨论】:

    • 感谢您的提示。我试图创建一个包含所有time 值的列表,但仅当d_node 属性在zth 元素中为1 时,如何将其保存在另一个列表中?
    • @kristian,如果d_node 属性不等于1 怎么办? data zth 班级的成员将是 null!没事吧?
    • 如果d_node不为1则可以忽略时间和值,只有为1时才有意义。
    • 当我显示t 的值时:Console.WriteLine(String.Join(", ", scenarios.Select(x =&gt; x.ZthList.Select(y =&gt; y.data.Select(z =&gt; z.t))))); 我没有得到这些值,但我得到了这个值:System.Linq.Enumerable+WhereSelectListIterator 2[prj.utils.Zth,System.Collections.Generic.IEnumerable 1[System.String]], System.Linq.Enumerable+WhereSelectListIterator 2[prj.utils.Zth,System.Collections.Generic.IEnumerable 1[System.String]]。我试图以这种方式获取场景的名称,它可以工作:Console.WriteLine(String.Join(", ", scenarios.Select(x =&gt; x.name)));我有什么问题吗?
    • foreach(Scenario sc in scenarios) { Console.WriteLine($"---=== {sc.name} ===---"); foreach(Zth z in sc.ZthList) { Console.WriteLine("times: {0}", string.Join(";", z.data.Select(x=&gt;x.t))); Console.WriteLine("values: {0}", string.Join(";", z.data.Select(x=&gt;x.v))); } }
    【解决方案2】:

    我做了很多改变。我总是建议避免使用“var”,除非有必要。你完全糊涂了,因为你不知道变量类型。 :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    using System.IO;
    
    namespace ConsoleApplication16
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XMLReader xReader = new XMLReader();
                xReader.xmlReader(FILENAME);
            }
     
        }
        public class Scenario
        {
            public string name { get; set; }
            public List<Zth> ZthList { get; set; }
        }
    
        public class Zth
        {
            public string m_node { get; set; }
            public string d_node { get; set; }
            public string time { get; set; }
            public string value { get; set; }
        }
        public class XMLReader
        {
    
            public void xmlReader(string filename)
            {
    
    
                XDocument doc = XDocument.Load(filename);
                List<Scenario> scenarios = (from s in doc.Root.Elements("scenario")
                                 select new Scenario
                                 {
                                     name = (string)s.Attribute("name"),
                                     ZthList = s.Elements("zth")
                                                .Select(r => new Zth()
                                                {
                                                    m_node = (string)r.Attribute("m_node"),
                                                    d_node = (string)r.Attribute("d_node"),
                                                    time = (string)r.Element("data").Attribute("time"),
                                                    value = (string)r.Element("data").Attribute("value")
                                                }).ToList()
                                 }).ToList();
                List<Scenario> zth_d_node = scenarios.Where(x => x.ZthList.Any(r => r.d_node == "1")).ToList();
                List<Scenario> s_names = scenarios.Where(x => x.name == "name").ToList();
    
                Console.WriteLine("List: ");
                Console.WriteLine(String.Join(", ", scenarios.Select(x => x.name )));
            }
        }
    }
    

    【讨论】:

    • 在这一行 List&lt;Scenario&gt; zth_d_node = scenarios.Where(x =&gt; x.ZthList.Any(r =&gt; r.d_node == "1")).ToList(); 我试图创建另一个列表,我在其中“过滤”zth 元素并检查 d_node 是否为一个,如果是这种情况我想保存元素datatime 值。如何将这些值保存在列表中,我尝试的代码仅显示“真实”值,而不显示实际数据。
    • 您正在看到 WHERE 的结果(真或假)。您需要在 WHERE 之后使用 SELECT 来返回数据。
    • 你能说得具体一点吗?在这种情况下如何从数据中选择time 属性?
    • 已经是这些了。我在答案中添加了一张图片,以便您查看。
    猜你喜欢
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多