2010-03-09 7 views
10

Come posso forzare un parser SAX (in particolare, Xerces in Java) per utilizzare una DTD durante l'analisi di un documento senza avere qualsiasi doctype nel documento di input? È possibile?Come posso forzare un parser SAX a usare una DTD se non ne viene specificato uno nel file di input?

Qui ci sono alcuni dettagli della mia situazione:

Abbiamo un mucchio di documenti XML conformi allo stesso DTD che sono generati da più sistemi differenti (nessuno dei quali posso cambiare). Alcuni di questi sistemi aggiungono un doctype ai loro documenti di output, altri no. Alcuni usano entità di carattere nominate, altre no. Alcuni usano entità di carattere denominate senza dichiarare un doctype. So che non è kosher, ma è quello con cui devo lavorare.

Sto lavorando al sistema che deve analizzare questi file in Java. Attualmente, gestisce i casi di cui sopra leggendo prima il documento XML come uno stream, tentando di rilevare se ha un doctype definito e aggiungendo una dichiarazione doctype se uno non è già presente. Il problema è che questo codice è bacato e mi piacerebbe sostituirlo con qualcosa di più pulito.

I file sono grandi, quindi Non è possibile utilizzare una soluzione basata su DOM. Sto anche cercando di risolvere le entità dei caratteri, quindi non aiuta a utilizzare uno schema XML.

Se si dispone di una soluzione, si prega di postarlo direttamente invece di collegarlo ad esso? Non fa molto bene lo Stack Overflow se in un futuro c'è una soluzione corretta con un link morto.

risposta

1

Penso che non sia un modo corretto per impostare DOCTYPE, se il documento non ne ha uno. La soluzione possibile è scrivere uno falso, come già fai tu. Se si utilizza SAX, è possibile utilizzare questo InputStream falso e un'implementazione di DefaultHandler contraffatta. (funzionerà solo per la codifica a 1 byte latin1)

Conosco anche questa soluzione, ma funziona bene solo con flussi di dati di grandi dimensioni.

Ecco un codice.

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 
} 
Problemi correlati