2010-05-24 8 views
8

XML-Spezifikation definiert eine Teilmenge von Unicode-Zeichen, die in XML-Dokumenten zulässig sind: http://www.w3.org/TR/REC-xml/#charsets.Filtern von ungültigen XML-Zeichen in Java

Wie filtere ich diese Zeichen aus einem String in Java?

einfacher Testfall:

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

Warum erhalten Sie diese "illegalen" XML-Zeichen? Was möchten Sie damit machen, wenn Sie sie einmal entdeckt haben? löschen? ersetzen? –

+0

@RH: es zu ignorieren wäre genug. Die beste Lösung wäre, sie zu löschen und eine Art von Bericht zu erhalten. Auf diese Weise konnte ich eine Warnung protokollieren. –

+0

Falls jemand sich wunderte, dass ich 'XMLChar' von Xerces ausnutzte, wie von ZZ Coder vorgeschlagen. Sie können die ganze Methode hier finden: http://pastebin.com/6Vbm1zuC –

Antwort

5

Es ist nicht trivial, alle ungültigen Zeichen für XML zu finden. Sie müssen rufen oder die XMLChar.isInvalid() von Xerces reimplementieren,

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

+0

+1, nice find .. – Bozho

+0

Diese Klasse ist ziemlich involviert [lese: schwer zu verstehen - für mich sowieso dank ihrer maschinengenerierten Sektion], ebenso wie ein 64K CHARS Array instanziiert und vorverbreitet werden muss ... – rogerdpack

0

Mit StringEscapeUtils.escapeXml(xml) von commons-lang entkommen, nicht die Zeichen filtert.

+2

Ich benutze bereits diese Methode, um Entitäten zu entgehen (z.B. '<' '' < '), aber das ist etwas anderes. Die Methode scheint keine unzulässigen Zeichen zu filtern. Es schlägt für meinen "Testfall" fehl. –

+2

zeigen Sie den Testfall. – Bozho

+0

Wie in der Frage angegeben: 'assertEquals (" ", StringEscapeUtils.escapeXml (" "+ Character.valueOf ((char) 2)));' –

1

This pageinvalid XML characters zum Strippen eine Java-Methode enthält, indem geprüft wird, ob jedes Zeichen innerhalb der Spezifikation ist, wenn es nicht für highly discouraged überprüft Zeichen

Im Übrigen ist das Entkommen der Zeichen keine Lösung, da die XML-1.0- und 1.1-Spezifikationen die ungültigen Zeichen auch nicht in ausgeblendeter Form zulassen.

+1

Link ist tot ... es sieht so aus als wäre das die neue URL? http://benjchristensen.com/2008/02/07/how-to-strip-invalid-xml-characters/ – Michael

+0

Aktualisierter Link - danke –

0

Hier ist eine Lösung, die Pflege des rohen Saibling nimmt sowie das entwichene Zeichen im Stream arbeitet mit stax oder Saxophon. Es muss für die anderen ungültigen Zeichen erstreckt, aber Sie bekommen die Idee

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

Lose basiert auf einem comment in der Verbindung von Stephen C Antwort und wikipedia für die XML 1.1 spec hier ist eine Java-Methode, die Ihnen zeigt, wie zu entfernen ungültige Zeichen, die regulären Ausdruck verwenden ersetzen:

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; 
}