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

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

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

Ответ 1

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

Использование System.Xml.XmlWriter не приведет к какой-либо проблеме с производительностью при загрузке "дополнительных библиотек".


Причиной использования XML-API является то, что они понимают правила 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", "[email protected]"),
            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

Я бы не использовал 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>[email protected]</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 строк ИЛ не будут заметны.

Ответ 3

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

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

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

Ответ 4

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

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

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

попробуйте следующее:

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

Ответ 5

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

У вас есть looK: StringBuilder vs XmlTextWriter

Ответ 6

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

Ответ 7

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

Ответ 8

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