如何在C#中构建XML?

457

如何在C#中生成有效的XML?

9个回答

524
这取决于具体情况。 XmlSerializer 无疑是一种方法,并且具有直接映射到对象模型的优点。在 .NET 3.5 中,XDocument 等也非常友好。如果大小非常大,则 XmlWriter 是您的朋友。
对于 XDocument 的示例:
Console.WriteLine(
    new XElement("Foo",
        new XAttribute("Bar", "some & value"),
        new XElement("Nested", "data")));

或者使用 XmlDocument

XmlDocument doc = new XmlDocument();
XmlElement el = (XmlElement)doc.AppendChild(doc.CreateElement("Foo"));
el.SetAttribute("Bar", "some & value");
el.AppendChild(doc.CreateElement("Nested")).InnerText = "data";
Console.WriteLine(doc.OuterXml);

如果你正在编写大量的数据流,那么任何DOM方法(例如XmlDocument/XDocument等)都会快速占用大量内存。因此,如果你要从CSV文件中编写100 MB的XML文件,则可以考虑使用XmlWriter;这更为原始(一次性的写入口),但非常高效(想象一个大循环在这里):

XmlWriter writer = XmlWriter.Create(Console.Out);
writer.WriteStartElement("Foo");
writer.WriteAttributeString("Bar", "Some & value");
writer.WriteElementString("Nested", "data");
writer.WriteEndElement();

最终,通过 XmlSerializer:
[Serializable]
public class Foo
{
    [XmlAttribute]
    public string Bar { get; set; }
    public string Nested { get; set; }
}
...
Foo foo = new Foo
{
    Bar = "some & value",
    Nested = "data"
};
new XmlSerializer(typeof(Foo)).Serialize(Console.Out, foo);

这是一个很好的将XML映射到类等的模型,但如果您只是做一些简单的事情(或者所需的XML与对象模型没有直接关联),可能会过度。另一个问题是XmlSerializer不喜欢序列化不可变类型:每个属性都必须有公共的getter和setter(除非您通过实现IXmlSerializable来自己完成所有操作,在这种情况下,使用XmlSerializer并没有太多优势)。

11
不要忘记使用XStreamingElement,它可以在这里找到:http://msdn.microsoft.com/en-us/library/system.xml.linq.xstreamingelement.aspx。 :) - Todd White
1
对于 XmlWriter 示例,重要的是要注意,在最后需要关闭写入器才能正常工作 - 在 writer.WriteEndElement() 之后需要使用 writer.Close()。 - Marko
@Marko所说的是真的:正确关闭写入器很重要。除了直接调用writer.Close()之外,还有另一种方法可以做到这一点。您可以将对Create()的调用包装在using语句中,如下所示:using(XmlWriter writer = XmlWriter.Create(Console.Out)) { writer.WriteStartElement("Foo"); etc } 这里还有另一个(稍微更加完善)的XmlWriter示例:https://www.dotnetperls.com/xmlwriter - Morten
@Morten 如果XmlWriter实现了IDisposable接口,那么使用using语句是最好的选择。 - Marko
好老的XMLDocument拥有它所有的特性。如果您要创建XML文档,它是直接、简单和清晰的选择。 - FrenkyB

61

我尝试过的最好的东西是LINQ to XSD(大多数开发人员不知道)。你给它一个XSD模式,它会在后台生成一个完美映射、完整强类型对象模型(基于LINQ to XML),非常容易使用 - 它可以实时更新和验证您的对象模型和XML。虽然它仍然处于“预览”阶段,但我没有遇到任何错误。

如果您有一个像这样的XSD模式:

  <xs:element name="RootElement">
     <xs:complexType>
      <xs:sequence>
        <xs:element name="Element1" type="xs:string" />
        <xs:element name="Element2" type="xs:string" />
      </xs:sequence>
       <xs:attribute name="Attribute1" type="xs:integer" use="optional" />
       <xs:attribute name="Attribute2" type="xs:boolean" use="required" />
     </xs:complexType>
  </xs:element>

然后,您可以像这样简单地构建XML:
RootElement rootElement = new RootElement;
rootElement.Element1 = "Element1";
rootElement.Element2 = "Element2";
rootElement.Attribute1 = 5;
rootElement.Attribute2 = true;

或者像这样从文件中加载XML:

RootElement rootElement = RootElement.Load(filePath);

或者像这样保存:

rootElement.Save(string);
rootElement.Save(textWriter);
rootElement.Save(xmlWriter);

rootElement.Untyped也以XElement的形式提供元素(来自LINQ to XML)。


似乎这段代码不起作用。当我尝试像这样做时,RootElement上没有应用保存功能。 - DanilGholtsman

24
new XElement("Foo",
       from s in nameValuePairList
       select
             new XElement("Bar",
                  new XAttribute("SomeAttr", "SomeAttrValue"),
                          new XElement("Name", s.Name),
                          new XElement("Value", s.Value)
                         )
            );

10

XmlWriter是编写优秀XML的最快方法。XDocument、XMLDocument等也可以很好地工作,但它们没有针对编写XML进行优化。如果您想要尽可能快地编写XML,您应该绝对使用XmlWriter。


7
换句话说,如果你想让计算机以最快的速度编写XML文件。但如果你作为开发者想以最简单和自然的方式创建XML,那么XmlWriter可能不是最佳方案! - sjy

5

4

我认为这个资源应该足够完成中等难度的XML保存/加载:使用C#读写XML

我的任务是存储音乐符号。我选择了XML,因为我猜测.NET已经成熟到可以轻松解决这个任务。我是对的 :)

这是我的歌曲文件原型:

<music judul="Kupu-Kupu yang Lucu" pengarang="Ibu Sud" tempo="120" birama="4/4" nadadasar="1=F" biramapembilang="4" biramapenyebut="4">
    <not angka="1" oktaf="0" naikturun="" nilai="1"/>
    <not angka="2" oktaf="0" naikturun="" nilai="0.5"/>
    <not angka="5" oktaf="1" naikturun="/" nilai="0.25"/>
    <not angka="2" oktaf="0" naikturun="\" nilai="0.125"/>
    <not angka="1" oktaf="0" naikturun="" nilai="0.0625"/>
</music>

这可以很容易地解决:
对于“保存到文件”:
 private void saveToolStripMenuItem_Click(object sender, EventArgs e)
 {
     saveFileDialog1.Title = "Save Song File";
     saveFileDialog1.Filter = "Song Files|*.xsong";
     if (saveFileDialog1.ShowDialog() == DialogResult.OK)
     {
         FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create);
         XmlTextWriter w = new XmlTextWriter(fs, Encoding.UTF8);
         w.WriteStartDocument();
         w.WriteStartElement("music");
         w.WriteAttributeString("judul", Program.music.getTitle());
         w.WriteAttributeString("pengarang", Program.music.getAuthor());
         w.WriteAttributeString("tempo", Program.music.getTempo()+"");
         w.WriteAttributeString("birama", Program.music.getBirama());
         w.WriteAttributeString("nadadasar", Program.music.getNadaDasar());
         w.WriteAttributeString("biramapembilang", Program.music.getBiramaPembilang()+"");
         w.WriteAttributeString("biramapenyebut", Program.music.getBiramaPenyebut()+"");

         for (int i = 0; i < listNotasi.Count; i++)
         {
             CNot not = listNotasi[i];
             w.WriteStartElement("not");
             w.WriteAttributeString("angka", not.getNot() + "");
             w.WriteAttributeString("oktaf", not.getOktaf() + "");
             String naikturun="";
             if(not.isTurunSetengah())naikturun="\\";
             else if(not.isNaikSetengah())naikturun="/";
             w.WriteAttributeString("naikturun",naikturun);
             w.WriteAttributeString("nilai", not.getNilaiNot()+"");
             w.WriteEndElement();
         }
         w.WriteEndElement();

         w.Flush();
         fs.Close();
     }

 }

加载文件:

openFileDialog1.Title = "Open Song File";
openFileDialog1.Filter = "Song Files|*.xsong";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
    FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open);
    XmlTextReader r = new XmlTextReader(fs);

    while (r.Read())
    {
        if (r.NodeType == XmlNodeType.Element)
        {
            if (r.Name.ToLower().Equals("music"))
            {
                Program.music = new CMusic(r.GetAttribute("judul"),
                    r.GetAttribute("pengarang"),
                    r.GetAttribute("birama"),
                    Convert.ToInt32(r.GetAttribute("tempo")),
                    r.GetAttribute("nadadasar"),
                    Convert.ToInt32(r.GetAttribute("biramapembilang")),
                    Convert.ToInt32(r.GetAttribute("biramapenyebut")));
            }
            else
                if (r.Name.ToLower().Equals("not"))
                {
                    CNot not = new CNot(Convert.ToInt32(r.GetAttribute("angka")), Convert.ToInt32(r.GetAttribute("oktaf")));
                    if (r.GetAttribute("naikturun").Equals("/"))
                    {
                        not.setNaikSetengah();
                    }
                    else if (r.GetAttribute("naikturun").Equals("\\"))
                    {
                        not.setTurunSetengah();
                    }
                    not.setNilaiNot(Convert.ToSingle(r.GetAttribute("nilai")));
                    listNotasi.Add(not);
                }
        }
        else
            if (r.NodeType == XmlNodeType.Text)
            {
                Console.WriteLine("\tVALUE: " + r.Value);
            }
    }
}

}
}

1

对于简单的事情,我只使用System.XML中找到的XmlDocument / XmlNode / XmlAttribute类和XmlDocument DOM。

它为我生成XML,我只需要将几个项目链接在一起。

然而,在更大的事情上,我使用XML序列化。


1
对于简单案例,我建议看一下XmlOutput,这是一个用于构建Xml的流畅接口。
XmlOutput非常适合使用可读性和可维护性代码创建简单的Xml,并且可以生成有效的Xml。 原始帖子中有一些很好的示例。

-3

如上所述。

我使用stringbuilder.append()。

非常简单明了,然后您可以使用xmldocument.load(stringbuilder对象作为参数)。

您可能会发现自己在append参数中使用string.concat,但这是一种非常直接的方法。


11
除非你忘记正确编码某些内容并且写下了非法的XML。 - Robert Paulson
3
这篇答案备受批评,但基于这个问题,我查看了自己构建XML的一个实现。就我的项目而言,我发现使用StringBuilder构建比使用XDocument/XmlWriter更快,处理时间快10%。但是,对于我的特定项目,我感觉熟悉XML更为舒适。(参考文献:最终XML文件大小约为3.4MB,包含8000多行代码。) - James Skemp
2
我很好奇您是否衡量了应用程序性能(我们正在谈论毫秒级的改进吗?)和应用程序维护(现在您的工程师需要花一个小时熟悉代码才能进行更改吗?)之间的权衡。 - Dan Esparza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接