java.lang.IllegalArgumentException:非法字符(d83d)

时间:2016-05-28 13:52:44

标签: java android xml unicode xml-serialization

在我的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)

首要问题是 :我该如何修复它,以免我的用户在emojis上崩溃...

后续问题是:

这个KXmlSerializer应该支持表情符号/ Unicode吗?

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

谁在维护KXmlSerializer? 是http://kxml.org/吗?我找不到多少......

如果放在class-path上的更新版本是否会与Android内置版本冲突?

我应该/可以使用哪些其他xml-writing lib来替换KXmlSerializer?

编辑 :我将补充说,应用程序通过xml保存的文本来自用户输入文本的标准Android EditText UI小部件(我不是对字符串执行任何Unicode级操作。

2 个答案:

答案 0 :(得分:3)

我在我的测试设备(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.So将该类用作:

final XmlSerializer serializer = new TestKXmlSerializer();

API17,API20,API23可以。

答案 1 :(得分:2)

以下是导致问题的代码。

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代码点的序列化。 (如果是这种情况,我的诊断将是不正确的。)

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