使用StringBuilder编写XML好吗?

时间:2010-04-09 20:42:59

标签: c# asp.net xml stringbuilder

感觉很脏。但也许它不是......使用StringBuilder编写XML是否可以?我的直觉说:“虽然这感觉不对,但它可能非常高效,因为它没有加载额外的库和开销它没有做任何额外的方法调用XmlWriter调用。”它似乎只是一般的代码更少。 XmlWriter有什么好处?

这就是它的样子。我正在根据您来自的域构建OpenSearch XML文档。

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/xml";

    string domain = WebUtils.ReturnParsedSourceUrl(null); //returns something like www.sample.com
    string cachedChan = context.Cache[domain + "_opensearchdescription"] as String;

    if (cachedChan == null)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.Append("<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:moz=\"http://www.mozilla.org/2006/browser/search/\">");
        sb.Append("    <ShortName>Search</ShortName>");
        sb.Append("    <Description>Use " + domain + " to search.</Description>");
        sb.Append("    <Contact>contact@sample.com</Contact>");
        sb.Append("    <Url type=\"text/html\" method=\"get\" template=\"http://" + domain + "/Search.aspx?q={searchTerms}\" />");
        sb.Append("    <moz:SearchForm>http://" + domain + "/Search.aspx</moz:SearchForm>");
        sb.Append("    <Image height=\"16\" width=\"16\" type=\"image/x-icon\">http://" + domain + "/favicon.ico</Image>");
        sb.Append("</OpenSearchDescription>");

        cachedChan = sb.ToString();

        context.Cache.Insert(domain + "_opensearchdescription", cachedChan, null, DateTime.Now.AddDays(14), TimeSpan.Zero);
    }

    context.Response.Write(cachedChan);
}

跟进,约2年后 我意识到我的意思,完全没有说出来:使用XML类生成这个文件的代码的优点是什么,而不仅仅是使用字符串?有吗?这比(例如)John Saunder的例子更糟糕吗?

我使用了吉姆舒伯特的方法,选择'我能读懂它并且它有意义'而不是争夺'正确性'。我很高兴我做到了。 John Saunder的例子没有任何问题 - 但我觉得方式对我想要完成的事情感到咄咄逼人。实用主义?也许

8 个答案:

答案 0 :(得分:15)

这是非常错误的。使用其中一个了解XML的.NET API来编写XML。

使用System.Xml.XmlWriter加载“任何额外的库”不会导致任何性能问题。


使用XML API的原因是他们理解XML的规则。例如,他们将知道需要在元素内引用的字符集,以及需要在属性中引用的不同集合。

这可能不是您的问题:也许您确定domain中不会有任何需要引用的字符。在任何更广泛的情况下,最好让XML API执行XML - 他们知道如何操作 - 因此您不必自己完成。


以下是使用LINQ to XML生成有效XML的简单示例:

public static string MakeXml()
{
    XNamespace xmlns = "http://a9.com/-/spec/opensearch/1.1/";
    XNamespace moz = "http://www.mozilla.org/2006/browser/search/";
    string domain = "http://localhost";
    string searchTerms = "abc";
    var doc = new XDocument(
        new XDeclaration("1.0", "UTF-8", "yes"),
        new XElement(
            xmlns + "OpenSearchDescription",
            new XElement(xmlns + "ShortName", "Search"),
            new XElement(
                xmlns + "Description",
                String.Format("Use {0} to search.", domain)),
            new XElement(xmlns + "Contact", "contact@sample.com"),
            new XElement(
                xmlns + "Url",
                new XAttribute("type", "text/html"),
                new XAttribute("method", "get"),
                new XAttribute(
                    "template",
                    String.Format(
                        "http://{0}/Search.aspx?q={1}",
                        domain,
                        searchTerms))),
            new XElement(
                moz + "SearchForm",
                String.Format("http://{0}/Search.aspx", domain)),
            new XElement(
                xmlns + "Image",
                new XAttribute("height", 16),
                new XAttribute("width", 16),
                new XAttribute("type", "image/x-icon"),
                String.Format("http://{0}/favicon.ico", domain))));
    return doc.ToString(); // If you _must_ have a string
}

答案 1 :(得分:2)

我不会使用StringBuilder,因为你必须为每一行调用Append方法。您可以使用XmlWriter,这不会影响性能。

您可以通过执行以下操作来减少生成的IL代码量:

private const string XML_TEMPLATE = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:moz=\"http://www.mozilla.org/2006/browser/search/\">
    <ShortName>Search</ShortName>
    <Description>Use {0} to search.</Description>
    <Contact>contact@sample.com</Contact>
    <Url type=\"text/html\" method=\"get\" template=\"http://{0}/Search.aspx?q={searchTerms}\" />
    <moz:SearchForm>http://{0}/Search.aspx</moz:SearchForm>
    <Image height=\"16\" width=\"16\" type=\"image/x-icon\">http://{0}/favicon.ico</Image>
</OpenSearchDescription>";

在你的方法中:

    if (cachedChan == null)
    {
        cachedChan = String.Format(XML_TEMPLATE, domain);

        context.Cache.Insert(domain + "_opensearchdescription", 
               cachedChan, null, DateTime.Now.AddDays(14), TimeSpan.Zero);
    }

这应该适合你,因为你现在拥有的方法必须为每个StringBuilder.Append()调用创建一个新字符串,然后调用该方法。 String.Format调用只生成17行IL代码,而StringBuilder生成8行代码,然后每行调用6行。虽然,利用今天的技术,额外的50行IL不会引人注意。

答案 2 :(得分:1)

嗯,这很微妙。像生活中的所有其他优化一样,为了提高效率,你打破抽象界限并为此付出代价。

根据我的经验,它确实快得多,不是因为加载库当然(如果有的话,会使它变慢),而是因为它节省了字符串分配。我不记得到底有多快,抱歉。使用分析器测量它将很难,因为您还节省了垃圾收集成本。

但是,当你不得不处理编码和逃避时,不要怪我,并且知道还有什么,并且在将这些XML带到任何地方之前,请记住仔细阅读XML标准。

答案 3 :(得分:1)

嗯,手动编写XML字符串本身并没有错,但它更容易出错。除非你有令人信服的性能原因(也就是说,你已经测量并发现XML格式是瓶颈),否则我会使用XML类。您将在调试和开发时节省很多。

顺便说一下,为什么要将动态字符串操作与构建器调用混合使用?而不是:

sb.Append("    <Description>Use " + domain + " to search.</Description>"); 

试试这个:

sb.Append("    <Description>Use ").Append(domain).Append(" to search.</Description>");

答案 4 :(得分:1)

请不要使用StringBuilder。任何告诉你它快得多的人都没有向你展示任何真实的数据。速度的差异是无关紧要的,你将面临一场噩梦般的维护。

有一个looK:StringBuilder vs XmlTextWriter

答案 5 :(得分:0)

你的直觉是错的。无论您是手写XML还是使用XmlWriter,将XML发送到HttpResponse的最有效方式都是将文本直接附加到Response。构建整个字符串然后发送它会浪费资源。

答案 6 :(得分:0)

域变量是否会返回“&amp;”字符或需要编码的其他字符?您可能希望花时间进行防御性编程并验证您的输入。

答案 7 :(得分:-1)

您可以创建强类型对象并使用XmlSerialization类生成xml数据