2014-01-13 33 views
2

IDE:Embarcadero XE5 C++构建器。XML从UnicodeString创建CData节点时出现无效字符

我试图转储UnicodeStringsXML CData部分

这样的字符串的小摘录:

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\[email protected]" 

我知道一个XML文档可以包含非ASCII字符,我想到了一个XML CDATA节不被XML解析器解析的内容(除了的结尾部分指示符“[[>”,它不存在于我的数据中,请检查它)。

创建(写)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

看来这个问题实际上可能是字符串的内容。由于数据的“随机”性质,字符串包含字符文字(转义字符)的加载......并且它们错误地(根据我的要求)被解释为这样。导致问题。因此,在创建CData节点之前,需要为转义字符分析数据字符串。 – HvS

回答

4

如果你读了XML specificationSection 2.7,它描述了一个CDATA节的格式:

CDATA Sections 

[18] CDSect ::= CDStart CData CDEnd 
[19] CDStart ::= '<![CDATA[' 
[20] CData ::= (Char* - (Char* ']]>' Char*)) 
[21] CDEnd ::= ']]>' 

Char是DEFI斯内德在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#x1C)。这就是为什么你会收到关于非法字符的错误,因为你确实有非法字符。

CDATA部分不允许您将任意二进制数据放入XML数据中。当文本内容包含通常为XML标记保留的字符时,应使用CDATA部分,以便它们不必转义或编码为实体。将二进制数据放入XML文档的唯一方法是将其编码为兼容XML(通常为7位ASCII)格式(如Base64)(但还有其他可用的格式,例如yEnc)。

0

原来这个问题确实是所有原始数据字符串中存在的转义字符。

通过在创建XML CData节之前通过Base64编码整个字符串来解决这个问题。

的RAD Studio方法:EncodeBase64DecodeBase64

页眉:Soap.EncdDecd.hpp

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;