Почему браузеры разбора tags differently?

#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-документа напрямую.