android - SchemaFactory no es compatible con W3C XML Schema en plataforma nivel 8?
xsd android-2.2-froyo (2)
Es posible que tengas algo de suerte al volver a empaquetar xerces con jarjar y luego pasar
"org.apache.xerces.jaxp.validation.XMLSchemaFactory"
a
SchemaFactory.newInstance(String schemaLanguage, String factoryClassName, ClassLoader classLoader)
si estás utilizando API> = 9 o directamente creando instancias
org.apache.xerces.jaxp.validation.XMLSchemaFactory
si está utilizando la API 8. Es posible que no funcione en absoluto con una API más antigua.
Con el SDK de Android, falla el siguiente código en una actividad simple vacía:
@Override
protected void onStart() {
super.onStart();
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
}
El logcat del emulador 2.2 muestra esta excepción:
06-28 05:38:06.107: WARN/dalvikvm(495): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
06-28 05:38:06.128: ERROR/AndroidRuntime(495): FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.HelloWorldActivity}: java.lang.IllegalArgumentException: http://www.w3.org/2001/XMLSchema
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
at android.app.ActivityThread.access$2300(ActivityThread.java:125)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: http://www.w3.org/2001/XMLSchema
at javax.xml.validation.SchemaFactory.newInstance(SchemaFactory.java:194)
at com.example.HelloWorldActivity.onStart(HelloWorldActivity.java:26)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1129)
at android.app.Activity.performStart(Activity.java:3781)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2636)
... 11 more
El Javadoc de SchemaFactory menciona "La plataforma predeterminada SchemaFactory se encuentra en una forma específica de implementación. Debe haber una plataforma predeterminada SchemaFactory para el esquema XML del W3C".
Tuve el mismo problema y leí muchas publicaciones antes de recibir una respuesta que me funcionó. La referencia a la constante no funcionará en Dalvik. Descubrí que tenía que modificar mi código para trabajar con el proyecto Xerces para Android y luego pude obtener la validación xml que buscaba. Lo más probable es lo que está haciendo con la referencia de variable. Los siguientes son detalles de la configuración y algunos ejemplos de código que muestran cómo hacer que la validación funcione en Android.
Lo siguiente me funcionó:
- Crea una utilidad de validación
- Obtenga tanto el xml como el xsd en un archivo en el sistema operativo Android y use la utilidad de validación en su contra.
- Use Xerces-For-Android para hacer la validación.
Android es compatible con algunos paquetes que podemos usar, creé mi utilidad de validación xml basada en: http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/package-summary.html
Mi prueba inicial de sandbox fue bastante suave con java, luego traté de transferirlo a Dalvik y descubrí que mi código no funcionaba. Algunas cosas simplemente no son compatibles con Dalvik, así que hice algunas modificaciones.
Encontré una referencia a xerces para Android, así que modifiqué mi prueba de sandbox ( lo siguiente no funciona con android, el ejemplo después de esto ):
import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
/**
* A Utility to help with xml communication validation.
*/
public class XmlUtil {
/**
* Validation method.
* Base code/example from: http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/package-summary.html
*
* @param xmlFilePath The xml file we are trying to validate.
* @param xmlSchemaFilePath The schema file we are using for the validation. This method assumes the schema file is valid.
* @return True if valid, false if not valid or bad parse.
*/
public static boolean validate(String xmlFilePath, String xmlSchemaFilePath) {
// parse an XML document into a DOM tree
DocumentBuilder parser = null;
Document document;
// Try the validation, we assume that if there are any issues with the validation
// process that the input is invalid.
try {
// validate the DOM tree
parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
document = parser.parse(new File(xmlFilePath));
// create a SchemaFactory capable of understanding WXS schemas
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// load a WXS schema, represented by a Schema instance
Source schemaFile = new StreamSource(new File(xmlSchemaFilePath));
Schema schema = factory.newSchema(schemaFile);
// create a Validator instance, which can be used to validate an instance document
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
} catch (Exception e) {
// Catches: SAXException, ParserConfigurationException, and IOException.
return false;
}
return true;
}
}
El código anterior tenía que modificarse para que funcione con xerces para Android ( http://gc.codehum.com/p/xerces-for-android/ ). Necesita SVN para obtener el proyecto, las siguientes son algunas notas de cuna:
download xerces-for-android
download silk svn (for windows users) from http://www.sliksvn.com/en/download
install silk svn (I did complete install)
Once the install is complete, you should have svn in your system path.
Test by typing "svn" from the command line.
I went to my desktop then downloaded the xerces project by:
svn checkout http://xerces-for-android.googlecode.com/svn/trunk/ xerces-for-android-read-only
You should then have a new folder on your desktop called xerces-for-android-read-only
Con el frasco anterior (Eventualmente lo convertiré en un frasco, simplemente lo copié directamente en mi fuente para realizar pruebas rápidas. Si desea hacer lo mismo, puede hacer el frasco rápidamente con Ant ( http://ant.apache.org/manual/using.html )), pude hacer que funcionara lo siguiente para mi validación de XML:
import java.io.File;
import java.io.IOException;
import mf.javax.xml.transform.Source;
import mf.javax.xml.transform.stream.StreamSource;
import mf.javax.xml.validation.Schema;
import mf.javax.xml.validation.SchemaFactory;
import mf.javax.xml.validation.Validator;
import mf.org.apache.xerces.jaxp.validation.XMLSchemaFactory;
import org.xml.sax.SAXException;
/**
* A Utility to help with xml communication validation.
*/public class XmlUtil {
/**
* Validation method.
*
* @param xmlFilePath The xml file we are trying to validate.
* @param xmlSchemaFilePath The schema file we are using for the validation. This method assumes the schema file is valid.
* @return True if valid, false if not valid or bad parse or exception/error during parse.
*/
public static boolean validate(String xmlFilePath, String xmlSchemaFilePath) {
// Try the validation, we assume that if there are any issues with the validation
// process that the input is invalid.
try {
SchemaFactory factory = new XMLSchemaFactory();
Source schemaFile = new StreamSource(new File(xmlSchemaFilePath));
Source xmlSource = new StreamSource(new File(xmlFilePath));
Schema schema = factory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(xmlSource);
} catch (SAXException e) {
return false;
} catch (IOException e) {
return false;
} catch (Exception e) {
// Catches everything beyond: SAXException, and IOException.
e.printStackTrace();
return false;
} catch (Error e) {
// Needed this for debugging when I was having issues with my 1st set of code.
e.printStackTrace();
return false;
}
return true;
}
}
Algunas notas secundarias:
Para crear los archivos, hice una utilidad de archivo simple para escribir cadenas en los archivos:
public static void createFileFromString(String fileText, String fileName) {
try {
File file = new File(fileName);
BufferedWriter output = new BufferedWriter(new FileWriter(file));
output.write(fileText);
output.close();
} catch ( IOException e ) {
e.printStackTrace();
}
}
También necesitaba escribir en un área a la que tenía acceso, por lo que hice uso de:
String path = this.getActivity().getPackageManager().getPackageInfo(getPackageName(), 0).applicationInfo.dataDir;
Un poco hackish, funciona. Estoy seguro de que hay una manera más sucinta de hacer esto, sin embargo, pensé que iba a compartir mi éxito, ya que no encontré ningún buen ejemplo.