Использование 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-данных