Есть ли способ избежать конечного токена CDATA в xml?

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

  •  03-07-2019
  •  | 
  •  

Вопрос

Мне было интересно, есть ли какой-нибудь способ избежать конечного токена CDATA (]]>) в разделе CDATA в xml-документе.Или, в более общем плане, если есть какая-то escape-последовательность для использования внутри CDATA (но если она существует, я думаю, в любом случае, вероятно, имело бы смысл экранировать токены begin или end только).

В принципе, можете ли вы встроить токен begin или end в CDATA и указать анализатору не интерпретировать его, а рассматривать как просто еще одну последовательность символов.

Вероятно, вам следует просто реорганизовать свою структуру xml или свой код, если вы обнаружите, что пытаетесь это сделать, но, хотя я работаю с xml ежедневно в течение последних 3 лет или около того и у меня никогда не возникало этой проблемы, мне было интересно, возможно ли это.Просто из любопытства.

Редактировать:

Кроме использования html-кодировки...

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

Решение

Очевидно, что этот вопрос носит чисто академический характер.К счастью, на это есть вполне определенный ответ.

Вы не можете экранировать конечную последовательность CDATA.Производственное правило 20 XML спецификация совершенно ясно:

[20]    CData      ::=      (Char* - (Char* ']]>' Char*))

Редактировать:Это правило продукта буквально означает "Раздел CData может содержать все, что вы хотите, КРОМЕ последовательности ']]>'.Никаких исключений"..

РЕДАКТИРОВАТЬ 2:В тот же раздел также читает:

В разделе CDATA только строка CDEnd распознается как разметка, так что левые угловые скобки и амперсанды могут встречаться в их буквальной форме;их не нужно (и не может) экранировать с помощью "<" и "&".Разделы CDATA не могут быть вложены.

Другими словами, невозможно использовать ссылку на сущность, разметку или любую другую форму интерпретируемого синтаксиса.Единственным анализируемым текстом внутри раздела CDATA является ]]>, и это завершает раздел.

Следовательно, сбежать невозможно ]]> внутри раздела CDATA.

РЕДАКТИРОВАТЬ 3:В тот же раздел также читает:

2.7 Разделы CDATA

[Определение:Разделы CDATA могут встречаться в любом месте, где могут встречаться символьные данные;они используются для экранирования блоков текста, содержащих символы, которые в противном случае были бы распознаны как разметка.Разделы CDATA начинаются со строки "<![CDATA[" and end with the string "]]>":]

Тогда в любом месте, где могут встречаться символьные данные, может быть раздел CDATA, включая множество смежных разделов CDATA вместо одного раздела CDATA.Это позволяет разделить ]]> токен и поместите две его части в смежные разделы CDATA.

бывший:

<![CDATA[Certain tokens like ]]> can be difficult and <invalid>]]> 

должно быть записано как

<![CDATA[Certain tokens like ]]]]><![CDATA[> can be difficult and <valid>]]> 

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

Вы должны разбить свои данные на части, чтобы скрыть ]]>.

Вот в чем дело в целом:

<![CDATA[]]]]><![CDATA[>]]>

Первый <![CDATA[]]]]> имеет ]].Второй <![CDATA[>]]> имеет >.

Вы не избегаете ]]> но вы избегаете > после ]] вставив ]]><![CDATA[ перед тем, как >, думайте об этом просто как о \ в C / Java / PHP / Perl строка, но необходимая только перед > и после того , как ]].

КСТАТИ,

Ответ С. Лотта такой же, как этот, просто сформулирован по-другому.

S.Ответ Лотта правильный:вы не кодируете конечный тег, вы разбиваете его на несколько разделов CDATA.

Как столкнуться с этой проблемой в реальном мире:используя редактор XML для создания XML-документа, который будет передан в систему управления контентом, попробуйте написать статью о разделах CDATA.Ваш обычный трюк по встраиванию примеров кода в раздел CDATA здесь вас подведет.Вы можете себе представить, как я этому научился.

Но в большинстве случаев вы с этим не столкнетесь, и вот почему:если вы хотите сохранить (скажем) текст XML-документа в качестве содержимого XML-элемента, вы, вероятно, будете использовать метод DOM, например:

XmlElement elm = doc.CreateElement("foo");
elm.InnerText = "<[CDATA[[Is this a problem?]]>";

И DOM вполне разумно избегает < и > , что означает, что вы случайно не внедрили раздел CDATA в свой документ.

О, и это интересно:

XmlDocument doc = new XmlDocument();

XmlElement elm = doc.CreateElement("doc");
doc.AppendChild(elm);

string data = "<![[CDATA[This is an embedded CDATA section]]>";
XmlCDataSection cdata = doc.CreateCDataSection(data);
elm.AppendChild(cdata);

Вероятно, это идеосинкразия .NET DOM, но это не создает исключения.Исключение генерируется здесь:

Console.Write(doc.OuterXml);

Я бы предположил, что под капотом происходит то, что XmlDocument использует XmlWriter для создания своих выходных данных, и XmlWriter проверяет правильность оформления при записи.

просто замените ]]> с ]]]]><![CDATA[>

Вот еще один случай, в котором ]]> нужно сбежать.Предположим, нам нужно сохранить абсолютно корректный HTML-документ внутри блока CDATA XML-документа, и так получилось, что у источника HTML есть собственный блок CDATA.Например:

<htmlSource><![CDATA[ 
    ... html ...
    <script type="text/javascript">
        /* <![CDATA[ */
        -- some working javascript --
        /* ]]> */
    </script>
    ... html ...
]]></htmlSource>

прокомментированный суффикс CDATA необходимо изменить на:

        /* ]]]]><![CDATA[> *//

поскольку анализатор XML не будет знать, как обрабатывать блоки комментариев javascript

В PHP: '<![CDATA['.implode(explode(']]>', $string), ']]]]><![CDATA[>').']]>'

Более чистый способ в PHP:

   function safeCData($string)
   {
      return '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', $string) . ']]>';
   }

Не забудьте при необходимости использовать str_replace, защищенный от многобайтов (не на латинице1 $string):

   function mb_str_replace($search, $replace, $subject, &$count = 0)
   {
      if (!is_array($subject))
      {
         $searches = is_array($search) ? array_values($search) : array ($search);
         $replacements = is_array($replace) ? array_values($replace) : array ($replace);
         $replacements = array_pad($replacements, count($searches), '');
         foreach ($searches as $key => $search)
         {
            $parts = mb_split(preg_quote($search), $subject);
            $count += count($parts) - 1;
            $subject = implode($replacements[$key], $parts);
         }
      }
      else
      {
         foreach ($subject as $key => $value)
         {
            $subject[$key] = mb_str_replace($search, $replace, $value, $count);
         }
      }
      return $subject;
   }

Другое решение заключается в замене ]]> Автор: ]]]><![CDATA[]>.

Посмотрите на эту структуру:

<![CDATA[
   <![CDATA[
      <div>Hello World</div>
   ]]]]><![CDATA[>
]]>

Для внутренних тегов CDATA вы должны закрыть с помощью ]]]]><![CDATA[> вместо того , чтобы ]]>.Вот так просто.

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