【问题标题】:Tool that auto-generate a code for accesing a xml-file自动生成用于访问 xml 文件的代码的工具
【发布时间】:2010-05-04 12:44:01
【问题描述】:

我的应用程序有一个配置 xml 文件。该文件包含 50 多个程序设置。目前我分别读取并保存每个程序设置。我猜 对于此类任务来说效率不高

我需要可以使用预定义的 xml 模式自动生成加载代码和保存程序设置的东西。

我在 添加新项目 对话框中找到了一个数据集。不幸的是,我无法向 dataset1 添加新代码,例如属性的 set-accessors 中的事件,因此

//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.

也许,有一个工具可以让用户生成一个用于访问 xml 文件的包装器?如 DataSet1,但可以添加事件。

编辑:我没有标记有用的答案,因为我阅读了您给我的文章(链接)。稍后我会标记有用的答案。

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    如果您不愿意使用 app.config/web.config 或属性文件(Oded 和 Bruno 推荐,我也推荐),我强烈推荐这个实用程序:

    Web Services Contract First (WSCF) Blue 用于 VS2008 和 VS2010

    如果你使用的是 VS2005,你会想要这个版本的工具:http://www.thinktecture.com/resourcearchive/tools-and-software/wscf(不要在这个网站上使用 VS2008 版本。我永远无法让它正常工作。)

    将插件安装到 Visual Studio 后,您将需要 XML 文件的 XSD 架构。 (Google for an online XSD Generator.) 按照 WSCF 网站上的说明,您可以生成一个包装类,它将反序列化和重新序列化您的 XML,并为您提供 XML 的抽象视图。

    我认为添加新的节点/元素类型是不可能的(或者至少非常困难),但是添加现有节点/元素类型的新实例、访问您的数据、编辑数据、重新排序节点,然后保存回来出去都很容易。

    反序列化代码如下:

    private MyGeneratedXMLconfigClass config;
    using (StreamReader sr = new StreamReader(filename))
    {
       XmlSerializer cXml = new XmlSerializer(typeof(MyGeneratedXMLconfigClass));
       config = (MyGeneratedXMLconfigClass)cXml.Deserialize(sr);
    }
    

    现在您的 XML 已反序列化为自定义类的“配置”实例。然后,您可以将整个类作为一系列嵌套值和列表访问。

    例如:

    string errorFile = config.errorsFile;
    List<string> actions = config.actionList;
    var specialActions = from action in config.actionList
                          where action.contains("special")
                          select action;
    

    等等等等。然后,一旦你完成了对数据的操作,你就可以用这个代码重新序列化:

    using (StreamWriter wr = new StreamWriter(filename, false))
    {
       XmlSerializer cXml = new XmlSerializer(typeof(MyGeneratedXMLconfigClass));
       cXml.Serialize(wr, config);
    }
    

    这个工具的优点之一是它会自动将所有类生成为“部分”类,这样您就可以随意扩展每个类,而不必担心您的代码会被踩到以防万一由于 XSD/XML 已更改,因此需要重新生成。

    我想这听起来可能很多,但学习曲线实际上很容易,一旦安装并工作,你就会意识到它是多么简单。这很值得。我发誓。 :-)

    【讨论】:

      【解决方案2】:

      如果您的 xml 文件有合适的 xsd 架构,微软会提供 xsd.exe,这是一个小工具,可以为该架构自动生成 c# 类。

      详情见:http://msdn.microsoft.com/en-us/library/x6c1kb0s%28VS.71%29.aspx

      【讨论】:

        【解决方案3】:

        为什么要使用手动 XML 进行配置?现有的 app.configweb.config 架构有什么问题?

        【讨论】:

        • 我有一个多用户应用程序,所以我需要为每个用户提供 1 个 xml 文件。
        【解决方案4】:

        为什么不使用.Settings file

        【讨论】:

        • 我有一个多用户应用程序,所以设置文件不适合我。我需要 1 个包含每个用户设置的 xml 文件。
        • 如果您阅读我链接的文章,您会发现 .settings 文件用于多用户应用程序的。它们与 .config 文件不同。
        • 是的,我读过。设置文件对某些任务很有用。这不正是我想要的。我解释:如果我想动态创建设置文件怎么办?或者,例如,如果我想保存一个对象列表(我不知道对象的数量)。如何在我想要的位置创建该设置文件?使用更适合我的问题的 xsd 实用程序的解决方案。我现在正在阅读它。无论如何,谢谢你试图帮助我:)
        【解决方案5】:

        您可以按照以下步骤操作:

        1) 从您的 XML 文件生成 XSD 文件。因为曾经有一个工具可以从 XML 文件中推断模式,我忘记了它叫什么。目前我使用自己的实用程序,它基本上运行这个核心例程来读取一个xml文件并生成相应的xsd:

        static void InferSchema(string fileName)
        {
            XmlWriter writer = null;
            XmlSchemaInference infer = new XmlSchemaInference();
            XmlSchemaSet sc = new XmlSchemaSet();
        
            string outputXsd = fileName.Replace(".xml", ".xsd");
            sc = infer.InferSchema(new XmlTextReader(fileName));
        
            using (writer = XmlWriter.Create(new StreamWriter(outputXsd)))   
            {
                foreach(XmlSchema schema in sc.Schemas())
                {
                    schema.Write(writer);
                    Console.WriteLine(">> found schema - generated to {0}", 
                    outputXsd);
                }
            }
        }
        

        2) 运行 xsd.exe 以从 XSD 文件生成可序列化的类。

        xsd.exe /c /n:MyNameSpaceHere MyGenerated.xsd
        

        接下来,您可以使用 XmlSerializer.Serialize() 方法将 XML 文件读入可序列化类。像这样的:

            public static void Serialize<T>(T data, TextWriter writer)
            {
                try
                {
                    XmlSerializer xs = new XmlSerializer(typeof(T));
                    xs.Serialize(writer, data);
                }
                catch (Exception e)
                {
                    throw;
                }
            }
        

        最后,您可以使用 XmlSerializer.Deserialize() 方法从类中写回 XML 文件,例如:

        public static void Deserialize<T>(out T data, XmlReader reader)
        {
            try
            {
                XmlSerializer xs = new XmlSerializer(typeof(T));
                data = (T)xs.Deserialize(reader);
            }
            catch (Exception e)
            {
                reader.Close();
                throw;
            }
        }
        

        【讨论】:

          【解决方案6】:

          这称为属性文件。 C# 应该具有类似于 Java 的 Properties 类的内容,您可以在其中加载所有属性而无需对其名称进行硬编码。

          编辑: C# 显然没有内置的属性解析解决方案。但是你可以很容易地实现你自己的。见here

          【讨论】:

            【解决方案7】:

            如果您有 XSD 文件,则可以从中生成类。除了已经提到的 Microsoft 的 xsd.exe(很长一段时间没有更新)之外,还有其他工具可以做到这一点。我正在使用XSD2Code,它允许生成强类型集合、延迟初始化等。

            如果您没有 XSD,您可以将 xsd.exe 指向您的 xml 文件,它会从中生成一个 XSD。架构通常需要一些工作,但通常是一个很好的起点。

            xsd.exe (instance).xml
            

            【讨论】:

              【解决方案8】:

              您可以使用 System.Xml.Serialization - 它非常简单,您甚至可以直接序列化类对象,例如 MyCustomClass(它甚至可以保存 MyCustomClass 公共字段)。

              反序列化 XML 文件会得到一个新的 MyCustomClass 实例,所以这样的功能是无价的。

              注意一件事:你应该添加你在课堂上使用的每一种类型,但这很容易。

              我附上了一个完整的项目,可以做你想做的事。只需更改类和对象即可。 source code

              例如(我正在缩短代码):

              using System.Xml;
              using System.Xml.Serialization;
              using System.IO;
              
              [XmlRootAttribute("Vendor")]
              class Vendor{
                  [XmlAttribute]
                  Product prod;
              }
              [XmlRootAttribute("Product")]
              class Product{
                  [XmlAttribute]
                  public string name="";
              }
              
              class Test{
                  Vendor v=new Vendor();
                  Product p=new Product();
                  p.name="a cake";
                  v.prod=p;
              
                  //add EVERY SINGLE TYPE you use in the serialized class.
                  Type[] type_list = { typeof(Product) };
              
                      XmlSerializer packer = new XmlSerializer(v.GetType(),type_list);
                      XmlWriter flusher = XmlWriter.Create(@"c:\bak.xml");
              
              
              
              
                      packer.Serialize(flusher, v);
              
                      flusher.Close();
              
                      XmlReader restorer = XmlReader.Create(@"c:\bak.xml");
                      Vendor v2 = (Vendor)packer.Deserialize(restorer);
              
                  //v2.prod.name is now "cake"
                  //COOL was my first impression :P
              
              }
              

              【讨论】:

                猜你喜欢
                • 2011-03-13
                • 2011-09-06
                • 1970-01-01
                • 2012-03-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-02-01
                相关资源
                最近更新 更多