代码之家  ›  专栏  ›  技术社区  ›  dragonmantank

用C编写XML#

  •  3
  • dragonmantank  · 技术社区  · 17 年前

    我的C#有点生疏,我以前从未用它编写过XML。如果我尝试写入除元素之外的任何内容,我很难将XML写入文件。这是我的测试代码:

    var guiPath = txtGuiPath.Text;
    MessageBox.Show("Dumping File: " + guiPath);
    
    try
    {
        var writer = new XmlTextWriter("client_settings.xml", null);
        writer.WriteStartDocument();
        writer.WriteComment("Config generated on 01/01/01");
        writer.WriteStartElement("Config");
        writer.WriteStartElement("GuiPath");
        writer.WriteString(guiPath);
        writer.WriteEndElement();
        writer.WriteEndElement();
        writer.WriteEndDocument();
        writer.Close();
    } catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
    MessageBox.Show("Finished Dumping");
    

    如果guiPath为空,则得到以下XML:

    <?xml version="1.0"?>
    <!--Config generated on 01/01/01-->
    <Config>
        <GuiPath />
    </Config>
    

    但如果guiPath中有任何文本,则不会向文件写入任何内容。我甚至可以删除client_settings.xml文件并反复启动此代码,除非guiPath为空,否则xml文件永远不会生成。向WriteString()传递类似“This is a test”的东西也可以。

    更新

    由于我试图写出一个系统路径,这似乎是问题所在。如果我去掉所有反斜杠,它将正确写入结果字符串,但如果我将其传递给WriteString或WriteCData,XML将根本不会写入。

    更新2

    事实证明,我遇到这么多问题的原因是,XML文件是在guiPath设置的任何路径中生成的,而不是在应用程序运行的目录中生成的(所以在我看来,它根本没有生成)。因此,如果我将guiPath设置为“C:\Program Files\externalApp\appName.exe”,它会将XML文件另存为“C:\ProgramFiles\externalApp\client_settings.XML”,而不是保存在应用程序的启动文件夹中。为什么,我不知道。我开始通过申请。StartupPath并附加了文件名,现在效果很好。

    谢谢你的帮助!

    7 回复  |  直到 17 年前
        1
  •  12
  •   mqp    17 年前

    您可能需要检查系统中的API。Xml。林克。这是一种更灵活的生成和编写XML的方法。编写文档大致如下:

    XDocument document = new XDocument();
    document.Add(new XComment("Config generated on 01/01/01"));
    document.Add(new XElement("Config", new XElement("GuiPath", guiPath)));
    
    // var xmlWriter = new XmlTextWriter("client_settings.xml", null);
    // document.WriteTo(xmlWriter);
    
    // thanks to Barry Kelly for pointing out XDocument.Save()
    document.Save("client_settings.xml");
    
        2
  •  3
  •   Daniel Schaffer    17 年前

    为什么不创建一个简单的类来保存所需的所有数据,然后使用XmlSerializer对其进行序列化,而不是逐行手动生成它呢?您甚至可以在系统中使用这些属性。Xml。如果需要,可以进行序列化以控制输出:

    using System;
    using System.IO;
    using System.Windows.Forms;
    using System.Xml.Serialization;
    
    namespace Foo
    {    
        [XmlRoot(ElementName = "Config")]
        public class Config
        {        
            public String GuiPath { get; set; }
    
            public Boolean Save(String path)
            {
                using (var fileStream = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                {
                    try
                    {
                        var serializer = new XmlSerializer(typeof(Config));
                        serializer.Serialize(fileStream, this);
                        return true;
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                        // Other exception handling here
                        return false;
                    }
                }
            }
    
            public static Config Load(String path)
            {
                using (var fileStream = File.Open(path, FileMode.Open, FileAccess.Read))
                {
                    try
                    {
                        var serializer = new XmlSerializer(typeof(Config));
                        return (Config)serializer.Deserialize(fileStream);
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                        // Other exception handling here
                        return null;
                    }
                }
            }
        }
    }
    

    这样,如果字符串有奇怪的字符,您就不必担心手动编码字符串——序列化程序会为您完成这项工作。

    这还有一个额外的好处,即能够序列化回类中,这样如果需要的话,您就可以对结构进行强类型访问。

        3
  •  1
  •   annakata    17 年前

    嗯,似乎“真实” guiPath 包含破坏XML验证和XmlTextWriter的字符。

    我可以建议你试试吗 .WriteCData() (而不是 .WriteString() 即)

        4
  •  1
  •   Jim Mischel    17 年前

    您希望输出是什么?如果你正在寻找以下内容:

    <?xml version="1.0"?>
    <!--Config generated on 01/01/01-->
    <Config>
        GuiPath="c:\some\path\here\"
    </Config>
    

    然后,您需要将WriteString更改为:

    writer.WriteAttributeString("GuiPath", guiPath);
    

    或者,如果你愿意:

    <GuiPath>c:\some\path\here\</GuiPath>
    

    然后你需要写

    writer.WriteElementString("GuiPath", guiPath);
    
        5
  •  1
  •   Community Mohan Dere    9 年前

    没有其他人提到过,但我认为我最好: 强烈地 考虑使用 using 使用时的声明 IDisposable 实现方式,例如 XmlTextWriter 等等

    这不仅对于关闭资源(如底层流或文本编写器)很重要,而且对于确保任何缓冲区都已被刷新,以及确保任何剩余的未关闭元素都已关闭也很重要。

    所以,当你看到 mquander's anwser ,请考虑以下内容:

    using (var xmlWriter = new XmlTextWriter("client_settings.xml", null))
    {
        // ...
    }
    

    同样地,在 Daniel's answer ,不要盲目地接受异常,并强烈考虑使用 使用 关于返回值的声明 File.Open (也许应该是 File.OpenText 但丹尼尔在写作时的回答在风格上还有许多其他缺点)。

        6
  •  0
  •   Ray    17 年前

    我会使用这个系统。XML。林克。XElement类

    请注意,注释是肯定的,但配置部分会是这样的。

    XElement root = new XElement("Config");
    root.Add(new XElement("GuiPath", guiPath);
    root.Save("client_settings.xml");
    

    编辑: mquander的例子更好。你看。

        7
  •  -1
  •   Coderer    17 年前

    在写出内容之前,您需要对其进行转义,以确保它们是有效的字符串。我不知道。不幸的是,NET例程会自动执行此操作——这个问题以前也被问过。