Как, черт возьми, можно редактировать действительный XML на веб-странице?

StackOverflow https://stackoverflow.com/questions/244285

Вопрос

Мне нужно запустить быстрый и грязный редактор конфигурации.Поток выглядит примерно так:

Конфигурация (POCO на сервере) сериализуется в XML.
На данный момент XML хорошо сформирован.Конфигурация отправляется на веб-сервер в XElements.
На веб-сервере XML (да, ВСЕ ЭТО) выгружается в текстовую область для редактирования.
Пользователь редактирует XML непосредственно на веб-странице и нажимает «Отправить».
В ответ я получаю измененный текст конфигурации XML.На данный момент ВСЕ escape-последовательности были отменены в процессе их отображения на веб-странице.
Я пытаюсь загрузить строку в объект XML (XmlElement, XElement и т. д.).КАБУМ.

Проблема в том, что сериализация экранирует строки атрибутов, но они теряются при трансляции.

Например, предположим, что у меня есть объект с регулярным выражением.Вот конфигурация веб-сервера:

<Configuration>
  <Validator Expression="[^&lt;]" />
</Configuration>

Итак, я поместил это в текстовую область, где для пользователя это выглядит следующим образом:

<Configuration>
  <Validator Expression="[^<]" />
</Configuration>

Таким образом, пользователь вносит небольшие изменения и отправляет изменения обратно.На веб-сервере строка ответа выглядит так:

<Configuration>
  <Validator Expression="[^<]" />
  <Validator Expression="[^&]" />
</Configuration>

Итак, пользователь добавил еще одну штуку-валидатор, и теперь ОБА имеют атрибуты с недопустимыми символами.Если я попытаюсь загрузить это в любой объект XML, он выдаст исключение, поскольку < и & недопустимы в текстовой строке.Я НЕ МОГУ НЕ МОГУ НЕ МОГУ использовать какую-либо функцию кодирования, поскольку она кодирует всю эту чертову штуку:

результат вар = Server.HttpEncode(editedConfig);

приводит к

&lt;Configuration&gt;
  &lt;Validator Expression="[^&lt;]" /&gt;
  &lt;Validator Expression="[^&amp;]" /&gt;
&lt;/Configuration&gt;

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

ИТАК, вопрос остается...Является ли ЕДИНСТВЕННЫЙ способ подготовить эту строку XML для анализа в объект XML - использовать замену регулярных выражений?Есть ли способ «отключить ограничения» при загрузке?Как это обойти???


Один последний ответ, а затем его вики-сайт, так как я не думаю, что существует действительный ответ.

XML, который я помещаю в текстовую область, действителен, экранирован XML.Процесс 1) помещения его в текстовую область 2) отправки клиенту 3) отображения клиенту 4) отправки формы, в которой он находится 5) отправки обратно на сервер и 6) получения значения из формы УДАЛЯЕТ ЛЮБЫЕ ПОБЕГИ.

Позвольте мне сказать это еще раз:Я НИЧЕГО не избегаю.Просто отобразив его в браузере, вы получите результат!

Вещи, над которыми стоит задуматься:Есть ли способ вообще предотвратить это не-побег?Есть ли способ взять почти валидный XML и безопасно «очистить» его?


Теперь за этот вопрос есть награда.Чтобы получить награду, вы демонстрируете, как редактировать ДЕЙСТВИТЕЛЬНЫЙ XML в окне браузера БЕЗ стороннего инструмента с открытым исходным кодом, который не требует от меня использования регулярных выражений для экранирования значений атрибутов вручную, который не требует от пользователей экранировать свои атрибуты, и это не дает сбоя при двустороннем обмене (&amp;amp;etc;)

Это было полезно?

Решение

Erm & # 8230; & nbsp; Как сериализовать? Обычно сериализатор XML никогда не должен создавать недопустимый XML.

/ РЕДАКТИРОВАТЬ в ответ на ваше обновление: не отображайте неверный XML-код для редактирования пользователем! Вместо этого отобразите правильно экранированный XML в TextBox. Восстановление поврежденного XML - это не весело, и я на самом деле не вижу причин не отображать / редактировать XML в действительной, экранированной форме.

Опять же, я могу спросить: как вы отображаете XML в TextBox? Похоже, вы в какой-то момент намеренно удалили XML.

/ РЕДАКТИРОВАТЬ в ответ на ваш последний комментарий: Ну да, очевидно, поскольку он может содержать HTML. Вам нужно правильно экранировать свой XML перед тем, как записать его на страницу HTML. Под этим я подразумеваю весь XML. Итак, это:

<foo mean-attribute="&lt;">

становится таким:

&lt;foo mean-attribute="&amp;&lt;"&gt;

Другие советы

Конечно, когда вы помещаете ссылки на сущности в область текста, они выходят без экранирования. Текстовые зоны не волшебны, вы должны & Убежать; все, что вы вкладываете в них, как и любой другой элемент. Браузеры могут отображать необработанный '& Lt;' в текстовой области, но только потому, что они пытаются исправить ваши ошибки.

Таким образом, если вы помещаете редактируемый XML в текстовое поле, вам нужно один раз экранировать значение атрибута, чтобы сделать его действительным XML, а затем вам нужно снова экранировать весь XML, чтобы сделать его действительным HTML. Окончательный источник, который вы хотите отобразить на странице:

<textarea name="somexml">
    &lt;Configuration&gt;
        &lt;Validator Expression="[^&amp;lt;]" /&gt;
        &lt;Validator Expression="[^&amp;amp;]" /&gt;
    &lt;/Configuration&gt;
</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="[^&lt;]" />\n\
</Configuration>\
'
alert(elem.value);
</script>

Уведомляется и отображается пользователю неизменный, как:

<Configuration>
  <Validator Expression="[^&lt;]" />
</Configuration>

Так что, возможно, одно (нежизнеспособное?) решение — использовать Firefox для ваших пользователей.


Кажется, были раскрыты две части вашего вопроса:

1 XML, который вы отображаете, становится неэкранированным.

Например, "&lt;" не экранируется как "<".Но поскольку «<» также не экранируется как «<», информация теряется, и вы не можете получить ее обратно.

Одно из решений - избежать всех "&"персонажи, так что"&lt;"становится"&amp;lt;".Тогда это не будет экранировано текстовым полем как "&lt;".Когда вы перечитаете его, все будет так, как было изначально.(Я предполагаю, что текстовая область действительно меняет строку, но Firefox ведет себя не так, как вы сообщаете, поэтому я не могу это проверить)

Другое решение (я думаю, уже упомянутое) — создать/купить/заимствовать пользовательскую текстовую область (неплохо, если просто, но есть все клавиши редактирования, ctrl-C, ctrl-shift-left и так далее).

2 Вы бы хотели, чтобы пользователям не приходилось беспокоиться о побеге.

Вы находитесь в беглом аду:

Замена регулярного выражения в основном будет работать...но как вы можете надежно определить конечную кавычку ("), когда пользователь может (законно, в рамках указанных вами условий) ввести:

<Configuration>
  <Validator Expression="[^"<]" />
</Configuration>

Глядя на это с точки зрения синтаксиса регулярного выражения, он также не может определить, является ли последнее "частью регулярного выражения или его концом.Синтаксис регулярных выражений обычно решает эту проблему с помощью явного терминатора, например:

/[^"<]/

Если пользователи использовали этот синтаксис (с терминатором), а вы написали для него синтаксический анализатор, то вы могли бы определить, когда регулярное выражение закончилось, и, следовательно, следующий символ " является не частью регулярного выражения, а частью XML, и поэтому какие части необходимо экранировать.Я не говорю, что вам следует это делать!Я говорю, что это теоретически возможно.Это довольно далеко не быстро и грязно.

КСТАТИ:Та же проблема возникает с текстом внутри элемента.Следующее является законным в рамках указанных вами условий, но имеет те же проблемы с анализом:

<Configuration>
  <Expression></Expression></Expression>
</Configuration>

Основное правило синтаксиса, допускающее «любой текст», заключается в том, что разделитель должен избежать (например," или <), чтобы можно было распознать конец.Большая часть синтаксиса также избегает множества других вещей для удобства/неудобства.(РЕДАКТИРОВАТЬ ему понадобится escape для самого escape-символа:для XML это "&", который в буквальном смысле экранируется как "&amp;"Для регулярных выражений это стиль C/unix"\", который в буквальном смысле экранируется как "\\").

Вставьте синтаксисы, и вы попадете в ад.

Одним из простых решений для вас является сообщить своим пользователям:это быстрый и грязный редактор конфигурации, чтобы у вас не было никаких причудливых фраз «не нужно бежать» mamby-pamby:

  • Список персонажей и побегов далее в текстовую область, например:"<" как "&lt".
  • Для 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, "&lt;");

    return configuration;
}

(правка: удалена замена амперсанда, так как это вызывает проблемы с перекруткой)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top