Использование StringBuilder для записи XML в порядке?

Он чувствует себя грязным. Но, возможно, это не так... можно ли использовать StringBuilder для записи XML? Мой инстинкт говорит: "хотя это кажется неправильным, это, вероятно, довольно чертовски эффективно, потому что он не загружает дополнительные библиотеки и накладные расходы он не делает все, что вызывает дополнительный метод XmlWriter.- Кроме того, кажется, что в целом это просто меньше кода. В чем преимущество XmlWriter?

вот как это выглядит. Я создаю XML-документ OpenSearch на основе домен вы приходите от.

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 лет Я понял, что я хотел сказать, и полностью не смог сказать: в чем преимущество gobs кода с использованием классов XML для создания этого файла, а не просто с помощью строк? Есть такой? Это хуже, чем (например) пример Джона Сондера?

я использовал метод Джима Шуберта, предпочитая "я могу прочитать это, и это имеет смысл", а не соперничать за "правильность". Я рад, что сделал это. Есть в Примере Джона Сондера не было ничего плохого, но я чувствовал, что это так.--12-->путь властный для того, что я пытался достичь. Прагматизм? Возможно.

8 ответов


Это очень неправильно. Используйте один из API .NET, которые понимают XML для записи XML.

С помощью System.Xml.XmlWriter не вызовет проблем с производительностью, загрузив "любые дополнительные библиотеки".


причина использования API XML заключается в том, что они понимают правила XML. Например, они будут знать набор символов, которые должны быть процитированы внутри элемента, и другой набор, который должен быть процитирован внутри атрибута.

Это не может быть проблемой в вашем случае: может быть, вы уверены, что domain не будет иметь каких-либо символов, которые необходимо будет процитировать. В любой более широкой ситуации лучше позволить XML-API делать XML-что они знают, как это сделать, поэтому вам не нужно делать это самостоятельно.


вот пример того, как легко создать допустимый XML с помощью LINQ to 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
}

Я бы не использовал 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 (), затем вызовите этот метод. Этот Строка.Вызов формата генерирует только 17 строк кода IL, по сравнению со StringBuilder, генерирующим 8 строк кода ctor, а затем 6 строк для каждого вызова добавления. Хотя, с сегодняшней технологией, дополнительные 50 линий IL не будут заметны.


Ну, это дело тонкое. Как и все другие оптимизации в жизни, вы нарушаете границы абстракции и платите за это цену, чтобы получить эффективность.

по моему опыту, это действительно значительно быстрее, не из-за загрузки библиотек, конечно (если что-нибудь, это сделает его медленнее), но потому, что он экономит на строковых распределениях. Не помню точно, насколько быстрее. Измерение его с помощью профилировщика будет трудно, потому что вы также экономите на сборе мусора затраты.

но, не вините меня, когда вам придется иметь дело с кодировками и побегом, и черт знает что еще, и не забудьте внимательно прочитать стандарт XML, прежде чем получать эти XMLs в любом месте.


пожалуйста, не используйте StringBuilder. Любой, кто говорит вам, что это значительно быстрее, не представил вам никаких реальных данных. Разница в скорости несущественна, и у вас будет кошмар обслуживания впереди вас.

посмотреть: то StringBuilder против xmltextwriter с


Ну, нет ничего плохого в ручном написании XML-строк как таковых, но это гораздо более подвержено ошибкам. Если у вас нет веской причины для этого (то есть вы измерили и обнаружили, что форматирование XML является узким местом), я бы использовал классы XML вместо этого. Вы сэкономите много времени на отладке и разработке.

в стороне, почему вы смешиваете динамические строковые операции с вызовами компоновщика? Вместо:

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

попробовать это:

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

ваше чутье не так. Независимо от того, пишете ли вы XML вручную или используете XmlWriter, наиболее эффективным способом отправки XML в HttpResponse будет добавление текста непосредственно в ответ. Построение всей строки, а затем отправка ее тратит ресурсы.


будут ли переменные домена когда-либо возвращать символы "&" или другой символ, который должен быть закодирован? Возможно, вы захотите потратить время на оборонительное программирование и проверку ввода.


вы можете создать строго типизированный объект и использовать классы XmlSerialization для создания xml-данных