11

感觉很脏 但也许不是……使用 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 类生成此文件的代码块与仅使用字符串相比有什么好处?有吗?这比(例如)约翰桑德的例子更糟糕吗?

我使用了吉姆舒伯特的方法,选择“我能读懂这个并且它是有道理的”而不是争夺“正确性”。我很高兴我做到了。约翰桑德的例子并没有错——但我觉得这对我想要完成的事情来说太霸道了实用主义?也许。

4

8 回答 8

15

这是非常错误的。使用理解 XML 的 .NET API 之一来编写 XML。

通过加载“任何额外的库”,使用 aSystem.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
}
于 2010-04-09T20:45:27.453 回答
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 行 ctor 代码,然后每次 Append 调用生成 6 行。虽然,使用今天的技术,额外的 50 行 IL 不会引起注意。

于 2010-04-09T20:56:53.807 回答
1

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

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

但是,当您必须处理编码和转义时,不要责怪我,地狱知道还有什么,记住在将这些 XML 发布到任何地方之前仔细阅读 XML 标准。

于 2010-04-09T20:47:11.207 回答
1

好吧,手动编写 XML 字符串本身并没有什么问题,但它更容易出错。除非您有一个令人信服的性能理由来执行此操作(也就是说,您已经测量并发现 XML 格式是一个瓶颈),否则我将使用 XML 类。您将节省大量调试和开发时间。

顺便说一句,为什么要将动态字符串操作与构建器调用混合在一起?代替:

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

试试这个:

sb.Append("    <Description>Use ").Append(domain).Append(" to search.</Description>");
于 2010-04-09T20:58:16.223 回答
1

请不要使用 StringBuilder。任何告诉您它明显更快的人都没有向您提供任何真实数据。速度上的差异无关紧要,您将面临维护的噩梦。

看看:StringBuilder vs XmlTextWriter

于 2010-04-09T21:00:49.147 回答
0

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

于 2010-04-09T20:48:02.397 回答
0

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

于 2010-04-09T20:58:32.227 回答
-1

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

于 2010-04-09T20:47:26.377 回答