【问题标题】:XML to XSD to .NET class object and accessing the objectXML 到 XSD 到 .NET 类对象并访问该对象
【发布时间】:2017-03-29 20:25:42
【问题描述】:

我的总体目标是能够从我的 REST API 向 .NET 客户端返回 XML 响应。在我这样做之前,我需要了解如何对这些数据进行分类,以便客户能够理解它。我计划将 XML 反序列化为一个类对象。我目前正在使用 Cars 的示例。

我有以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<CarCollection>
<Cars>
  <Car>
    <StockNumber>1020</StockNumber>
    <Make>Nissan</Make>
    <Model>Sentra</Model>
  </Car>
  <Car>
    <StockNumber>1010</StockNumber>
    <Make>Toyota</Make>
    <Model>Corolla</Model>
  </Car>
  <Car>
    <StockNumber>1111</StockNumber>
    <Make>Honda</Make>
    <Model>Accord</Model>
  </Car>
</Cars>
</CarCollection>

我通过 XSD.exe 工具(使用上面的 xml 文件)生成了以下 XSD:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="CarCollection" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="CarCollection" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Cars">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Car" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="StockNumber" type="xs:string" minOccurs="0" />
                    <xs:element name="Make" type="xs:string" minOccurs="0" />
                    <xs:element name="Model" type="xs:string" minOccurs="0" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

由此,我生成了以下 C# 类(命令:xsd.exe carcollection.xsd /c):

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Xml.Serialization;

// 
// This source code was auto-generated by xsd, Version=4.6.1586.0.
// 


/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1586.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class CarCollection {

    private CarCollectionCars[] itemsField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Cars", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public CarCollectionCars[] Items {
        get {
            return this.itemsField;
        }
        set {
            this.itemsField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1586.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class CarCollectionCars {

    private CarCollectionCarsCar[] carField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Car", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public CarCollectionCarsCar[] Car {
        get {
            return this.carField;
        }
        set {
            this.carField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1586.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class CarCollectionCarsCar {

    private string stockNumberField;

    private string makeField;

    private string modelField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string StockNumber {
        get {
            return this.stockNumberField;
        }
        set {
            this.stockNumberField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Make {
        get {
            return this.makeField;
        }
        set {
            this.makeField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Model {
        get {
            return this.modelField;
        }
        set {
            this.modelField = value;
        }
    }
}

我将上面的 XML 文件和 XSD 添加到我的项目中。这是我的主要课程:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Reflection;
using System.Xml;

namespace xmlToClass
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlSerializer ser = new XmlSerializer(typeof(CarCollection));
            CarCollection collection;

            var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var file = dir + @"\test.xml";

            using (XmlReader reader = XmlReader.Create(file))
            {
                collection = (CarCollection)ser.Deserialize(reader);
            }

            //I can access these directly
            Console.WriteLine(collection.Car[0].StockNumber);
            Console.WriteLine(collection.Car[1].StockNumber);
            Console.WriteLine(collection.Car[2].StockNumber);

            //TODO: How to iterate over this collection?

            Console.ReadLine();
        }
    }
}

我希望能够迭代此集合并同时访问属性。我尝试了 foreach 循环,但控制台只打印了命名空间和对象名称"xmlToClass.CarCollection+CarsRow"(默认的 toString() 方法)。

    foreach(var car in con.Cars)
    {
        Console.WriteLine(car);
    }

我会使用 for 循环,但我无法获得集合的长度。我想我不理解生成的类属性或字段......我会非常感谢一些方向!奖励问题(在我了解如何正确访问这些被 XML 反序列化为类的对象之后):

  1. 如果我希望 StockNumber 为“int”或“integer”类型而不是字符串,该怎么办?我尝试向 XML 文档添加类型属性并重新生成 XSD,但无济于事。

感谢您的宝贵时间!如果你想要项目文件,我可以发给你。

注意事项

  1. 我不想直接编辑 XSD 或 .CS 文件,因为它们都是从 XML 文档生成的。需要对 XML 文档进行的任何更改都需要重新生成 XSD/CS 文件。

【问题讨论】:

    标签: c# xml rest


    【解决方案1】:

    "我试过foreach循环,但是控制台只打印了命名空间 以及对象名称“xmlToClass.CarCollection+CarsRow”:”

    你的 for each 工作正常,问题是你看到的是 ToString() 的默认实现。如果您实现自己的,您可以控制输出 - 例如

    public override string ToString()
    {
      return $"stock:{stockNumberField} make: {makeField}";
    }
    

    如果我想 StockNumber 为“int”或“integer”类型怎么办 代替字符串?

    然后更改声明并重新生成您的类

    <xs:element name="StockNumber" type="xs:int" minOccurs="0" />
    

    【讨论】:

    • 类和 XSD 都是自动生成的。因此,如果我对原始 XML 进行更改,自定义 toString() 方法和 XSD 中的数据类型将被删除。我会更新我的问题。我正在寻找访问类外部属性的方法,以及在原始 XML 中设置数据类型,以便 XSD.exe 工具可以解释它们并将它们存储在 XML 架构定义中。
    • xsd 构建部分类的全部原因是,您可以在不受重新生成影响的单独代码文件(同一类 - 当然是部分)中实现诸如 ToString() 之类的东西。
    • 关于为什么 xsd 生成字符串而不是 int 等有很多问题。假设您是从 xml 生成 xsd 到代码,那么对此没有简单的答案 - 这似乎是一个工具的限制。您始终可以在另一个为最终用户进行转换的部分类中将属性公开为 int……或者从模式优先方法开始,而不是从 xml 开始。
    • 我明白了。感谢关于部分类的非常重要的说明——我还没有深入研究过 C#。至于 XSD 数据类型,感谢您的洞察力。在我标记答案之前,我将让这个问题搁置几天。非常感谢您的宝贵时间!
    猜你喜欢
    • 2016-05-05
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多