Хорошо ли использовать StringBuilder для написания XML? - PullRequest
11 голосов
/ 10 апреля 2010

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

Я использовал метод Джима Шуберта, выбрав «я могу прочитать это, и это имеет смысл», а не бороться за «правильность». Я рад, что сделал. Нет ничего плохого в примере Джона Сандера - но я чувствовал, что это было способом властным для того, чего я пытался достичь. Прагматизм? Может быть.

Ответы [ 8 ]

15 голосов
/ 10 апреля 2010

Это очень неправильно. Используйте один из .NET API, которые понимают 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
}
2 голосов
/ 10 апреля 2010

Я бы не стал использовать 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, затем 6 строк для каждого вызова Append. Хотя при современных технологиях дополнительные 50 линий IL не будут заметны.

1 голос
/ 10 апреля 2010

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

Иметь знак: StringBuilder против XmlTextWriter

1 голос
/ 10 апреля 2010

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

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

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

попробуйте это:

sb.Append("    <Description>Use ").Append(domain).Append(" to search.</Description>");
1 голос
/ 10 апреля 2010

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

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

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

0 голосов
/ 10 апреля 2010

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

0 голосов
/ 10 апреля 2010

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

0 голосов
/ 10 апреля 2010

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

...