IDE:Embarcadero XE5 c ++ builder。
我正在尝试在 XML CData部分中转储 UnicodeStrings 。
这种字符串的小提取物:
u"‰PNG\r\n\x1A\n\0\0\0\rIHDR\0\0\0õ\0\0\02\b\x06\0\0\0„\\i\0\0\0\x01sRGB\0®Î\x1Cé\0\0\0\x04gAMA\0\0±\vüa\x05\0\0\0\tpHYs\0\0\x0EÃ\0\0\x0EÃ\x01Ço¨d\0\0\v¼IDATxÚíœypUÕ\x19ÀO\x06…°¤\x04D$ˆ²\b1š\b\x18@...etc"
我知道XML文档可以包含非ASCII字符,我认为XML解析器不会解析XML CData部分的内容(除了结尾部分指示符“ [[> ; “,我的数据中没有,检查它)。
当创建(写)CData部分时,我仍然会在创建节点时出现“在文本内容中找到无效字符”错误。
代码示例:
_di_IXMLDocument pXMLDocument = NewXMLDocument("1.0");
// I've played around with the document encoding with no success, guessing it's only applicable while reading the document.
// pXMLDocument->SetEncoding(L"iso-8859-1");
String myString; // Unicode, contains my data string.
// 1st param of CreateNode method is of type UnicodeString.
di_IXMLNode pCDataNode = pXMLDocument->CreateNode( myString, ntCData );
有关为何失败的任何想法?编码问题?
答案 0 :(得分:4)
如果您阅读了Section 2.7的XML specification,则说明了CDATA部分的格式:
CDATA Sections
[18] CDSect ::= CDStart CData CDEnd
[19] CDStart ::= '<![CDATA['
[20] CData ::= (Char* - (Char* ']]>' Char*))
[21] CDEnd ::= ']]>'
Char
在Section 2.2中定义:
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
如果您查看原始数据,它会包含从该范围中排除的十几个字符值(特别是#x0
,#x1
,#x2
,#x4
, #x5
,#x6
,#x8
,#xB
#xE
,#x18
,#x19
,#x1A
和{{ 1}})。这就是为什么你收到有关非法字符的错误,因为你确实有非法字符。
CDATA部分不允许您将任意二进制数据放入XML数据。当文本内容包含通常为XML标记保留的字符时,应使用CDATA部分,以便它们不必转义或编码为实体。将二进制数据放入XML文档的唯一方法是将其编码为XML兼容(通常为7位ASCII)格式,例如Base64(但您可以使用其他格式,例如yEnc)。
答案 1 :(得分:0)
原来问题确实是原始数据字符串中存在的所有转义字符,如怀疑的那样。
解决了在创建XML CData-sections之前通过Base64编码整个字符串的问题。
Rad Studio方法: EncodeBase64 , DecodeBase64
标题: Soap.EncdDecd.hpp
答案 2 :(得分:0)
对于我的情况,我创建了一个函数来将字符串修剪为只有一组有效的XML 字符。
<强>伪代码强>:
//Code released into public domain. No attribution required.
function TrimToXmlText(xmlText: String): string;
begin
/*
http://www.w3.org/TR/xml/#NT-Char
Regarless of entity encoding, the only valid characters allowed are:
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
I.e. any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
This means that a string such as
"Line one"#31#10"Line two"
is invalid (because of the #31 aka 0x1F).
This means we need to manually strip them out; because the xml library certainly won't do it for us.
*/
SetLength(Result, Length(xmlText));
Int32 o = 0;
for i = 1 to Length(s) do
begin
case Ord(s[i]) of
$9, $A, $D,
$20..$D7FF,
$E000..$FFFD:
begin
o = o+1;
Result[o] = xmlText[i];
end;
end;
end;
SetLength(Result, o);
end;