Как, черт возьми, вы можете редактировать действительный XML на веб-странице? - PullRequest
4 голосов
/ 28 октября 2008

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

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

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

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

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

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

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

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

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

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

var result = Server.HttpEncode (editedConfig);

Результаты в

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

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

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


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

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

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

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


У этого вопроса теперь есть щедрость. Чтобы получить награду, вы демонстрируете, как редактировать VALID XML в окне браузера, БЕЗ стороннего инструмента с открытым исходным кодом, который не требует от меня использования regex для экранирования значений атрибутов вручную, который не требует от пользователей экранирования их атрибутов, и это не дает сбоя при циклическом переключении (& amp; amp; etc;)

Ответы [ 8 ]

7 голосов
/ 28 октября 2008

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

/ EDIT в ответ на ваше обновление: not отображает недопустимый XML для вашего пользователя для редактирования! Вместо этого отобразите правильно экранированный XML в TextBox. Восстановление поврежденного XML - это не весело, и я на самом деле не вижу причин не отображать / редактировать XML в действительной, экранированной форме.

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

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

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

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

&lt;foo mean-attribute="&amp;&lt;"&gt;
5 голосов
/ 29 октября 2008

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

Таким образом, если вы помещаете редактируемый 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 с целью разрешения ошибок, таких как «<» или «&», не экранированных в значении атрибута, является потерей, полностью против того, как XML должен работать. Если вы не можете доверять своим пользователям писать правильно сформированный XML, предоставьте им более простой не-XML интерфейс, такой как простой список разделенных регулярными строками регулярных выражений. </p>

1 голос
/ 07 февраля 2009

Вставка CDATA вокруг всего текста даст вам другой механизм экранирования, который (1) спасет пользователей от ручного экранирования, и (2) позволит тексту, который автоматически был удален текстовой областью, правильно считываться.

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

: -)

1 голос
/ 29 января 2009

Примечание: 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;» не экранируется как «<». Но поскольку «<» также не экранируется как «<», информация теряется, и вы не можете ее вернуть. </p>

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

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

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

Ты в убежище:

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

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

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

/[^"<]/

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

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

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

Основное правило в синтаксисе, которое допускает «любой текст», заключается в том, что разделитель должен быть экранирован (например, «или <), чтобы можно было распознать конец. Большинство синтаксисов также избегает связки». других вещей, для удобства / неудобства. (<em> EDIT он должен иметь escape для самого escape-символа: для XML это "&", который когда литерал экранируется как "* 1051" * "Для регулярных выражений это C / unix-стиль" \ ", который, когда литерал экранируется как" \\ ").

Гнездятся синтаксисы, и вы попадаете в ад.

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

  • Перечислите символы и убегайте дальше к текстовой области, например: "<" как "<code>&lt".
  • Для XML это не подтвердите, покажите им список снова.

Оглядываясь назад, я вижу Бобинс дал мне тот же самый базовый ответ.

1 голос
/ 28 января 2009

Вы можете взглянуть на что-то вроде TinyMCE , что позволяет редактировать html в расширенном текстовом поле. Если вы не можете настроить его так, чтобы делать именно то, что вы хотите, вы можете использовать его как вдохновение.

1 голос
/ 28 октября 2008

Как вы говорите, обычный сериализатор должен избегать всего для вас.

Тогда проблема в текстовом блоке: вам нужно самостоятельно обрабатывать все, что пропущено через текстовый блок.

Вы можете попробовать HttpUtility.HtmlEncode (), но я думаю, что самый простой способ - просто заключить все, что вы проходите через текстовый блок, в раздел CDATA.

Обычно, конечно, я бы хотел, чтобы все было правильно экранировано, а не полагалось на "костыль" CDATA, но я также хотел бы использовать встроенные инструменты для экранирования. Для чего-то, что пользователь отредактировал в «спящем» состоянии, я думаю, что CDATA может быть подходящим вариантом.

Также посмотрите этот предыдущий вопрос:
Лучший способ кодировать текстовые данные для XML


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

Возможно, попробуйте автоматически исправить некоторые виды ошибок (например, плохие амперсанды из моего связанного вопроса), но затем получите номер строки и номер столбца первой ошибки проверки из анализатора .Net xml и используйте его, чтобы показать пользователям, где их ошибка до тех пор, пока они не дадут вам что-нибудь приемлемое. Бонусные баллы, если вы также проверяете по схеме.

0 голосов
/ 28 октября 2008

Это действительно мой единственный вариант? Разве это не достаточно распространенная проблема, что она имеет решение где-то в рамках?

private string EscapeAttributes(string configuration)
{
    var lt = @"(?<=\w+\s*=\s*""[^""]*)<(?=[^""]*"")";
    configuration = Regex.Replace(configuration, lt, "&lt;");

    return configuration;
}

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

0 голосов
/ 28 октября 2008

Этот специальный символ - "<" - должен был быть заменен другими символами, чтобы ваш XML был действительным. Проверьте эту ссылку на наличие специальных символов XML: </p>

http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references

Попробуйте также закодировать содержимое TextBlock перед отправкой в ​​десериализатор:

HttpServerUtility utility = new HttpServerUtility();
string encodedText = utility.HtmlEncode(text);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...