Есть ли способ избежать маркера конца CDATA в XML?

109

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

В принципе, у вас есть маркер начала или конца, встроенный в CDATA, и скажите парсеру не интерпретировать его, а рассматривать его как очередную последовательность символов.

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

Edit:

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

  • 4
    Во-первых, я принимаю ответ как правильный, но учтите: ничто не мешает кому-то кодировать > as > в CData, чтобы убедиться, что он встроен ]]> не будет анализироваться как CDEnd. Это просто означает, что это неожиданно, и что & FIRST должен быть закодирован как & слишком, чтобы данные могли быть правильно декодированы. Пользователи документа также должны знать, как декодировать эти CData. Это не случайно, так как часть цели CData состоит в том, чтобы содержать контент, который конкретный потребитель понимает, как обращаться с ним. Такая CData просто не может быть правильно истолкована обычным потребителем.
  • 1
    @nix, CDATA просто предоставляет явный способ объявления содержимого текстового узла таким образом, что языковые токены внутри (кроме]]>) не анализируются. В частности, он не расширяет ссылки на сущности, такие как & gt; по этой причине, так и в блоке CDATA, это означает только эти четыре символа, а не «>». Для сравнения: в спецификации xml все текстовое содержимое называется «cdata», а не только эти последовательности («символьные данные»). Также речь идет не о конкретных потребляющих агентах. (Такая вещь существует, хотя - инструкции обработки (<? Target инструкция?>).
Показать ещё 3 комментария
Теги:
escaping
cdata

10 ответов

128
Лучший ответ

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

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

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

EDIT: это правило продукта в буквальном смысле означает: "Раздел CData может содержать все, что вы хотите, но последовательность" ]] > "Нет исключения".

EDIT2: тот же раздел также гласит:

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

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

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

EDIT3: тот же раздел также гласит:

2.7 Разделы CDATA

[Определение: разделы CDATA могут возникать в любом случае, когда могут встречаться символьные данные; они используются для удаления блоков текста, содержащих символы, которые в противном случае были бы распознаны как разметка. Секции CDATA начинаются со строки "<! [CDATA [" и заканчиваются строкой "]] > ":]

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

Пример:

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

следует записать как

<![CDATA[Certain tokens like ]]]]><![CDATA[> can be difficult and <valid>]]> 
  • 1
    В самом деле. Ну, я не академический тип, но, как я уже сказал в этом вопросе, мне просто интересно это. Если честно, я просто скажу вам об этом, потому что едва ли могу понять смысл синтаксиса, используемого для правила. Спасибо за Ваш ответ.
  • 1
    Он выглядит следующим образом: Char * (набор всех последовательностей символов) - (кроме) Char * ']]>' Char * (набор всех последовательностей символов, которые включают подстроку ']]>').
Показать ещё 15 комментариев
163

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

Здесь все:

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

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

  • 1
    Спасибо за Ваш ответ. Я скорее искал что-то вроде эквивалента с обратной косой чертой (внутри строк в C, PHP, Java и т. Д.). Согласно правилу, указанному ddaa, кажется, что такого нет.
  • 27
    Это должен быть принятый ответ. Побег - это немного двусмысленный термин, но этот ответ определенно обращается к духу побега . Жаль, что это не соответствует узкой концепции ОП о побеге , которая произвольно требует, чтобы символ обратной косой черты был вовлечен по какой-то причине.
Показать ещё 8 комментариев
14

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

BTW,

Ответ S.Lott такой же, как и этот, только что сформулированный по-разному.

  • 2
    Я предпочитаю эту формулировку. :)
  • 3
    Этот способ сказать, что это дает людям неверную идею. Это не ускользает. ]]]]><![CDATA[> не магическая последовательность для ]]> . ]]]]> содержит ]] символов в качестве данных и ]]> заканчивает текущий раздел CDATA. <![CDATA[> открывает новый раздел CDATA и вставляет > в него. На самом деле это два разных элемента, и они будут обрабатываться по-разному при работе с анализатором DOM. Вы должны знать об этом. Этот способ похож на ]]]><![CDATA[]> , за исключением того, что он помещает ] в первый и ]> во второй CDATA. Разница остается.
Показать ещё 1 комментарий
7

S. Ответ Lott прав: вы не кодируете конечный тег, вы разбиваете его на несколько разделов 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 проверяет правильность записи, когда он пишет.

  • 0
    Ну, у меня был пример "реального мира". Я обычно загружаю Xml из Flash, который содержит html разметку в разделах CDATA. Я думаю, что иметь способ избежать этого может быть полезно. Но в любом случае, в этом случае содержимое CDATA обычно является допустимым XHTML, и поэтому «внешнего» CDATA можно было бы вообще избежать.
  • 2
    CDATA почти всегда можно полностью избежать. Я обнаружил, что люди, которые очень часто борются с CDATA, не понимают, что они на самом деле пытаются сделать и / или как реально работают используемые ими технологии.
Показать ещё 2 комментария
4

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

3

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

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

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

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

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

  • 0
    Это не частный случай. Просто замените ]]> на ]]]]><![CDATA[> все еще применяется здесь. Тот факт, что это JavaScript или комментарий, не важен.
1

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

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

Не забудьте использовать многобайтовое str_replace, если необходимо (не latin1 $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;
   }
  • 0
    Можете ли вы объяснить свой отрицательный голос? Сказать, что я совершил ошибку, не так полезно, как объяснить, где она есть.
1

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

0

См. эту структуру:

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

Для внутреннего тега (ов) CDATA вы должны закрыть ]]]]><![CDATA[> вместо ]]>. Просто как это.

0

Другим решением является замена ]]> на ]]]><![CDATA[]>.

  • 1
    Дубликат другого ответа .
  • 0
    @Palec, ]]]><![CDATA[]> не равно ]]]]><![CDATA[>
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню