2014-01-13 49 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;