65.9K
CodeProject 正在变化。 阅读更多。
Home

读取/写入由 XSD 定义的 XML 文件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2020 年 12 月 1 日

CPOL

2分钟阅读

viewsIcon

6191

如何快速生成代码来处理带有 XSD 定义的 XML 文件

引言

网上有很多文章展示了如何序列化/反序列化 XML - 有些不错,但大多数只是重复基本内容。我在这里不会这样做。几乎没有人介绍在您拥有 XSD 定义文件的情况下如何快速完成此操作。

这里有一个 Github 仓库 伴随本文。

为了演示这个过程,我们将导入 GPX 文件。这些是具有 gpx 扩展名的 XML 格式的文件。详细的 XSD 定义在这里

只需看一眼定义,您就能知道 GPX 文件可以有多复杂和详细,以及手动编写和测试处理类需要多少精力。幸运的是,微软提供了一个鲜为人知的工具来自动化大部分过程,它隐藏在 Windows SDK 中 - XSD.exe

构建类

  1. 设置一个基本的 DotNetCore 控制台项目(如果您使用 Visual Studio,IDE 将为您执行一些巧妙的 XSD 到类关联)。
  2. 获取 XSD 文件并将其添加到子文件夹 - GPX.xsd - 在这种情况下是 Gpx
  3. 找到 XSD.exe。它位于 Windows SDK 中 - 目前在我的机器上位于 C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools
  4. 打开一个控制台/powershell 窗口,并切换到 XSD.exe 目录。
  5. 运行 XSD.exe 针对 xsd 文件。请注意,我已将输出设置为输入目录。
.\xsd.exe "D:\Documents\GitHub\GPXReader\Gpx\gpx.xsd" 
 /c /outputdir:"D:\Documents\GitHub\GpxReader\Gpx"

结果应该是(我添加了分隔符 ============= 以使其更清晰)

PS C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools> 
.\xsd.exe "D:\Documents\GitHub\GPXReader\Gpx\gpx.xsd" 
/c /outputdir:"D:\Documents\GitHub\GPXReader\Gpx"

==========================================================
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.8.3928.0]
Copyright (C) Microsoft Corporation.  All rights reserved.
Writing file 'D:\Documents\GitHub\GPXReader\Gpx\gpx.cs'.

===========================================================
PS C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools>

在项目中,您现在应该看到

gpxclass

不要被诱惑去重命名(我也不喜欢那些类名!)。考虑一下如果定义被更新,您的代码维护过程会怎样。

导入代码

现在我们需要一个简单的 Importer 类来展示我们正在正确导入数据。这些方法都是 static,并使用流,因为 XmlSerializer 使用流,而不是字符串。

ReadFile - 有两个版本

  1. 创建一个 StreamReader 来获取导入文件
  2. 创建一个 XmlSerializer 对象,并使用正确的对象类型和 XSD 定义
  3. 运行 Deserialise,将结果转换为正确的对象类型
  4. 对象处置由 using 处理

WriteFile:

  1. 创建一个 StreamWriter 来接受 XmlSerializer 输出 - 指向输出文件
  2. 创建一个 XmlSerializer 对象,并使用正确的对象类型和 XSD 定义
  3. 运行 Serialize,输出到 StreamWriter
  4. 刷新 StreamWriter 以将数据写入文件
  5. 对象处置由 using 处理
using System;
using System.IO;
using System.Xml.Serialization;

namespace GPXReader
{
    public class GPXReader
    {
        public static gpxType ReadFile(Uri url)
        {
            gpxType gpxdata = null;
            try
            {
                using (StreamReader reader = new StreamReader(url.AbsolutePath))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(gpxType), 
                                               "http://www.topografix.com/GPX/1/1");
                    gpxdata = serializer.Deserialize(reader) as gpxType;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"An Error has occurred accessing file 
                {url.AbsolutePath}.{Environment.NewLine} Details:{Environment.NewLine} 
                {e.StackTrace}.");
            }
            return gpxdata;
        }
        
        //  Bool return version
        public static bool ReadFile(Uri url, out gpxType gpxdata)
        {
            gpxdata = null;
            try
            {
                using (StreamReader reader = new StreamReader(url.AbsolutePath))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(gpxType), 
                                               "http://www.topografix.com/GPX/1/1");
                    gpxdata = serializer.Deserialize(reader) as gpxType;
                    return true;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"An Error has occurred accessing file 
                                 {url.AbsolutePath}.{Environment.NewLine} 
                                 Details:{Environment.NewLine} {e.StackTrace}.");
            }
            return false;
        }

        public static bool WriteFile(gpxType data, Uri url)
        {
            try
            {
                using (StreamWriter writer = new StreamWriter(url.AbsolutePath, false))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(gpxType), 
                                               "http://www.topografix.com/GPX/1/1");
                    serializer.Serialize(writer, data);
                    writer.Flush();
                    return true;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"An Error has occurred accessing file 
                        {url.AbsolutePath}.{Environment.NewLine} 
                        Details:{Environment.NewLine} {e.StackTrace}.");
            }
            return false;
        }
    }
}

最后,我们构建一个简单的 Program。我将一个相当复杂的 gpx 文件(从 Google Maps 导入)添加到项目中。

using System;

namespace GPXReader
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("GPX Reader");

            var data = GPXReader.ReadFile
                       (new Uri($"D:/Documents/GitHub/GPXReader/gpx/Test.gpx"));

            Console.WriteLine($"Read file");

            // Set Break point here to view the imported file

            Console.WriteLine($"Writing output file");

            GPXReader.WriteFile
               (data, new Uri($"D:/Documents/GitHub/GPXReader/gpx/output.gpx"));

            Console.WriteLine("Complete");
        }
    }
}

项目如下所示

data view

测试输出

使用断点运行项目,并探索创建的 data 对象。

data view

就是这样!

历史

  • 2020 年 12 月 1 日:初始版本
© . All rights reserved.