0

Надо сохранить в XML текст. Например:

<p>"Hello">'hello'

Чтобы получить результат:

<p>&quot;Hello&quot;&gt;&apos;hello&apos;

Текст XML не может содержать спецсимволов:

" & < > '

Их надо заменять эквивалентами:

&quot; &amp; &lt; &gt; &apos;

Как заменить спецсимволы, но оставить нетронутыми теги HTML?

Вариант, который предлагают как дубликат этого вопроса, не возвращает нужный результат.

var encoded = HttpUtility.HtmlEncode("<p>\"Hello\">'hello'</p>");
  • https://ru.stackoverflow.com/a/470236/220553 – EvgeniyZ Jun 22 '18 at 08:00
  • @defaultlocale ни разу не дубликат: там asp.net используется, а тут - xml формируется – Pavel Mayorov Jun 22 '18 at 08:49
  • @PavelMayorov Дубликат в том смысле, что ответ подойдет и здесь. System.Web можно подключить к не ASP проекту. Если ответ по каким-то причинам не подходит, то стоит уточнить по каким именно, чтобы отвечающие не повторяли ответ. – default locale Jun 22 '18 at 08:55
  • @defaultlocale нет смысла. XML же обычно формируется не строкой, а через DOM, Linq2Xml или хотя бы XmlWriter. Все три варианта умеют делать экранирование. Фактически, при работе с XML в C# сложнее убрать экранирование чем добавить его. – Pavel Mayorov Jun 22 '18 at 08:56
  • @defaultlocale кроме того, не забывайте: на закрытый вопрос нельзя дать нового ответа. То есть отмечая вопрос про XML как дубликат вопроса про asp.net вы запрещаете другим давать xml-специфичные ответы. А это неправильно. – Pavel Mayorov Jun 22 '18 at 08:58
  • @PavelMayorov да, но сейчас вопрос о замене символов в тексте (строке). В вопросе нет ничего про формирование XML. Если автор его сформировал сам (не факт) и вопрос о включении экранирования, то в вопросе нужно рассказать об этом. – default locale Jun 22 '18 at 09:06
  • @defaultlocale первая строчка: "Надо сохранить в XML текст." – Pavel Mayorov Jun 22 '18 at 09:07
  • @PavelMayorov заголовок «Заменить спецсимволы, оставить теги HTML» :) Я не вижу в вопросе ничего про формирование XML. Если Вы видите и представляете XML-специфичный ответ, то предлагаю Вам его написать. – default locale Jun 22 '18 at 09:20
  • 1
    Вот, кстати, "оставить теги HTML" - отдельная проблема, которая там куда вы дали ссылку не раскрыта совершенно... – Pavel Mayorov Jun 22 '18 at 09:23
  • @defaultlocale я его как раз и писал пока вы спорили... Попробуйте найти куда там можно засунуть HttpUtility.HtmlEncode :-) – Pavel Mayorov Jun 22 '18 at 09:36
  • @PavelMayorov вижу, поставил плюс. Отзываю голос, раз уж вопрос получил столь всесторонний ответ. Остаюсь при мнении что вопрос требует уточнения и частично был отвечен ранее. Ваш пост отвечает как минимум на три разных вопроса. – default locale Jun 22 '18 at 09:46
  • 1
    Возможный дубликат вопроса: Как заменить символы !@#$%^& на простые? – 0xdb Jun 22 '18 at 23:46
  • Не дубликат! прежде чем редактировать - проверьте результат из другой темы с тем, что мне надо получить! – Aleksandr H. Jun 23 '18 at 19:08

1 Answers1

2

Проще всего было бы если бы не требовалось сохранять тэгов. Как известно, есть 3 API для формирования XML - DOM, Linq 2 XML и XmlWriter. Все три умеют автоматически экранировать все строки (и автоматически же убирать экранирование при чтении XML):

string text = "\"Hello\">'hello'";

/* XML DOM */
XmlNode node = ...;
node.InnerText = text;

/* Linq 2 XML */
XElement node = ...;
node.Value = text;
node.Add(text); // или так

/* XmlWriter  */
XmlWriter writer = ...;
writer.WriteValue(text);

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

Вторая проблема заключается в том, что HTML-тэги нужно еще как-то отделить от текста. Проще всего если вы их формируете программно: в таком случае их можно просто изначально не смешивать:

string text = "\"Hello\">'hello'";

/* XML DOM */
XmlDocument doc = ...;
XmlElement node = ...;

var p = doc.CreateElement("p");
p.InnerText = text;
node.AppendChild(p);

node.AppendChild(doc.CreateElement("p")).InnerText = text; // или вот так еще можно

/* Linq 2 XML */
XElement node = ...;
node.Add(new XElement("p", text));

/* XmlWriter  */
XmlWriter writer = ...;
writer.WriteStartElement("p");
writer.WriteValue(text);
writer.WriteEndElement();

Если же разделить разметку и текст еще на этапе формирования не получается - придется использовать HTML-парсер. Например, Html Agility Pack:

var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml("<p>\"Hello\">'hello'");
htmlDoc.OptionOutputAsXml = true;

/* XmlWriter */
XmlWriter writer = ...;
htmlDoc.Save(writer);

/* Linq 2 XML */
XElement node = ...;
using (var writer = node.CreateWriter())
    htmlDoc.Save(writer);

/* XMl DOM */
XmlElement node = ...;

var w = new StringWriter();
htmlDoc.Save(w);
node.InnerXml = w.ToString();
Pavel Mayorov
  • 58,537
  • на вход подается именно строка <p>"Hello">'hello' которую, после приведения к нужному виду, я через XmlCDataSection добавлю в xml. – Aleksandr H. Jun 22 '18 at 10:00
  • @AleksandrH. а в чем в таком случае проблема-то? – Pavel Mayorov Jun 22 '18 at 10:02
  • Использовав Ваш пример, получил <?xml version="1.0" encoding="koi8-r"?><p>&quot;Hello&quot;&gt;'hello'</p> , а хотел <p>&quot;Hello&quot;&gt;&apos;hello&apos;</p> – Aleksandr H. Jun 22 '18 at 10:14
  • @AleksandrH. а в чем смысл? Чем вас апострофы не устраивают? – Pavel Mayorov Jun 22 '18 at 10:14
  • такое требование к формированию xml файла. Решение: дальше через replace убрать обявление xml и заменить апострофы? – Aleksandr H. Jun 22 '18 at 10:19
  • @AleksandrH. объявление xml убрать если будете сохранять XML через XmlWriter с настройкой OmitXmlDeclaration – Pavel Mayorov Jun 22 '18 at 10:20
  • @AleksandrH. ну а апострофы можете и правда заменять регуляркой. Но лучше объяснить что это требование ничем не обосновано. – Pavel Mayorov Jun 22 '18 at 10:21