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

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

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

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

Edit:

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

Ответы

Ответ 1

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

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

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

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

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

В разделе CDATA только строка CDEnd распознается как разметка, так что левые угловые скобки и амперсанды могут встречаться в их литеральной форме; им не нужно (и не может) сбежать с помощью "<" и "&". Секции 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>]]> 

Ответ 2

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

Здесь все:

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

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

Ответ 3

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

BTW,

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

Ответ 4

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 проверяет правильность записи, когда он пишет.

Ответ 5

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

Ответ 6

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

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

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

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

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

Ответ 7

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

Ответ 8

Более чистый способ в 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;
   }

Ответ 9

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

Ответ 10

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

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

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