Есть ли способ избежать торможения конца 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[>
вместо ]]>
. Просто как это.