Как, черт возьми, можно редактировать действительный XML на веб-странице?
-
04-07-2019 - |
Вопрос
Мне нужно запустить быстрый и грязный редактор конфигурации.Поток выглядит примерно так:
Конфигурация (POCO на сервере) сериализуется в XML.
На данный момент XML хорошо сформирован.Конфигурация отправляется на веб-сервер в XElements.
На веб-сервере XML (да, ВСЕ ЭТО) выгружается в текстовую область для редактирования.
Пользователь редактирует XML непосредственно на веб-странице и нажимает «Отправить».
В ответ я получаю измененный текст конфигурации XML.На данный момент ВСЕ escape-последовательности были отменены в процессе их отображения на веб-странице.
Я пытаюсь загрузить строку в объект XML (XmlElement, XElement и т. д.).КАБУМ.
Проблема в том, что сериализация экранирует строки атрибутов, но они теряются при трансляции.
Например, предположим, что у меня есть объект с регулярным выражением.Вот конфигурация веб-сервера:
<Configuration>
<Validator Expression="[^<]" />
</Configuration>
Итак, я поместил это в текстовую область, где для пользователя это выглядит следующим образом:
<Configuration>
<Validator Expression="[^<]" />
</Configuration>
Таким образом, пользователь вносит небольшие изменения и отправляет изменения обратно.На веб-сервере строка ответа выглядит так:
<Configuration>
<Validator Expression="[^<]" />
<Validator Expression="[^&]" />
</Configuration>
Итак, пользователь добавил еще одну штуку-валидатор, и теперь ОБА имеют атрибуты с недопустимыми символами.Если я попытаюсь загрузить это в любой объект XML, он выдаст исключение, поскольку < и & недопустимы в текстовой строке.Я НЕ МОГУ НЕ МОГУ НЕ МОГУ использовать какую-либо функцию кодирования, поскольку она кодирует всю эту чертову штуку:
результат вар = Server.HttpEncode(editedConfig);
приводит к
<Configuration>
<Validator Expression="[^<]" />
<Validator Expression="[^&]" />
</Configuration>
Это НЕдействительный XML.Если я попытаюсь загрузить это в какой-либо XML-элемент, меня ударит падающая наковальня.Я не люблю падающие наковальни.
ИТАК, вопрос остается...Является ли ЕДИНСТВЕННЫЙ способ подготовить эту строку XML для анализа в объект XML - использовать замену регулярных выражений?Есть ли способ «отключить ограничения» при загрузке?Как это обойти???
Один последний ответ, а затем его вики-сайт, так как я не думаю, что существует действительный ответ.
XML, который я помещаю в текстовую область, действителен, экранирован XML.Процесс 1) помещения его в текстовую область 2) отправки клиенту 3) отображения клиенту 4) отправки формы, в которой он находится 5) отправки обратно на сервер и 6) получения значения из формы УДАЛЯЕТ ЛЮБЫЕ ПОБЕГИ.
Позвольте мне сказать это еще раз:Я НИЧЕГО не избегаю.Просто отобразив его в браузере, вы получите результат!
Вещи, над которыми стоит задуматься:Есть ли способ вообще предотвратить это не-побег?Есть ли способ взять почти валидный XML и безопасно «очистить» его?
Теперь за этот вопрос есть награда.Чтобы получить награду, вы демонстрируете, как редактировать ДЕЙСТВИТЕЛЬНЫЙ XML в окне браузера БЕЗ стороннего инструмента с открытым исходным кодом, который не требует от меня использования регулярных выражений для экранирования значений атрибутов вручную, который не требует от пользователей экранировать свои атрибуты, и это не дает сбоя при двустороннем обмене (&amp;etc;)
Решение
Erm & # 8230; & nbsp; Как сериализовать? Обычно сериализатор XML никогда не должен создавать недопустимый XML.
/ РЕДАКТИРОВАТЬ в ответ на ваше обновление: не отображайте неверный XML-код для редактирования пользователем! Вместо этого отобразите правильно экранированный XML в TextBox. Восстановление поврежденного XML - это не весело, и я на самом деле не вижу причин не отображать / редактировать XML в действительной, экранированной форме.
Опять же, я могу спросить: как вы отображаете XML в TextBox? Похоже, вы в какой-то момент намеренно удалили XML.
/ РЕДАКТИРОВАТЬ в ответ на ваш последний комментарий: Ну да, очевидно, поскольку он может содержать HTML. Вам нужно правильно экранировать свой XML перед тем, как записать его на страницу HTML. Под этим я подразумеваю весь XML. Итак, это:
<foo mean-attribute="<">
становится таким:
<foo mean-attribute="&<">
Другие советы
Конечно, когда вы помещаете ссылки на сущности в область текста, они выходят без экранирования. Текстовые зоны не волшебны, вы должны & Убежать; все, что вы вкладываете в них, как и любой другой элемент. Браузеры могут отображать необработанный '& Lt;' в текстовой области, но только потому, что они пытаются исправить ваши ошибки.
Таким образом, если вы помещаете редактируемый XML в текстовое поле, вам нужно один раз экранировать значение атрибута, чтобы сделать его действительным XML, а затем вам нужно снова экранировать весь XML, чтобы сделать его действительным HTML. Окончательный источник, который вы хотите отобразить на странице:
<textarea name="somexml">
<Configuration>
<Validator Expression="[^&lt;]" />
<Validator Expression="[^&amp;]" />
</Configuration>
</textarea>
Вопрос основан на неправильном понимании модели содержимого элемента textarea - средство проверки могло бы сразу решить проблему.
Комментарий ETA: Ну, какая проблема остается? Это проблема на стороне сериализации. Все, что остается, - это снова проанализировать его, и для этого вы должны предположить, что пользователь может создать правильно сформированный XML.
Попытка разобрать некорректно сформированный XML, чтобы допустить такие ошибки, как '<' или '& amp;' неэкранированное значение атрибута является потерей, полностью против того, как должен работать XML. Если вы не можете доверять своим пользователям писать правильно сформированный XML, предоставьте им более простой не-XML интерфейс, такой как простой список разделенных регулярными строками строк регулярного выражения.
Как вы говорите, обычный сериализатор должен избежать всего за вас.
Проблема в текстовом блоке:вам нужно самостоятельно обрабатывать все, что проходит через текстовый блок.
Вы можете попробовать HttpUtility.HtmlEncode(), но я думаю, что самый простой способ — просто поместить все, что вы передаете через текстовый блок, в раздел CDATA.
Обычно, конечно, я хотел бы, чтобы все было правильно экранировано, а не полагалось на «костыль» CDATA, но я также хотел бы использовать встроенные инструменты для экранирования.Я думаю, что для чего-то, что редактируется пользователем в «спящем» состоянии, лучше всего подойдет CDATA.
Также см. этот более ранний вопрос:
Лучший способ кодирования текстовых данных для XML
Обновлять
Основываясь на комментарии к другому ответу, я понял, что вы показываете пользователям разметку, а не только содержимое.Парсеры XML очень разборчивы.Я думаю, лучшее, что вы могли бы сделать в этом случае, это проверить правильность формата. до принятие отредактированного XML.
Возможно, попробуйте автоматически исправить определенные виды ошибок (например, неправильные амперсанды из моего связанного вопроса), но затем получите номер строки и номер столбца первой ошибки проверки из синтаксического анализатора .Net xml и используйте его, чтобы показать пользователям, в чем заключается их ошибка, пока они дают вам что-то приемлемое.Бонусные баллы, если вы также проверите схему.
Вы можете взглянуть на что-то вроде TinyMCE , которое позволяет редактировать html в расширенном тексте. коробка. Если вы не можете настроить его так, чтобы он делал именно то, что вы хотите, вы можете использовать его как вдохновение.
Примечание:Firefox (в моем тесте) не выполняет экранирование в текстовых областях, как вы описываете.В частности, этот код:
<textarea cols="80" rows="10" id="1"></textarea>
<script>
elem = document.getElementById("1");
elem.value = '\
<Configuration>\n\
<Validator Expression="[^<]" />\n\
</Configuration>\
'
alert(elem.value);
</script>
Уведомляется и отображается пользователю неизменный, как:
<Configuration>
<Validator Expression="[^<]" />
</Configuration>
Так что, возможно, одно (нежизнеспособное?) решение — использовать Firefox для ваших пользователей.
Кажется, были раскрыты две части вашего вопроса:
1 XML, который вы отображаете, становится неэкранированным.
Например, "<
" не экранируется как "<".Но поскольку «<» также не экранируется как «<», информация теряется, и вы не можете получить ее обратно.
Одно из решений - избежать всех "&
"персонажи, так что"<
"становится"&lt;
".Тогда это не будет экранировано текстовым полем как "<
".Когда вы перечитаете его, все будет так, как было изначально.(Я предполагаю, что текстовая область действительно меняет строку, но Firefox ведет себя не так, как вы сообщаете, поэтому я не могу это проверить)
Другое решение (я думаю, уже упомянутое) — создать/купить/заимствовать пользовательскую текстовую область (неплохо, если просто, но есть все клавиши редактирования, ctrl-C, ctrl-shift-left и так далее).
2 Вы бы хотели, чтобы пользователям не приходилось беспокоиться о побеге.
Вы находитесь в беглом аду:
Замена регулярного выражения в основном будет работать...но как вы можете надежно определить конечную кавычку ("), когда пользователь может (законно, в рамках указанных вами условий) ввести:
<Configuration>
<Validator Expression="[^"<]" />
</Configuration>
Глядя на это с точки зрения синтаксиса регулярного выражения, он также не может определить, является ли последнее "частью регулярного выражения или его концом.Синтаксис регулярных выражений обычно решает эту проблему с помощью явного терминатора, например:
/[^"<]/
Если пользователи использовали этот синтаксис (с терминатором), а вы написали для него синтаксический анализатор, то вы могли бы определить, когда регулярное выражение закончилось, и, следовательно, следующий символ " является не частью регулярного выражения, а частью XML, и поэтому какие части необходимо экранировать.Я не говорю, что вам следует это делать!Я говорю, что это теоретически возможно.Это довольно далеко не быстро и грязно.
КСТАТИ:Та же проблема возникает с текстом внутри элемента.Следующее является законным в рамках указанных вами условий, но имеет те же проблемы с анализом:
<Configuration>
<Expression></Expression></Expression>
</Configuration>
Основное правило синтаксиса, допускающее «любой текст», заключается в том, что разделитель должен избежать (например," или <), чтобы можно было распознать конец.Большая часть синтаксиса также избегает множества других вещей для удобства/неудобства.(РЕДАКТИРОВАТЬ ему понадобится escape для самого escape-символа:для XML это "&
", который в буквальном смысле экранируется как "&
"Для регулярных выражений это стиль C/unix"\
", который в буквальном смысле экранируется как "\\
").
Вставьте синтаксисы, и вы попадете в ад.
Одним из простых решений для вас является сообщить своим пользователям:это быстрый и грязный редактор конфигурации, чтобы у вас не было никаких причудливых фраз «не нужно бежать» mamby-pamby:
- Список персонажей и побегов далее
в текстовую область, например:"<" как
"
<
". - Для XML это не будет Подтвердите, покажите им список еще раз.
Оглядываясь назад, я вижу боббинс дал тот же самый основной ответ до меня.
Вставка CDATA вокруг всего текста даст вам еще один механизм escape, который (1) избавит пользователей от необходимости экранирования вручную и (2) позволит тексту, который был автоматически экранирован текстовой областью, правильно прочитан.
<Configuration>
<Validator Expression="<![CDATA[ [^<] ]]>" />
</Configuration>
:-)
Этот специальный символ — «<» — следует заменить другими символами, чтобы ваш XML был действительным.Проверьте эту ссылку на наличие специальных символов XML:
http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
Попробуйте также закодировать содержимое TextBlock перед отправкой его в десериализатор:
HttpServerUtility utility = new HttpServerUtility();
string encodedText = utility.HtmlEncode(text);
Это действительно мой единственный вариант? Разве это не достаточно распространенная проблема, что у нее есть решение где-то в рамках?
private string EscapeAttributes(string configuration)
{
var lt = @"(?<=\w+\s*=\s*""[^""]*)<(?=[^""]*"")";
configuration = Regex.Replace(configuration, lt, "<");
return configuration;
}
(правка: удалена замена амперсанда, так как это вызывает проблемы с перекруткой)