有没有办法在 xml 中转义 CDATA 结束标记?
题
我想知道是否有任何方法可以转义 CDATA 结束令牌(]]>
) 在 xml 文档的 CDATA 部分中。或者,更一般地说,如果在 CDATA 中使用一些转义序列(但如果存在,我想无论如何,转义开始或结束标记可能才有意义)。
基本上,您是否可以在 CDATA 中嵌入一个开始或结束标记,并告诉解析器不要解释它,而是将其视为另一个字符序列。
也许,如果您发现自己试图这样做,您应该重构您的 xml 结构或代码,但即使在过去 3 年左右的时间里我每天都在使用 xml,而且我从未遇到过这个问题,我想知道这是否可能。只是出于好奇。
编辑:
除了使用 html 编码...
解决方案
您无法转义CDATA结束序列。 XML 规范的制定规则20非常明确:
[20] CData ::= (Char* - (Char* ']]>' Char*))
编辑:此产品规则字面意思是<!>“; CData部分可能包含您想要的任何内容但序列']] <!> gt;'。没有例外。<!>“。
EDIT2:同一部分也写着:
在CDATA部分中,只有CDEnd字符串被识别为标记,因此左尖括号和&符号可能以其字面形式出现;它们不需要(也不能)使用<!>“
<
<!>来转义;和<!>“;&
<!>”; CDATA部分无法嵌套。
换句话说,不可能使用实体引用,标记或任何其他形式的解释语法。 CDATA部分中唯一解析的文本是]]>
,它终止了该部分。
因此,无法在CDATA部分中逃避<=>。
EDIT3:同一部分也写着:
2.7 CDATA章节
[定义:CDATA部分可能出现在任何可能出现字符数据的地方;它们用于转义包含字符的文本块,否则这些字符将被识别为标记。 CDATA部分以字符串<!>“<!> lt;![CDATA [<!>];并以字符串<!> quot;]] <!> gt; <!>“;:]
结束
然后可能存在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中的<=>字符串,但仅在<=>之前和<=>之后才需要。
BTW,
S.Lott的回答与此相同,措辞不同。
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[>
这是另一个需要转义]]>
的案例。假设我们需要在XML文档的CDATA块中保存一个完全有效的HTML文档,并且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(非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;
}
另一种解决方案是将]]>
替换为]]]><![CDATA[]>
。
见这个结构:
<![CDATA[
<![CDATA[
<div>Hello World</div>
]]]]><![CDATA[>
]]>
对于内部CDATA标记,您必须使用]]]]><![CDATA[>
而不是]]>
关闭。就这么简单。