#javascript #html #xml #svg
#javascript #HTML #xml #svg
Вопрос:
Я разрабатываю новый сайт и при написании некоторого клиентского HTML / Javascript-кода наткнулся на этот сценарий.
Например, если в <script>
теге есть символы в HTML-кодировке, <script> alert("amp;>");</script>
должно появиться предупреждение с amp;>
, и это происходит, потому что я считаю, что анализатор HTML запускается первым перед анализатором javascript для <script>
и <style>
тегов. Это работает так, как ожидалось.
Теперь, при написании некоторого кода, я сделал это — <svg><script>alert("amp;>");</script></svg>
. На этот раз я получаю всплывающее окно с >
вместо amp;>
. Хотя я могу понять, что это из-за <svg>
тега, я не уверен, в чем основная причина и какие другие теги, кроме <svg>
, изменяют поведение по умолчанию.
Если кто-нибудь может указать на официальную документацию, это было бы очень полезно.
Вот простой JSFiddle, который я создал для этого сценария — https://jsfiddle.net/emz8Lfxt /.
Комментарии:
1. Ваш HTML неверен. Ваш тег SVG не закрыт, и теперь браузеры не понимают, находится ли SVG вокруг тега script (что, кстати, не имеет смысла) или перед ним. Закройте свой SVG-тег и посмотрите, работает ли что-то по-другому. Вы можете убедиться, что ваш HTML-код действителен, используя этот сайт. validator.w3.org/#validate_by_input
2. Закрытие тега svg никак не влияет на то, что демонстрирует пользователь. Попробуйте сами. Отмечу, что я поддержал его вопрос, чтобы противостоять вашему отрицательному голосованию; независимо от некоторой несущественной копирования-вставки, вопрос интересный.
3. @Crayons — Спасибо! Закрытие тега svg после тега </script> не оказывает никакого влияния.
4. закрытие тега до или после тега script действительно имеет значение.
5.
<svg></svg><script></script>
и<svg><script></script></svg>
действительно имеет значение.
Ответ №1:
Честно говоря, я чувствую, что вам было бы трудно найти официальную документацию о том, почему это происходит.
Мое лучшее предположение в этом сценарии заключается в том, что, поскольку элемент SVG является контейнером для графики SVG, и что контейнер SVG основан на XML и может содержать в себе другие элементы HTML; пример:
<svg>
<rect style="fill:rgb(0,0,255);" />
</svg>
Браузер пытается проанализировать внутренний HTML, пытаясь нарисовать объект. Однако, как только он осознает, что на самом деле это не элемент SVG, он просто останавливается и переходит к выполнению javascript, который у вас там есть. Как следствие, amp;>
анализируется до завершения выполнения javascript.
Я чувствую, что нам нужен кто-то с глубокими знаниями о том, как обрабатывается элемент SVG.
Я отмечу, для справки, этот пример:
<script>alert("amp;>")</script>
<svg><script>alert("amp;>")</script></svg>
<span><script>alert("amp;>")</script></span>
Будет выводиться по порядку:
amp;>
>
amp;>
Комментарии:
1. В этом есть большой смысл. Я склоняюсь к вашему ответу после прочтения документов W3. 🙂
Ответ №2:
Браузеры разбирают <script>
специально, они не заменяют в них HTML-объекты. Это позволяет вам писать такие вещи, как:
if (a < b)
вместо того, чтобы писать:
if (a amp;< b)
В ранних браузерах вам приходилось писать что-то вроде:
<script type="text/javascript">
<![CDATA[
…
]]>
</script>
CDATA
Раздел не выполнял подстановку сущности, поэтому вы могли бы написать код «нормально» там.
Но более поздние спецификации HTML сделали это по умолчанию для <script>
тел, поэтому в этом больше нет необходимости.
Но когда <script>
находится внутри <svg>
, по-видимому, синтаксический анализатор SVG имеет приоритет. So amp;>
переводится на >
.
Комментарии:
1. Существуют ли какие-либо другие теги, кроме
<svg>
где HTML-объекты разрешаются внутри<script>
тегов?2. Я не знаю сразу. Как упоминалось в другом ответе, это, по-видимому, происходит потому, что SVG, по сути, является собственным мини-языком (использующим синтаксис XML), и он должен полностью анализировать свое тело. Если есть какие-либо другие теги, которые определяют встроенный язык, они также могут делать то же самое.
3. Кстати,
<script>
сам по себе является другим тегом, который вызывает специальный анализ его содержимого — в этом случае он не ищет встроенные теги и HTML-объекты.4. Как объясняется в этом посте, если вы добавите
<![CDATA[ … ]]>
тег in script, вы сможете анализировать их как обычно: jsfiddle.net/sob43r2v (возможно, связанный источник: dev.w3.org/SVG/tools/svgweb/docs/QuickStart.html )
Ответ №3:
Встроенный SVG в HTML-документе рассматривается синтаксическим анализатором как посторонний элемент. Затем его содержимое анализируется анализатором SVG, и все содержимое этого SVGElement, таким образом, анализируется как SVG.
SVG имеет собственное определение в <script> element, and what you have here is actually an SVGScriptElement, not an HTML one:
<svg>
<script>
const thisScript = document.currentScript;
console.log('HTMLScriptElement?', thisScript instanceof HTMLScriptElement); // false
console.log('SVGScriptElement?', thisScript instanceof SVGScriptElement); // true
</script>
</svg>
Теперь о том, почему содержимое <svg:script>
элемента анализируется так, как если бы это был XML, прежде чем он будет выполнен, нам нужно вернуться немного назад во времени.
SVG1.1 ли определить его <script> element as
Категории:
Нет
Модель содержимого:
Любые элементы или символьные данные.
Атрибуты: …
Это означает, что SVG1.1, в отличие от HTML, позволяет <script> element to have other content than символьные данные. (HTML4 определил модель содержимого скрипта как данные скрипта, которые в конечном итоге были сопоставлены с CDATA).
СВГ крошечные 1.2 с тех пор следовал по HTML и не лечить <script> content as Character Data, but unfortunately browsers only did implement векторные эффекты от этой бедной tiny1.2 версии, так парсинг тега скрипта есть еще следующие правила 1.1.
[Но входящий SVG2] (https://www.w3.org/TR/SVG/interact.html#ScriptElement следует следовать здесь, пока это все еще обсуждается, что означает, что в ближайшем будущем нам больше не нужно будет упаковывать наш код в //<![CDATA[
блоки, даже если это было бы решением для вашего случая:
<svg>
<script>
console.log("out", "amp;>"); // >
//<![CDATA[
// ^- this forces the SVG parser to treat the content as Character Data
console.log("in", "amp;>"); // amp;>
//]]>
</script>
</svg>
Однако будьте осторожны, <![CDATA[
блоки не разрешены в HTML (отсюда и //
комментарии js), за исключением внешних элементов, таких как SVG и MathML, поэтому вместо этого вы также можете просто переместить свой скрипт из вашего элемента <svg>, чтобы он стал частью вашего HTML-документа напрямую.