问题
I have to use commons-digester.jar for processing xml files in android actually this was open source program that uses commons-digester.jar for xml processing in Java and I need to change it to support Android but this error happens :
Digester.getParser: java.lang.UnsupportedOperationException: This parser does not support specification "Unknown" version "0.0"
java.lang.NullPointerException 03-29 11:24:02.590: W/System.err(17018): at org.apache.commons.digester3.Digester.getXMLReader(Digester.java:790) 03-29 11:24:02.590: W/System.err(17018): at org.apache.commons.digester3.Digester.parse(Digester.java:1588) 03-29 11:24:02.590: W/System.err(17018): at org.apache.commons.digester3.Digester.parse(Digester.java:1557) 03-29 11:24:02.590: W/System.err(17018): at com.tashkeel.android.utilities.alkhalil.DbLoader.LoadPrefixes(DbLoader.java:65) 03-29 11:24:02.590: W/System.err(17018): at com.tashkeel.android.utilities.alkhalil.analyse.Analyzer.(Analyzer.java:64) 03-29 11:24:02.600: W/System.err(17018): at com.tashkeel.android.MainActivity$1.run(MainActivity.java:80) 03-29 11:24:02.600: W/System.err(17018): at java.lang.Thread.run(Thread.java:856) 03-29 11:24:03.240: W/System.err(17018):
and sample of code that uses commons-digester
Digester digester = new Digester();
digester.addObjectCreate("prefixes", Lists.class);
digester.addObjectCreate("prefixes/prefixe", Prefixe.class);
digester.addSetProperties("prefixes/prefixe", "unvoweledform",
"unvoweledform");
digester.addSetProperties("prefixes/prefixe", "voweledform",
"voweledform");
digester.addSetProperties("prefixes/prefixe", "desc", "desc");
digester.addSetProperties("prefixes/prefixe", "classe", "classe");
digester.addSetNext("prefixes/prefixe", "addPrefixe");
return (Lists)digester.parse(pref);
part of xml that I try to parse :
<?xml version="1.0" encoding="utf-8" ?>
<prefixes>
<prefixe unvoweledform="" voweledform="" desc="" classe="C1">
</prefixe>
<prefixe unvoweledform="و" voweledform="وَ" desc="حرف العطف" classe="C1">
</prefixe>
<prefixe unvoweledform="ف" voweledform="فَ" desc="حرف العطف أو الاستئناف"
classe="C1">
</prefixe>
</prefixes>
回答1:
Looking at the source code for Digester, what it comes down to appears to be this code:
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware( namespaceAware );
factory.setXIncludeAware( xincludeAware );
factory.setValidating( validating );
factory.setSchema( schema );
Then checking the JavaDoc for SAXParserFactory#setSchema:
A parser must be able to work with any Schema implementation... Throws: UnsupportedOperationException - When implementation does not override this method.
So my guess is the SAXParserFactory
implementation your code is receiving does not support schemas in some way.
There are some tips for troubleshooting in the SAXParserFactory.html#newInstance doco, but you can also just find the exact parser class being returned with the following (no Digester code required):
SAXParserFactory factory = SAXParserFactory.newInstance();
System.err.println("SAXParserFactory class is " + factory.getClass().getName());
Also, from the Android SAXParserFactory doco:
UnsupportedOperationException For backward compatibility, when implementations for earlier versions of JAXP is used, this exception will be thrown.
So you may want to check the versions of JAXP etc. you are using.
Update
Given that you do not need schemas, you can try this which may work... instead of letting the digester create the SAXParserFactory
for you, create one yourself - that way you can avoid the call to setSchema
which looks like it may be the problem:
// create your own SAXParserFactory, but don't call any of the set methods unless you explicitly need to
final SAXParserFactory myfactory = SAXParserFactory.newInstance();
//myfactory.setNamespaceAware( namespaceAware );
//myfactory.setXIncludeAware( xincludeAware );
//myfactory.setValidating( validating );
//myfactory.setSchema( schema );
// create your own Digester and override the getFactory method to return your own factory
Digester digester = new Digester() {
@Override
public SAXParserFactory getFactory() {
return myfactory;
}
};
// use this digester as normal for the rest of your code...
Not doing any android development at the moment so can't test this, but looks like it could work...
Update 2
So that looked like it fixed the schema problem, and what you have now appears to be a separate class loader issue. That's actually a separate question, but here's a possible hack... bypass the banutils introspection and just process the attributes yourself with a custom rule. This is only really practical because you have fairly simple XML in your example - anything more complicated that that and this approach becomes unworkable:
final List<Prefixe> list = new ArrayList<>();
final SAXParserFactory factory = SAXParserFactory.newInstance();
Digester digester = new Digester() {
@Override
public SAXParserFactory getFactory() {
System.out.println("using custom factory...");
return factory;
}
};
digester.addRule("prefixes/prefixe", new Rule() {
@Override
public void begin(String namespace, String name, Attributes attributes) throws Exception {
Prefixe prefixe = new Prefixe();
prefixe.setUnvoweledform(attributes.getValue("unvoweledform"));
prefixe.setVoweledform(attributes.getValue("voweledform"));
prefixe.setDesc(attributes.getValue("desc"));
prefixe.setClasse(attributes.getValue("classe"));
list.add(prefixe);
}
});
digester.parse(...);
Please note that it looks like you have classloader issues somewhere (unless the version of beanutils you have has been crippled in some way?) and I'd strongly recommend you try to get to the bottom of those as they may come back to bite you again and again...
Good luck!
回答2:
final answer after little bit modification from @Barney answer to make returned lists from the function add prefix inside addRule function :
public Lists LoadPrefixes() throws Exception {
InputStream in = assetManager.open("db/prefixes.xml");
final SAXParserFactory factory = SAXParserFactory.newInstance();
Digester digester = new Digester() {
@Override
public SAXParserFactory getFactory() {
//System.out.println("using custom factory...");
return factory;
}
};
final Lists Lists_ob=new Lists();
digester.addRule("prefixes/prefixe", new Rule() {
@Override
public void begin(String namespace, String name, Attributes attributes) throws Exception {
Prefixe prefixe = new Prefixe();
prefixe.setUnvoweledform(attributes.getValue("unvoweledform"));
prefixe.setVoweledform(attributes.getValue("voweledform"));
prefixe.setDesc(attributes.getValue("desc"));
prefixe.setClasse(attributes.getValue("classe"));
Lists_ob.addPrefixe(prefixe);
}
});
digester.parse(in);
return Lists_ob;
}
and this is code was originally inside Lists.class
private List prefixes = new LinkedList();
public void addPrefixe(Prefixe p) {
prefixes.add(p);
}
来源:https://stackoverflow.com/questions/29327630/android-with-commons-digester-java-lang-unsupportedoperationexception-this-pars