2010-03-09 13 views
10

¿Cómo puedo forzar a un analizador SAX (específicamente, Xerces en Java) a usar un DTD al analizar un documento sin tener ningún doctype en el documento de entrada? ¿Esto es posible?¿Cómo puedo forzar a un analizador SAX a usar un DTD si no se especifica uno en el archivo de entrada?

Éstos son algunos más detalles de mi escenario:

Tenemos un montón de documentos XML que se ajusten a la misma DTD que se generan por varios sistemas diferentes (ninguno de los cuales puedo cambiar). Algunos de estos sistemas agregan un tipo de documento a sus documentos de salida, otros no. Algunos usan entidades de caracteres con nombre, otros no. Algunos usan entidades de caracteres nombrados sin declarar un doctype. Sé que no es kosher, pero es con lo que tengo que trabajar.

Estoy trabajando en el sistema que necesita analizar estos archivos en Java. Actualmente, maneja los casos anteriores leyendo por primera vez en el documento XML como una secuencia, intentando detectar si tiene un tipo de documento definido y agregando una declaración de tipo de documento si uno no está presente. El problema es que este código tiene errores, y me gustaría reemplazarlo con algo más limpio.

Los archivos son grandes, por lo que No puedo usar una solución DOM. También estoy tratando de resolver las entidades de caracteres, por lo que no ayuda a a usar un esquema XML.

Si tiene una solución, ¿podría publicarla directamente en lugar de enlazarla? No hace mucho Stack Overflow si en el futuro hay una solución correcta con un enlace muerto.

Respuesta

1

Creo que no es una buena manera de configurar DOCTYPE, si el documento no tiene una. La posible solución es escribir uno falso, como ya lo hace. Si está utilizando SAX, puede usar esta implementación falsa de InputStream y Falsificación de DefaultHandler. (solo funcionará para la codificación latin1 de un byte)

Conozco esta solución también fea, pero solo una funciona bien con grandes flujos de datos.

Aquí hay algunos códigos.

private enum State {readXmlDec, readXmlDecEnd, writeFakeDoctipe, writeEnd}; 

private class MyInputStream extends InputStream{ 

    private final InputStream is; 
    private StringBuilder sb = new StringBuilder(); 
    private int pos = 0; 
    private String doctype = "<!DOCTYPE register SYSTEM \"fake.dtd\">"; 
    private State state = State.readXmlDec; 

    private MyInputStream(InputStream source) { 
     is = source; 
    } 
    @Override 
    public int read() throws IOException { 
     int bit; 

     switch (state){ 
      case readXmlDec: 
       bit = is.read(); 
       sb.append(Character.toChars(bit)); 
       if(sb.toString().equals("<?xml")){ 
        state = State.readXmlDecEnd; 
       } 
       break; 
      case readXmlDecEnd: 
       bit = is.read(); 
       if(Character.toChars(bit)[0] == '>'){ 
        state = State.writeFakeDoctipe; 
       } 
       break; 
      case writeFakeDoctipe: 
       bit = doctype.charAt(pos++); 
       if(doctype.length() == pos){ 
        state = State.writeEnd; 
       } 
       break; 
      default: 
       bit = is.read(); 
       break; 
     } 
     return bit; 
    } 

    @Override 
    public void close() throws IOException { 
     super.close(); 
     is.close(); 
    } 
} 

private static class MyHandler extends DefaultHandler { 

    @Override 
    public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException { 
     System.out.println("resolve "+ systemId); 
     // get real dtd 
     InputStream is = ClassLoader.class.getResourceAsStream("/register.dtd"); 
     return new InputSource(is); 
    } 

... // rest of code 
} 
Cuestiones relacionadas