代码之家  ›  专栏  ›  技术社区  ›  Levijatanu

DB2 UTF-8 XML C2 85到新行的转换

  •  0
  • Levijatanu  · 技术社区  · 8 年前

    在表中保存编码为DB29.7LUW的XML数据(UTF-8)时,我们遇到了问题。

    表DDL:

    CREATE TABLE DB2ADMIN.TABLE_FOR_XML
    (   
      ID           INTEGER NOT NULL, 
      XML_FIELD      XML   NOT NULL
    )
    

    问题出现在一些罕见的Unicode字符示例中,我们使用的是java-jdbc-db2驱动程序。

    例如,在编辑器中以正常模式而不是十六进制视图(记事本++)查看,下面这个奇怪的A(16之后)在黑色方块中表示为NEL

    输入XML采用UTF-8编码,在HEX编辑器中查看时有以下值:

    00000010h: 31 36 2E 20 C2 85 42                            ; 16. Â…B
    

    在DB2中插入之后,我假设发生了某种转换,因为当选择回数据时,这个字符现在是

    00000010h: 31 36 2E 20 0D 0A 42                            ; 16. ..B
    

    C2 85转换为0D 0A,即新线。

    另一件事我注意到,虽然在将XML保存到表头内容时 <xml version="1.0" encoding="UTF-8">

    但从db2获取xml之后,内容开始

    <xml version="1.0" encoding="UTF-16">

    有没有办法强制db2以UTF-8格式存储XML而不进行转换?使用XMLSERIALIZE提取没有帮助

    从DB2ADMIN.TABLE_FOR_XML中选择XML_FIELD作为内容1,XMLSERIALIZE(XML_FIELD作为cLOB(1M))作为内容2

    在content2中没有XML头,但仍然有newLine。

    2 回复  |  直到 8 年前
        1
  •  1
  •   bobince    8 年前

    这种行为是XML1.1处理器的标准行为。 XML 1.1 s2.11 :

    在解析之前,XML处理器必须通过将[the single character#x85]转换为单个#xA字符来规范输入时外部解析实体(包括文档实体)中的所有换行符

    行结束类型是文档的许多细节之一,这些细节将在解析和序列化周期中丢失(例如属性顺序、标记中的空格、数字字符引用…)。

    DB2的XML字段使用XML1.1有点奇怪,因为没有太多使用该修订版的XML,但支持NEL(陈旧无用的大型机行尾字符)是IBM一直想要的东西,这并不奇怪。

    有没有办法强制db2以UTF-8格式存储XML而不进行转换?

    使用BLOB?

    如果您需要两种本机XML字段功能 要保留文档的原始序列化形式,您需要两列。

    (你是 当然 您需要保留NEL行结尾吗?通常没有人关心行尾,这些都是假的。)

        2
  •  0
  •   Community CDub    7 年前

    由于我通常不需要非可读字符,在将XML字符串保存到Db2之前,我决定实现来自x'c285(代码点133)的干净字符串和4字节UTF-8字符,仅用于以下情况:

    发现类似示例( How to replace/remove 4(+)-byte characters from a UTF-8 string in Java? )并进行了调整。

    public static final String LAST_3_BYTE_UTF_CHAR = "\uFFFF";
    public static final String REPLACEMENT_CHAR = "\uFFFD"; 
    
    public static String toValid3ByteUTF8String(String line)  {
        final int length = line.length();
        StringBuilder b = new StringBuilder(length);
        for (int offset = 0; offset < length; ) {
           final int codepoint = line.codePointAt(offset);
    
           // do something with the codepoint
           if (codepoint > LAST_3_BYTE_UTF_CHAR.codePointAt(0)) { //4-byte UTF replace
               b.append(REPLACEMENT_CHAR);
           } else if( codepoint == 133){ //NEL or x'c285 
               b.append(REPLACEMENT_CHAR);
           } else {
               if (Character.isValidCodePoint(codepoint)) {
                   b.appendCodePoint(codepoint);
               } else {
                   b.append(REPLACEMENT_CHAR);
               }
           }
           offset += Character.charCount(codepoint);
        }
        return b.toString();
    }