2010-05-24 16 views
8

La especificación XML define un subconjunto de caracteres Unicode que están permitidos en documentos XML: http://www.w3.org/TR/REC-xml/#charsets.Filtrado de caracteres XML ilegales en Java

¿Cómo puedo filtrar estos caracteres de una cadena en Java?

caso de prueba sencilla:

Assert.equals("", filterIllegalXML(""+Character.valueOf((char) 2))) 
+0

¿Por qué obtiene estos caracteres XML "ilegales"? ¿Qué quieres hacer con ellos una vez que los detectas? ¿borrar? ¿reemplazar? –

+0

@RH: ignorarlos sería suficiente. La mejor solución sería eliminarlos y obtener algún tipo de informe. De esta forma podría registrar una advertencia. –

+0

En caso de que alguien se pregunte, aproveché el 'XMLChar' de Xerces, como lo sugirió ZZ Coder. Puedes encontrar el método completo aquí: http://pastebin.com/6Vbm1zuC –

Respuesta

5

No es trivial descubrir todos los caracteres inválidos para XML. Es necesario llamar o reimplementar la XMLChar.isInvalid() desde Xerces,

http://kickjava.com/src/org/apache/xerces/util/XMLChar.java.htm

+0

+1, buen hallazgo .. – Bozho

+0

Esa clase es bastante complicada [léase: difícil de entender, para mí de todos modos gracias a su sección generada por la máquina], así como también requiere una matriz de 64K CHARS para ser instanciada y prepropagada ... – rogerdpack

0

Usando StringEscapeUtils.escapeXml(xml) de commons-lang escaparán, no filtra los caracteres.

+2

Ya estoy usando este método para escapar de entidades (por ejemplo, '<' a '<'), pero eso es algo diferente. El método no parece filtrar ningún carácter ilegal. Falla para mi 'caso de prueba'. –

+2

muestra el caso de prueba. – Bozho

+0

Como se indicó en la pregunta: 'assertEquals (" ", StringEscapeUtils.escapeXml (" "+ Character.valueOf ((char) 2)));' –

1

This page incluye un método Java para despojar a invalid XML characters comprobando si cada personaje está dentro de las especificaciones, aunque no comprueba highly discouraged caracteres

Dicho sea de paso, escaparse de los caracteres no es una solución ya que las especificaciones XML 1.0 y 1.1 tampoco permiten los caracteres no válidos en forma de escape.

+1

El enlace está muerto ... parece que esta es la nueva URL. http://benjchristensen.com/2008/02/07/how-to-strip-invalid-xml-characters/ – Michael

+0

Enlace actualizado - gracias –

0

Aquí es una solución que se encarga del carbón en bruto, así como el carbón escapado en la corriente funciona con Stax o saxo. Se necesita que se extiende a los otros caracteres no válidos, pero se entiende la idea

import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.Reader; 
import java.io.UnsupportedEncodingException; 
import java.io.Writer; 

import org.apache.commons.io.IOUtils; 
import org.apache.xerces.util.XMLChar; 

public class IgnoreIllegalCharactersXmlReader extends Reader { 

    private final BufferedReader underlyingReader; 
    private StringBuilder buffer = new StringBuilder(4096); 
    private boolean eos = false; 

    public IgnoreIllegalCharactersXmlReader(final InputStream is) throws UnsupportedEncodingException { 
     underlyingReader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
    } 

    private void fillBuffer() throws IOException { 
     final String line = underlyingReader.readLine(); 
     if (line == null) { 
      eos = true; 
      return; 
     } 
     buffer.append(line); 
     buffer.append('\n'); 
    } 

    @Override 
    public int read(char[] cbuf, int off, int len) throws IOException { 
     if(buffer.length() == 0 && eos) { 
      return -1; 
     } 
     int satisfied = 0; 
     int currentOffset = off; 
     while (false == eos && buffer.length() < len) { 
      fillBuffer(); 
     } 
     while (satisfied < len && buffer.length() > 0) { 
      char ch = buffer.charAt(0); 
      final char nextCh = buffer.length() > 1 ? buffer.charAt(1) : '\0'; 
      if (ch == '&' && nextCh == '#') { 
    final StringBuilder entity = new StringBuilder(); 
    // Since we're reading lines it's safe to assume entity is all 
    // on one line so next char will/could be the hex char 
    int index = 0; 
    char entityCh = '\0'; 
    // Read whole entity 
    while (entityCh != ';') { 
     entityCh = buffer.charAt(index++); 
     entity.append(entityCh); 
    } 
    // if it's bad get rid of it and clean it from the buffer and point to next valid char 
    if (entity.toString().equals("&#2;")) { 
     buffer.delete(0, entity.length()); 
     continue; 
    } 
      } 
      if (XMLChar.isValid(ch)) { 
    satisfied++; 
    cbuf[currentOffset++] = ch; 
      } 
      buffer.deleteCharAt(0); 
     } 
     return satisfied; 
    } 

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

    public static void main(final String[] args) { 
     final File file = new File(
    <XML>); 
     final File outFile = new File(file.getParentFile(), file.getName() 
    .replace(".xml", ".cleaned.xml")); 
     Reader r = null; 
     Writer w = null; 
     try { 
      r = new IgnoreIllegalCharactersXmlReader(new FileInputStream(file)); 
      w = new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"); 
      IOUtils.copyLarge(r, w); 
      w.flush(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      IOUtils.closeQuietly(r); 
      IOUtils.closeQuietly(w); 
     } 
    } 
} 
0

Basado libremente en un comment en el enlace de la respuesta de Stephen C, y Wikipedia para el XML 1.1 spec aquí hay un método Java que muestra cómo extraer Caracteres ilegales que usan expresión regular reemplazan:

boolean isAllValidXmlChars(String s) { 
    // xml 1.1 spec http://en.wikipedia.org/wiki/Valid_characters_in_XML 
    if (!s.matches("[\\u0001-\\uD7FF\\uE000-\uFFFD\\x{10000}-\\x{10FFFF}]")) { 
    // not in valid ranges 
    return false; 
    } 
    if (s.matches("[\\u0001-\\u0008\\u000b-\\u000c\\u000E-\\u001F\\u007F-\\u0084\\u0086-\\u009F]")) { 
    // a control character 
    return false; 
    } 

    // "Characters allowed but discouraged" 
    if (s.matches(
    "[\\uFDD0-\\uFDEF\\x{1FFFE}-\\x{1FFFF}\\x{2FFFE}–\\x{2FFFF}\\x{3FFFE}–\\x{3FFFF}\\x{4FFFE}–\\x{4FFFF}\\x{5FFFE}-\\x{5FFFF}\\x{6FFFE}-\\x{6FFFF}\\x{7FFFE}-\\x{7FFFF}\\x{8FFFE}-\\x{8FFFF}\\x{9FFFE}-\\x{9FFFF}\\x{AFFFE}-\\x{AFFFF}\\x{BFFFE}-\\x{BFFFF}\\x{CFFFE}-\\x{CFFFF}\\x{DFFFE}-\\x{DFFFF}\\x{EFFFE}-\\x{EFFFF}\\x{FFFFE}-\\x{FFFFF}\\x{10FFFE}-\\x{10FFFF}]" 
)) { 
    return false; 
    } 

    return true; 
} 
Cuestiones relacionadas