使用字符串拼接构建XML有什么不好的地方?

25
在主题你最讨厌程序员的哪些无知行为?中,有一个回答获得了大量赞同: 使用字符串拼接构建XML的程序员。 我的问题是,为什么通过字符串拼接(例如在C#中使用StringBuilder)构建XML是不好的?
我以前做过几次这样的事情,因为对于我正在处理的数据结构/对象来说,这有时是最快的方法。到目前为止,我想出了一些原因,说明这不是最佳方法,但我是否忽略了什么?为什么应该避免这种方法?
  1. 我能想到的最大原因可能是你需要手动转义字符串,而大多数新程序员(甚至一些经验丰富的程序员)会忘记这一点。当他们测试时,它将非常好用,但是当有人在他们的输入中抛出 & 符号时,他们的应用程序将"随机"失败。好吧,我同意这个观点,但很容易避免这个问题(其中一个方法是SecurityElement.Escape)。
  2. 当我这样做时,我通常会省略XML声明(即<?xml version="1.0"?>)。这有害吗?
  3. 性能损失?如果您坚持使用正确的字符串连接方法(即StringBuilder),是否有什么需要担心的?可以想象,像XmlWriter这样的类也需要进行一些字符串操作...
  4. 有更优雅的生成XML的方式,例如使用XmlSerializer自动序列化/反序列化您的类。好的,我同意。C#有许多有用的类可以做到这一点,但有时我不想为写日志文件之类的东西创建一个类。这只是我懒惰吗?如果我做一些"真正的"事情,这是我处理XML的首选方法。

附注:由于管理原因,本帖顶部引用的链接已被从 Stack Overflow 中删除。 - T.M.
12个回答

30

您可能会得到无效的XML,但直到再次解析它时才会发现 - 然后就为时已晚了。我是通过吸取教训学习这个经验的。


+1 - 经常是使用损坏的 XML 的消费者被留下来尝试找到解决损坏问题的方法。这就是为什么这被称为“个人恶习”的原因! - Stephen C
+1 - 我需要解析一些实体为数字的“XML”文件,这真是让人头疼。 - Rob

15

我认为可读性、灵活性和可扩展性是重要因素。考虑下面的 Linq-to-Xml 代码片段:

XDocument doc = new XDocument(new XDeclaration("1.0","UTF-8","yes"),
   new XElement("products", from p in collection
    select new XElement("product",
        new XAttribute("guid", p.ProductId), 
        new XAttribute("title", p.Title),
        new XAttribute("version", p.Version))));

你能找到比这更简单的方法吗?我可以通过添加几行代码,将其输出到浏览器,保存到文档中,添加属性/元素等等... 我可以轻松地完成几乎所有事情。


5
在创建一个大的文件时,可能会像在 Lisp 程序中一样有很多括号,但我不得不承认这也是我做事情的方式。 - Gregory Higley
这就是所谓的Linq-to-Xml!哇塞。 - Anton Tykhyy
@Gregory Higley:如果你使用了 StringBuilder,你会有很多的 < 和 >,或许这就是另一种 Lisp? - user7116
@sixlettervariables:我听说这被称为“尖括号汤”。 - Gregory Higley

6

实际上,我发现字符串拼接的最大问题不是第一次正确使用它,而是在代码维护期间保持正确性。很多时候,一个完美编写的使用字符串拼接的XML代码被更新以满足新需求,但字符串拼接代码却太脆弱了。

只要备选方案是XML序列化和XmlDocument,我可以看到支持字符串拼接的简单性论点。然而,自从XDocument等出现以来,就没有理由再使用字符串拼接来构建XML了。请参见Sander的答案,了解编写XML的最佳方法。

XDocument的另一个好处是,XML实际上是一个相当复杂的标准,大多数程序员根本不理解它。我目前正在处理一位向我发送“XML”的人,其中包括未引用的属性值、缺少结束标记、不正确的大小写敏感度和错误的转义。但因为IE接受它(作为HTML),所以一定是对的!哎...无论如何,重点是字符串拼接让你写任何内容,但XDocument将强制执行符合标准的XML。


6

我在2006年写了一篇博客文章抱怨用字符串拼接生成的XML; 简单地说,如果一个XML文档无法验证(编码问题,命名空间问题等),它不是XML,也不能被视为XML。

我曾经看到过多个与XML文档相关的问题,这些问题可以直接归因于使用字符串拼接手动生成XML文档,几乎总是围绕正确使用编码的问题。

请问您自己,我当前正在使用哪个字符集来编码我的文档('ascii7'、'ibm850'、'iso-8859-1'等)?如果我将一个UTF-16字符串值写入手动声明为'ibm850'的XML文档中会发生什么?

考虑到.NET中对XML的支持非常丰富,特别是使用XmlDocument和现在的XDocument,我认为必须有一个非常有力的理由才能使用这些库而改用基本的字符串拼接。


5
我认为问题在于您没有将XML文件视为逻辑数据存储方式,而是仅仅把它当做一个简单的文本文件来写字符串。虽然那些库可以为您进行字符串操作,但读/写XML应该类似于将数据保存到数据库或类似的逻辑存储中。

3
如果您只需要简单的XML,那么没问题。但是,当XML变得更大或更复杂时,字符串连接的可维护性会遇到问题。您可以选择在开发阶段或维护阶段付出代价,但历史表明,维护通常更加昂贵,因此任何使其更容易的方法都是值得的。

2

你需要手动转义字符串。没错,但这就是全部吗?当你构建XML字符串时,你可以将XML规范放在桌子上并反复检查,以确保考虑了每种可能的角落情况。或者,你可以使用一个封装了这些知识的库...


你能再详细解释一下吗?除了像&、<、>、"和'这些特殊字符之外,还有什么其他的陷阱呢?难道只是正确嵌套标签吗?我还漏掉了什么? - wsanville
@wsanville:与[[CDATA]]、Unicode、命名空间、模式、处理指令有关的任何内容。 - Craig Trader
4
@wsanville: <!-- 你知道吗--这个注释不是有效的XML语法 --> - dtb

2

另一个不利于使用字符串拼接的因素是,当读取代码时,数据的分层结构不清晰。例如,在@Sander的Linq-to-XML示例中,很明显可以知道“product”元素属于哪个父元素,“title”属性应用于哪个元素等。


1

正如你所说,使用字符串拼接构建XML是很尴尬的,特别是现在有了XML linq,它允许简单地构建XML图形并正确获取命名空间等。

显然,上下文和使用方式很重要,例如在日志记录示例中,string.Format可能是完全可接受的。

但是,在处理复杂的XML图形时,人们经常忽略这些替代方案,只使用StringBuilder。


1

主要原因是DRY:不要重复自己。

如果您使用字符串连接来处理XML,那么您将不断重复保持字符串有效的XML文档所需的函数。所有验证都将被重复或不存在。最好依赖于一个包含XML验证的类。


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