我想知道是否有办法在xml文档的CDATA部分中转义CDATA结束标记(]]>
)。或者,更一般地说,如果在CDATA中使用某些转义序列(但如果它存在,我想它可能只有在逃避开始或结束令牌时才有意义)。
基本上,您是否可以在CDATA中嵌入开始或结束标记,并告诉解析器不要解释它,而是将其视为另一个字符序列。
如果你发现自己试图这样做,你应该重构你的xml结构或你的代码,但即使我在过去3年左右的时间里每天都在使用xml而且我从未有过这个问题,我想知道是否有可能。只是出于好奇。
编辑:
除了使用html编码...
答案 0 :(得分:166)
您必须将数据分成几部分才能隐藏]]>
。
以下是整个事情:
<![CDATA[]]]]><![CDATA[>]]>
第一个<![CDATA[]]]]>
有]]
。第二个<![CDATA[>]]>
包含>
。
答案 1 :(得分:133)
您无法转义CDATA结束序列。 XML specification的生产规则20非常明确:
[20] CData ::= (Char* - (Char* ']]>' Char*))
编辑:此产品规则的字面意思是“CData部分可能包含您想要的任何内容但序列']]&gt;'。没有例外。”。
EDIT2:same section也读取:
在CDATA部分中,只有CDEnd字符串被识别为标记,因此左尖括号和&符号可能以其字面形式出现;他们不需要(也不能)使用“
<
”和“&
”进行转义。 CDATA部分无法嵌套。
换句话说,不可能使用实体引用,标记或任何其他形式的解释语法。 CDATA部分中唯一解析的文本是]]>
,它会终止该部分。
因此,无法在CDATA部分中转义]]>
。
EDIT3:same section也读取:
2.7 CDATA章节
[定义:CDATA部分可能出现在任何可能出现字符数据的地方;它们用于转义包含字符的文本块,否则这些字符将被识别为标记。 CDATA部分以字符串“&lt;![CDATA [”开头,以字符串“]]&gt;”:]结束
然后可能存在CDATA部分,可能出现任何字符数据,包括单个CDATA部分的多个相邻CDATA部分。这样就可以分割]]>
标记,并将它的两部分放在相邻的CDATA部分中。
例如:
<![CDATA[Certain tokens like ]]> can be difficult and <invalid>]]>
应该写成
<![CDATA[Certain tokens like ]]]]><![CDATA[> can be difficult and <valid>]]>
答案 2 :(得分:15)
你没有逃脱]]>
,但是在>
之后]]
移出]]><![CDATA[
,>
之前插入\
,就像>
一样{1}}在C / Java / PHP / Perl字符串中,但仅在]]
之前和{{1}}之后需要。
BTW,
S.Lott的回答与此相同,措辞不同。
答案 3 :(得分:7)
S上。 Lott的答案是正确的:你没有对结束标记进行编码,而是将其分成多个CDATA部分。
如何在现实世界中遇到这个问题:使用XML编辑器创建一个将被送入内容管理系统的XML文档,尝试写一篇关于CDATA部分的文章。你在CDATA部分嵌入代码示例的普通技巧将在这里失败。你可以想象我是如何学到这一点的。
但是在大多数情况下,你不会遇到这个,这就是原因:如果你想存储(比方说)XML文档的文本作为XML元素的内容,你可能会使用DOM方法,例如:
XmlElement elm = doc.CreateElement("foo");
elm.InnerText = "<[CDATA[[Is this a problem?]]>";
并且DOM非常合理地逃脱了&lt;和&gt ;,这意味着你没有无意中在文档中嵌入了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在写入时检查格式良好。
答案 4 :(得分:5)
只需将]]>
替换为]]]]><![CDATA[>
答案 5 :(得分:3)
这是另一个需要转义]]>
的案例。假设我们需要在XML文档的CDATA块中保存一个完全有效的HTML文档,并且HTML源恰好拥有它自己的CDATA块。例如:
<htmlSource><![CDATA[
... html ...
<script type="text/javascript">
/* <![CDATA[ */
-- some working javascript --
/* ]]> */
</script>
... html ...
]]></htmlSource>
注释的CDATA后缀需要更改为:
/* ]]]]><![CDATA[> *//
因为XML解析器不知道如何处理javascript注释块
答案 6 :(得分:1)
在PHP中:'<![CDATA['.implode(explode(']]>', $string), ']]]]><![CDATA[>').']]>'
答案 7 :(得分: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;
}
答案 8 :(得分:0)
另一种解决方案是将]]>
替换为]]]><![CDATA[]>
。
答案 9 :(得分:0)
见这个结构:
<![CDATA[
<![CDATA[
<div>Hello World</div>
]]]]><![CDATA[>
]]>
对于内部CDATA标记,您必须使用]]]]><![CDATA[>
而非]]>
关闭。就这么简单。
答案 10 :(得分:-1)
我不认为中断CDATA是个好方法。这是我的选择...
将]
用于转义序列,后跟字符的十六进制值。就像在&#xhhhh;
=> ]<unicode value>;
这样,如果您尝试记录]]>
,则编码fn将产生]005D;]005D;]003E;
,这在CDATA中是可以的。
这比按实体名称进行转义更好,因为它们不会在您的应用程序中每次都解码,并且您可能对使用&符号转义实体与对某些其他字符/序列转义可能具有不同的优先级。因此,您可以更好地控制CDATA的内容。