Android离线日英词典解析JMDict XML时触发XmlPullParserException异常求助
嘿,我看你在做Jetpack Compose离线日英词典的时候,解析JMDict XML遇到了XmlPullParserException的崩溃问题,刚好我之前折腾过类似的场景,来给你梳理下大概率的问题原因和解决办法!
先说说异常的核心原因
XmlPullParserException: Unexpected token 这种报错,在解析JMDict这类自定义实体很多的XML时,90%的概率是编码不匹配或者自定义实体未被解析器识别导致的,咱们结合你的代码和JMDict的特性来拆解:
问题1:未指定XML编码
JMDict的官方XML文件默认是UTF-8编码,但你的代码里parser.setInput(input, null)没有指定编码,解析器会尝试自动推断,一旦推断错误就会把某些字节当成非法字符,触发异常。
问题2:自定义实体未被处理
你提供的XML示例里有&n;、&exp;这类标记,这些是JMDict定义的自定义实体,它们的定义都在JMdict.dtd文件里。如果你的assets目录里没有这个DTD文件,或者解析器没启用DTD处理,就会把这些实体当成非法的未知 token,直接报错。
问题3:XML文件可能不完整/损坏
如果下载的JMDict XML文件中途截断、或者下载过程中出现了数据损坏,也会导致解析器读到不合法的内容触发异常。
针对性解决步骤
1. 补全DTD文件并配置解析器
- 先把
JMdict.dtd文件下载下来(和你的JMDict XML版本匹配),放到assets目录里,和jMdict.xml同级。 - 修改你的解析函数,启用DTD处理并指定UTF-8编码:
fun countEntriesInXml(input: InputStream): Float { val parser = XmlPullParserFactory.newInstance().newPullParser() // 启用DTD解析,让解析器能识别JMDict的自定义实体 parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true) // 明确指定UTF-8编码,避免自动推断出错 parser.setInput(input, "UTF-8") var count = 0 var event = parser.eventType while (event != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG && parser.name == "entry") { count++ } // 正常推进解析,这里如果还是遇到异常,可以临时跳过标签(不推荐,优先解决根本问题) event = try { parser.next() } catch (e: XmlPullParserException) { parser.nextTag() } } return count.toFloat() }
2. 验证XML文件完整性
检查assets里的jMdict.xml文件大小是否和官方下载的一致,也可以用电脑上的XML编辑器(比如VS Code的XML插件)打开看看,能不能正常解析,有没有报错的节点。
3. 优化资源加载(可选)
JMDict的XML文件非常大,直接在主线程解析会导致ANR甚至崩溃,建议把解析逻辑放到WorkManager或者Coroutine的IO线程里执行,避免阻塞主线程。
你可以先试试前两个核心步骤,尤其是补全DTD文件和指定编码,应该能解决当前的异常。如果还是有问题,可以在捕获异常时打印parser.position()和parser.text,看看具体是哪个位置的内容触发了错误,方便进一步定位。
内容来源于stack exchange




