【问题标题】:XML Invalid characters when creating CData node from UnicodeString从 UnicodeString 创建 CData 节点时 XML 无效字符
【发布时间】:2014-01-13 09:26:46
【问题描述】:

IDE:Embarcadero XE5 c++ 构建器。

我正在尝试在 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 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 ); 

关于为什么失败的任何想法?编码问题?

【问题讨论】:

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

标签: c++ xml c++builder


【解决方案1】:

如果您阅读XML specification 中的Section 2.7,它描述了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#x1C)。这就是为什么您会收到有关非法字符的错误,因为您确实有非法字符。

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

【讨论】:

    【解决方案2】:

    事实证明问题确实是原始数据字符串中存在的所有转义字符,正如怀疑的那样。

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

    Rad Studio 方法:EncodeBase64DecodeBase64

    标题:Soap.EncdDecd.hpp

    【讨论】:

      【解决方案3】:

      对于我的情况,我创建了一个函数来将字符串修剪为一组有效的 XML Characters

      伪代码

      //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;
      

      【讨论】:

        猜你喜欢
        • 2012-12-20
        • 2011-03-09
        • 1970-01-01
        • 2017-01-30
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        • 2012-03-09
        • 2011-02-27
        相关资源
        最近更新 更多