【问题标题】:java.lang.IllegalArgumentException: Illegal character (d83d)java.lang.IllegalArgumentException:非法字符(d83d)
【发布时间】:2016-09-26 18:13:22
【问题描述】:

在我的 Android 应用程序中保存 XML 数据文件时,当用户输入表情符号时出现异常。 据我了解,d83d 字符就是这个:http://apps.timwhitlock.info/unicode/inspect?s=%F0%9F%98%84 - 笑脸????字符。

相关的堆栈跟踪:

java.lang.IllegalArgumentException: Illegal character (d83d)
at org.kxml2.io.KXmlSerializer.reportInvalidCharacter(KXmlSerializer.java:144)
at org.kxml2.io.KXmlSerializer.writeEscaped(KXmlSerializer.java:130)
at org.kxml2.io.KXmlSerializer.attribute(KXmlSerializer.java:465)

最重要的问题是:我该如何解决它,这样我的用户才不会遇到应用在表情符号上崩溃...

后续问题是:

这个 KXmlSerializer 是否应该支持 emoji/Unicode?​​p>

某处有更新版本吗?到目前为止我找不到它。 该库是否得到积极维护?

谁在维护 KXmlSerializer? 是http://kxml.org/ 吗?我在那里找不到很多东西......

如果放在 class-path 上,更新版本会不会与 Android 内置版本发生冲突?

我应该/可以使用哪些其他 xml 编写库来替换 KXmlSerializer?

编辑:我要补充一点,应用程序通过 xml 保存的文本来自标准的 Android EditText UI 小部件,用户可以在其中输入文本(我没有对字符串进行任何 Unicode 级别的操作)。

【问题讨论】:

  • 这个补丁可能是相关的:android.googlesource.com/platform/libcore/+/3f1a5eb%5E! 但我想知道从哪里获得正确的二进制文件。
  • Android 联系人与表情符号同步的可能相关问题:code.google.com/p/android/issues/detail?id=64108。一位项目成员写道“我在 L 中修复了 KXmlSerializer。”
  • 你知道你是如何解决这个问题的吗?我还想知道在哪里可以找到具有该修复程序的最新依赖项。它仍然向我显示 2.3.0,我猜它最后一次更新是在 2009 年。

标签: java android xml unicode xml-serialization


【解决方案1】:

这是导致我认为的问题的代码。

boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
if (allowedInXml) {
    if (unicode || c < 127) {
        append(c);
    } else {
        append("&#" + ((int) c) + ";");
    }
} else if (Character.isHighSurrogate(c) && i < s.length() - 1) {
    writeSurrogate(c, s.charAt(i + 1));
    ++i;
} else {
    reportInvalidCharacter(c);
}

(在这里找到:https://android.googlesource.com/platform/libcore/+/master/xml/src/main/java/org/kxml2/io/KXmlSerializer.java

您似乎正在尝试编写 unicode 代码点 1F604,它表示为 D83D DE04 的代理对。请注意,“高”代理范围是 D800-DBFF。

如果我们将它输入到代码中,我们会看到 D83D 应该是可以接受的,但前提是它后面跟着另一个字符。 (writeSurrogate 方法检查第二个字符是否为低代理,但如果不是,则会收到不同的异常消息。)

所以我的诊断是,你不知何故丢失了构成表情符号的第二个字符。在责怪序列化程序类之前,检查该属性的值以确认/反驳该诊断。它试图执行的检查完全符合犹太教规。


更新

提示您可能正在使用不支持非 BMP 代码点序列化的序列化程序的早期版本。 (如果是这样的话,我的诊断就不正确了。)

我不知道你会如何解决这个问题。

【讨论】:

  • 嗨。谢谢。编辑:我要补充一点,应用程序通过 xml 保存的文本来自用户输入文本的标准 Android EditText UI 小部件(我不对字符串进行任何 Unicode 级别的操作)。似乎在游戏后期(2014)中添加了“对非 BMP 字符的支持” - android.googlesource.com/platform/libcore/+/3f1a5eb%5E! 。如果目标设备有旧版本怎么办?我可以发布 XML 类的更新版本吗?
【解决方案2】:

我的测试设备 (API17) 出现相同的异常。代码如下:

final XmlSerializer serializer = new Xml.newSerializer();
final StringWriter stringWriter = new StringWriter();
serializer.setOutput(stringWriter);
serializer.startDocument("UTF-8", true);
serializer.startTag("", "XXXX");
....
serializer.endTag("", "XXXX");
serializer.endDocument();
writer.write(stringWriter.toString());
writer.close();

但是代码在 API21 和 API23 上都可以。

API17中,KXmlSerializer的关键代码:

// BEGIN android-changed: refuse to output invalid characters
// See http://www.w3.org/TR/REC-xml/#charsets for definition.
// No other Java XML writer we know of does this, but no Java
// XML reader we know of is able to parse the bad output we'd
// otherwise generate.
// Note: tab, newline, and carriage return have already been
// handled above.
boolean valid = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
if (!valid) {
    reportInvalidCharacter(c);
}
if (unicode || c < 127) {
    writer.write(c);
} else {
    writer.write("&#" + ((int) c) + ";");
}
// END android-changed

API23中,KXmlSerializer的关键代码:

// BEGIN android-changed: refuse to output invalid characters
// See http://www.w3.org/TR/REC-xml/#charsets for definition.
// No other Java XML writer we know of does this, but no Java
// XML reader we know of is able to parse the bad output we'd
// otherwise generate.
// Note: tab, newline, and carriage return have already been
// handled above.
boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
if (allowedInXml) {
    if (unicode || c < 127) {
        writer.write(c);
    } else {
        writer.write("&#" + ((int) c) + ";");
    }
} else if (Character.isHighSurrogate(c) && i < s.length() - 1) {
    writeSurrogate(c, s.charAt(i + 1));
    ++i;
} else {
    reportInvalidCharacter(c);
}
// END android-changed

Exception的原因,你可以阅读Stephen C的答案。

最后,我从 kXML(https://sourceforge.net/projects/kxml/files/kxml2/2.3.0/) 下载了类 KXmlSerializer 的最新代码。并添加到我的项目中,将该类重命名为 TestKXmlSerializer。所以将该类用作:

final XmlSerializer serializer = new TestKXmlSerializer();

API17,API20,API23都可以。

【讨论】:

    猜你喜欢
    • 2015-04-19
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    相关资源
    最近更新 更多