如何将带有嵌套元素的基于模式的 xml 文件读取到表类型对象中?

发布于 2025-01-05 10:24:35 字数 4655 浏览 1 评论 0原文

沿着 解析 xml 文件的最佳实践? 我正在寻找快速、简单的方法来获取精心呈现的 XML 模式和在其上构建的一堆 xml 数据实例,并将它们快速读入一些类似于 DataSet 的对象中。 (实际上,可以是具有多个表、行和列的任何内容,只要我可以在网格中呈现它,添加一些列,进行一些更改,并在完成与)我想我会使用 XmlReader< /a>来做到这一点,但它的表创建非常不智能,也许是因为我正在使用 xsd 中的全局声明/可重用类型?或者因为我没有使用正确的参数来实现?

详细示例代码如下。不过,为了解决这个问题:XmlReader 似乎没有任何工具来解释架构的关系性质;子元素必须链接到表结构中的父元素才有意义,但结果输出不会这样做。读者也无法理解列表只是表的集合,其设置是为了避免冲突、不相关的兄弟姐妹的麻烦(尽管示例代码没有)。

如果我想主要批量处理这些数据(实际上不需要的对象),将其导入 C# 并同时完全尊重分层结构的最佳实践、代码行数最少的方法是什么?结构体在xsd中定义并在xml中进行?

进一步说明:我并没有与 XmlReader 结婚,并且确实研究了 LINQ to XML 和 xsd.exe 对象生成器,但这两者都意味着编写比我想象的更多的代码(或清理更多的代码)制定严格、可读的 xsd。几天前,我认为这将是一个快速转换...


示例模式,另存为 FooSchema.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
    targetNamespace="http://tempuri.org/FooSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/FooSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:complexType name="FooNoteType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="dateStamp" type="xs:dateTime" use="optional" />
        <xs:attribute name="isBar" type="xs:boolean" use="optional" />
      </xs:extension>
    </xs:simpleContent>  
  </xs:complexType>
  <xs:complexType name="FooType">
    <xs:sequence>
      <xs:element name="stuff" type="xs:string" />
      <xs:element name="nonsense" type="xs:string" minOccurs="0" />
      <xs:element name="note" type="FooNoteType" minOccurs="0" />
    </xs:sequence>
    <xs:attribute name="isBar" type="xs:boolean" use="required" />
  </xs:complexType>
  <xs:complexType name="FooListType">
    <xs:sequence>
      <xs:element name ="foo" type="FooType" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>

  <xs:element name="fullaFoo">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="foos" type="FooListType" />
      </xs:sequence>
    </xs:complexType>

  </xs:element>
</xs:schema>

示例实例 FooData.xml——注意嵌套注释

<?xml version="1.0" encoding="utf-8" ?>
<fullaFoo xmlns="http://tempuri.org/FooSchema">
  <foos>
    <foo isBar="false">
      <stuff>first</stuff>
      <nonsense>item</nonsense>
      <note>This is the first note.</note>
    </foo>
    <foo isBar="true">
      <stuff>things</stuff>
      <nonsense>other things</nonsense>
    </foo>
    <foo isBar="false">
      <stuff>yet more information</stuff>
      <nonsense>sound, fury, etc.</nonsense>
    </foo>
    <foo isBar="true">
      <stuff>yes please</stuff>
      <nonsense>no thank you</nonsense>
      <note dateStamp="2012-02-12T00:00:00" isBar="false">RE good manners</note>
    </foo>
    <foo isBar="false">
      <stuff>last</stuff>
      <nonsense>item</nonsense>
    </foo>
  </foos>
</fullaFoo>

基本预期的 C# 转换

    void Test_ReadXmlToDataset()
    {
        string pathRoot = @"C:\SomePath\";
        string pathSchema = pathRoot + @"FooSchema.xsd";
        string pathData = pathRoot + @"FooData.xml";

        DataSet dsTest = new DataSet("testXml");
        dsTest.ReadXmlSchema(pathSchema);
        dsTest.ReadXml(pathData);

        //rubber would meet road here...

        DisplayTableStructure(dsTest);
    }
    void DisplayTableStructure(DataSet dataSet)
    {
        Console.WriteLine("\r\nTable structure \r\n");
        Console.WriteLine("Tables count=" + dataSet.Tables.Count.ToString());
        for (int i = 0; i < dataSet.Tables.Count; i++)
        {
            Console.WriteLine("\tTableName='" + dataSet.Tables[i].TableName + "'.");
            Console.WriteLine("\tColumns count=" + dataSet.Tables[i].Columns.Count.ToString());

            for (int j = 0; j < dataSet.Tables[i].Columns.Count; j++)
            {
                Console.WriteLine("\t\tColumnName='" +
                                  dataSet.Tables[i].Columns[j].ColumnName + "', type = "
                                  + dataSet.Tables[i].Columns[j].DataType.ToString());
            }
        }
        Console.ReadLine();
    }

Along the lines of Best practices to parse xml files? I am looking for a quick, simple method to take a carefully rendered XML schema and a bunch of instances of xml data built upon it, and read them quickly into some DataSet-like object. (Can be anything with multiple tables, rows, and columns, really, as long as I can present it in grids, add some columns, make some changes, and push it along to granular objects or a database when I'm done interacting with it in aggregate.) I thought I would use XmlReader to do this, but its table creation is pretty unintelligent, perhaps because I'm working with globally-declared/reusable types in the xsd? Or because I'm not implementing with correct parameters?

Detailed sample code below. To get to the problem though: XmlReader doesn't seem to have any facility to interpret the relational nature of the schema; a child element must be linked to its parent in a table structure to be meaningful, but the resulting output won't do that. Nor can the reader understand that a list is just a collection of tables, set off to avoid trouble with colliding, unrelated siblings (though the sample code has none).

If I want to work with this data primarily in bulk (objects not required really), what is the best-practice, fewest-lines-of-code method to get it into C# while fully respecting the hierarchical structure defined in the xsd and carried out in the xml?

One further note: I'm not married to the XmlReader, and did investigate LINQ to XML and the xsd.exe object generator, but both of these implied writing more code (or cleaning up more) than I would have thought I'd have to do with a rigorous, readable xsd in place. I thought, several days ago, that this would be a quick transformation...


Sample schema, saved as FooSchema.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
    targetNamespace="http://tempuri.org/FooSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/FooSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:complexType name="FooNoteType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="dateStamp" type="xs:dateTime" use="optional" />
        <xs:attribute name="isBar" type="xs:boolean" use="optional" />
      </xs:extension>
    </xs:simpleContent>  
  </xs:complexType>
  <xs:complexType name="FooType">
    <xs:sequence>
      <xs:element name="stuff" type="xs:string" />
      <xs:element name="nonsense" type="xs:string" minOccurs="0" />
      <xs:element name="note" type="FooNoteType" minOccurs="0" />
    </xs:sequence>
    <xs:attribute name="isBar" type="xs:boolean" use="required" />
  </xs:complexType>
  <xs:complexType name="FooListType">
    <xs:sequence>
      <xs:element name ="foo" type="FooType" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>

  <xs:element name="fullaFoo">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="foos" type="FooListType" />
      </xs:sequence>
    </xs:complexType>

  </xs:element>
</xs:schema>

Sample instance FooData.xml--note the nested notes

<?xml version="1.0" encoding="utf-8" ?>
<fullaFoo xmlns="http://tempuri.org/FooSchema">
  <foos>
    <foo isBar="false">
      <stuff>first</stuff>
      <nonsense>item</nonsense>
      <note>This is the first note.</note>
    </foo>
    <foo isBar="true">
      <stuff>things</stuff>
      <nonsense>other things</nonsense>
    </foo>
    <foo isBar="false">
      <stuff>yet more information</stuff>
      <nonsense>sound, fury, etc.</nonsense>
    </foo>
    <foo isBar="true">
      <stuff>yes please</stuff>
      <nonsense>no thank you</nonsense>
      <note dateStamp="2012-02-12T00:00:00" isBar="false">RE good manners</note>
    </foo>
    <foo isBar="false">
      <stuff>last</stuff>
      <nonsense>item</nonsense>
    </foo>
  </foos>
</fullaFoo>

Rudimentary expected C# transformation

    void Test_ReadXmlToDataset()
    {
        string pathRoot = @"C:\SomePath\";
        string pathSchema = pathRoot + @"FooSchema.xsd";
        string pathData = pathRoot + @"FooData.xml";

        DataSet dsTest = new DataSet("testXml");
        dsTest.ReadXmlSchema(pathSchema);
        dsTest.ReadXml(pathData);

        //rubber would meet road here...

        DisplayTableStructure(dsTest);
    }
    void DisplayTableStructure(DataSet dataSet)
    {
        Console.WriteLine("\r\nTable structure \r\n");
        Console.WriteLine("Tables count=" + dataSet.Tables.Count.ToString());
        for (int i = 0; i < dataSet.Tables.Count; i++)
        {
            Console.WriteLine("\tTableName='" + dataSet.Tables[i].TableName + "'.");
            Console.WriteLine("\tColumns count=" + dataSet.Tables[i].Columns.Count.ToString());

            for (int j = 0; j < dataSet.Tables[i].Columns.Count; j++)
            {
                Console.WriteLine("\t\tColumnName='" +
                                  dataSet.Tables[i].Columns[j].ColumnName + "', type = "
                                  + dataSet.Tables[i].Columns[j].DataType.ToString());
            }
        }
        Console.ReadLine();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文