java - Error al deserializar el objeto XML utilizando el marco SimpleXML solo en Android
xml-parsing simple-framework (0)
De acuerdo, hace dos días que me estoy dando palmadas en este problema sin una solución (buscando en Internet y las publicaciones de StackOverflow posibles soluciones sin éxito), así que quizás alguien más sepa qué está pasando aquí.
Estoy tratando de analizar JMDict con SimpleXML, pero estoy recibiendo errores realmente extraños. La otra cosa extraña es que los errores solo ocurren cuando estoy depurando en Android (SDK 23, versión 6.0.1), nunca localmente en mi caja (como una prueba de unidad). Hay 2 errores que estoy recibiendo actualmente:
Error 1
org.xmlpull.v1.XmlPullParserException: Unexpected token (position:TEXT/n@399:1 in java.io.InputStreamReader@e2fbd29)
Sé lo que está causando este error es el comentario entre la declaración DTD y el elemento raíz, y la nueva línea que está allí. Se va cuando se elimina.
<!ENTITY joc "jocular, humorous term">
<!ENTITY anat "anatomical term">
]>
<!-- JMdict created: 2016-04-26 -->
<JMdict>
<entry>
Pero, ¿por qué sucede esto? ¿Cómo puedo suprimir este error? Y más importante aún, ¿por qué ocurre solo cuando lo ejecuto en Android? (Funciona completamente bien en mi prueba de unidad)
Error 2
04-27 23:58:13.038 9527-9527/ca.fuwafuwa.kaku W/System.err: org.xmlpull.v1.XmlPullParserException: unresolved: &n; (position:ENTITY_REF null@408:9 in java.io.InputStreamReader@bc1fe42)
El error que está causando esto es probablemente:
<entry>
<ent_seq>1000000</ent_seq>
<r_ele>
<reb>ヽ</reb>
</r_ele>
<r_ele>
<reb>くりかえし</reb>
</r_ele>
<sense>
<pos>&n;</pos> <------------------------------------ THIS GUY
<gloss>repetition mark in katakana</gloss>
<gloss xml:lang="ita">simbolo di ripetizione in katakana</gloss>
</sense>
</entry>
Excepto que esto definitivamente se define en la DTD:
<!ENTITY n "noun (common) (futsuumeishi)">
Cosas intentadas
Y de nuevo, estos dos errores NO se producen cuando se ejecutan como una prueba unitaria (en la computadora, no en un dispositivo / emulador Android), y todo el JMDict se analiza correctamente. Aquí está la prueba de la unidad:
public class ExampleUnitTest {
@BeforeClass
public static void ClassSetup(){
// Needed because there''s a 64000 default limit in the JDK
// I didn''t see this limit on Android for some reason
System.setProperty("jdk.xml.entityExpansionLimit", "0");
}
@Test
public void wtfXmlSrsly() throws Exception {
Serializer serializer = new Persister();
File file = new File("D://Android//JMDictOriginal.xml");
JmDict dict = serializer.read(JmDict.class, file, false);
}
}
Aquí está la versión de Android fallando gloriosamente:
public void parseDict() throws Exception{
Log.d(TAG, "INITIALIZING DICTIONARY");
long startTime = System.currentTimeMillis();
Serializer serializer = new Persister();
String fileLoc = mContext.getExternalFilesDir(null).getAbsolutePath();
File file = new File(fileLoc, "JMDict.xml");
Log.d(TAG, file.getAbsolutePath());
JmDict dict = serializer.read(JmDict.class, file, false);
Log.d(TAG, String.format("FINISHED, TOOK %d", System.currentTimeMillis() - startTime));
}
Por lo que puedo decir, básicamente están haciendo lo mismo.
Objetos de deserialización SimpleXML
@Root(name="JMdict")
public class JmDict {
@ElementList(entry = "entry", inline = true)
List<JmEntry> entry;
}
@Root(name="entry")
public class JmEntry {
@Element(name = "ent_seq")
private String ent_seq;
@ElementList(entry = "k_ele", inline = true, required = false)
private List<JmKEle> k_ele;
@ElementList(entry = "r_ele", inline = true)
private List<JmREle> r_ele;
@Element(name = "info", required = false)
private JmInfo info;
@ElementList(entry = "sense", inline = true)
private List<JmSense> sense;
}
@Root(name = "k_ele")
public class JmKEle {
@Element(name = "keb")
private String keb;
@ElementList(entry = "ke_inf", inline = true, required = false)
private List<String> ke_inf;
@ElementList(entry = "ke_pri", inline = true, required = false)
private List<String> ke_pri;
}
@Root(name = "r_ele")
public class JmREle {
@Element(name = "reb")
private String reb;
@Element(name = "re_nokanji", required = false)
private String re_nokanji;
@ElementList(entry = "re_restr", inline = true, required = false)
private List<String> re_restr;
@ElementList(entry = "re_inf", inline = true, required = false)
private List<String> re_inf;
@ElementList(entry = "re_pri", inline = true, required = false)
private List<String> re_pri;
}
@Root(name = "info")
public class JmInfo {
@ElementList(entry = "links", inline = true, required = false)
private List<Links> links;
@ElementList(entry = "bibl", inline = true, required = false)
private List<Bibl> bibl;
@ElementList(entry = "etym", inline = true, required = false)
private List<String> etym;
@ElementList(entry = "audit", inline = true, required = false)
private List<Audit> audit;
}
@Root(name = "links")
public class Links {
@Element(name = "link_tag")
private String link_tag;
@Element(name = "link_desc")
private String link_desc;
@Element(name = "link_uri")
private String link_uri;
}
@Root(name = "bibl")
public class Bibl {
@Element(name = "bib_tag", required = false)
private String bib_tag;
@Element(name = "bib_txt", required = false)
private String bib_txt;
}
@Root(name = "audit")
public class Audit {
@Element(name = "upd_date")
private String upd_date;
@Element(name = "upd_detl")
private String upd_detl;
}
@Root(name = "sense")
public class JmSense {
@ElementList(entry = "stagk", inline = true, required = false)
private List<String> stagk;
@ElementList(entry = "stagr", inline = true, required = false)
private List<String> stagr;
@ElementList(entry = "pos", inline = true, required = false)
private List<String> pos;
@ElementList(entry = "xref", inline = true, required = false)
private List<String> xref;
@ElementList(entry = "ant", inline = true, required = false)
private List<String> ant;
@ElementList(entry = "field", inline = true, required = false)
private List<String> field;
@ElementList(entry = "misc", inline = true, required = false)
private List<String> misc;
@ElementList(entry = "s_inf", inline = true, required = false)
private List<String> s_inf;
@ElementList(entry = "lsource", inline = true, required = false)
private List<String> lsource;
@ElementList(entry = "dial", inline = true, required = false)
private List<String> dial;
@ElementList(entry = "gloss", inline = true, required = false)
private List<String> gloss;
@ElementList(entry = "example", inline = true, required = false)
private List<String> example;
}
Alternativas
Alternativamente, si alguien puede sugerir un marco de análisis XML en Android que realmente funcione para este caso de uso, eso también funciona. También debería manejar este caso (SimpleXML no lo hace muy bien):
<!ELEMENT gloss (#PCDATA | pri)*>
<!ELEMENT pri (#PCDATA)>
<!-- Above breaks down into: -->
<gloss>GLOSS TEXT</gloss>
<!-- or -->
<gloss><pri>PRI TEXT</pri></gloss>
Pensé que el análisis de XML ya era un problema resuelto. Nunca esperé quedar atrapado en el análisis XML durante 3 días seguidos: /
Actualizar
De acuerdo, estoy casi seguro de que algo está roto en Android ahora, y no puede analizar entidades DTD o algo así. Leí aquí que debe excluir algunas dependencias que están predeterminadas en Android. ¿Tal vez la implementación cambió de alguna manera?
Ni siquiera pude analizar este archivo XML realmente simple con una declaración ENTITY:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XmlTest [
<!ELEMENT XmlTest (sometest, atest*)>
<!ELEMENT sometest (#PCDATA) >
<!ELEMENT atest (#PCDATA) >
<!ENTITY noun "noun">
]><XmlTest>
<sometest>sometest</sometest>
<atest>test1</atest>
<atest>&noun;</atest>
</XmlTest>
Resultó en:
org.xmlpull.v1.XmlPullParserException: unresolved: &noun; (position:ENTITY_REF null@10:18 in java.io.InputStreamReader@4c793e1)