2010-07-09 10 views
2

D'abord les choses d'abord, je ne peux pas changer la sortie du xml, il est produit par un tiers. Ils insèrent des caractères invalides dans le fichier XML. On me donne un InputStream de la représentation du flux d'octets du xml. Est-ce leur façon plus propre de filtrer les personnages offensants en plus de consommer le flux dans une chaîne et de le traiter? J'ai trouvé ceci: using a FilterReader mais cela ne fonctionne pas pour moi car j'ai un flux d'octets et pas un flux de caractères. Pour que cela vaille la peine, tout cela fait partie d'une procédure jmab unmarshalling, juste au cas où des options sont proposées.filtre/supprimer les caractères xml invalides du flux

Nous ne sommes pas prêts à jeter le flux entier s'il a de mauvais caractères. Nous avons décidé de les enlever et de continuer.

Voici un FilterReader que j'ai essayé de construire.

public class InvalidXMLCharacterFilterReader extends FilterReader 
{ 

private static final Log LOG = LogFactory 
.getLog(InvalidXMLCharacterFilterReader.class); 

public InvalidXMLCharacterFilterReader(Reader in) 
{ 
    super(in); 
} 

public int read() throws IOException { 
    char[] buf = new char[1]; 
    int result = read(buf, 0, 1); 
    if (result == -1) 
     return -1; 
    else 
     return (int) buf[0]; 
} 

public int read(char[] buf, int from, int len) throws IOException { 
    int count = 0; 
    while (count == 0) { 
     count = in.read(buf, from, len); 
     if (count == -1) 
      return -1; 

     int last = from; 
     for (int i = from; i < from + count; i++) { 
      LOG.debug("" + (char)buf[i]); 
      if(!isBadXMLChar(buf[i])) 
      { 
       buf[last++] = buf[i]; 
      } 
     } 

     count = last - from; 
    } 
    return count; 
} 

private boolean isBadXMLChar(char c) 
{ 
    if ((c == 0x9) || 
     (c == 0xA) || 
     (c == 0xD) || 
     ((c >= 0x20) && (c <= 0xD7FF)) || 
     ((c >= 0xE000) && (c <= 0xFFFD)) || 
     ((c >= 0x10000) && (c <= 0x10FFFF))) 
    { 
     return false; 
    } 
    return true; 
} 

}

Et voici comment je suis unmarshalling il:

jaxbContext = JAXBContext.newInstance(MyObj.class); 
Unmarshaller unMarshaller = jaxbContext.createUnmarshaller(); 
Reader r = new InvalidXMLCharacterFilterReader(new BufferedReader(new InputStreamReader(is, "UTF-8"))); 
MyObj obj = (MyObj) unMarshaller.unmarshal(r); 

et certains mauvais exemple xml

<?xml version="1.0" encoding="UTF-8" ?> 
<foo> 
    bar&#x01; 
</foo> 
+2

Etes-vous sûr que * ils * insèrent des caractères non valides? N'est-ce pas vous qui lisez les caractères du flux binaire en utilisant le mauvais encodage et/ou en affichant les caractères lus en utilisant le mauvais encodage? – BalusC

+0

Vous devriez vérifier le commentaire de BalusC. Si vous voulez continuer avec une implémentation FilteredReader, vous n'avez aucun problème à transformer le flux d'octets en un lecteur (en utilisant InputStreamReader), à condition que vous connaissiez le codage du flux d'octets. –

+0

Je ne sais pas ce que BalusC veut dire. Ce sont des caractères XML 1.0 manifestement invalides. J'ai essayé d'utiliser un InputStreamReader (ainsi que l'emballage dans un lecteur tamponné) sans aucune chance. Je vais mettre à jour ma question avec du code. – DanInDC

Répondre

1

Afin de le faire avec un filtre, la le filtre doit être conscient de l'entité XML, car (au moins dans votre exemple et probablement parfois en utilisation réelle) les mauvais caractères sont en le xml en tant qu'entités. Le filtre voit votre entité comme une séquence de 6 caractères parfaitement acceptables et ne les dépouille donc pas.

La conversion qui interrompt JAXB se produit plus tard dans le processus.

+0

Droite. Donc, avez-vous des idées sur un filtre d'entité sensible? Ou est ma seule option pour juste le sucer dans un tampon et .replaceAll() la merde hors de lui? – DanInDC

+0

Je suis sûr que j'ai vu un exemple de code FilterReader quelque part pour filtrer par des expressions régulières. Je ne peux pas mettre la main dessus pour le moment, mais un google pourrait trouver quelque chose. Cela revient à "aspirer dans un tampon et .replaceAll() la merde", mais dans le code du filtre. –