it-swarm.com.de

entfernen ungültiger XML-Zeichen aus einer Zeichenfolge in Java

Hallo, ich möchte alle ungültigen XML-Zeichen aus einer Zeichenfolge entfernen. Ich möchte einen regulären Ausdruck mit der string.replace-Methode verwenden.

mögen

line.replace(regExp,"");

was ist das richtige RegExp zu verwenden?

ein ungültiges XML-Zeichen ist alles, was nicht so ist:

[#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

vielen Dank.

20
yossi

Javas Regex unterstützt zusätzliche Zeichen , sodass Sie diese hohen Bereiche mit zwei UTF-16-kodierten Zeichen angeben können.

Hier ist das Muster zum Entfernen von Zeichen, die in XML ​​1.0 unzulässig sind:

// XML 1.0
// #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
String xml10pattern = "[^"
                    + "\u0009\r\n"
                    + "\u0020-\uD7FF"
                    + "\uE000-\uFFFD"
                    + "\ud800\udc00-\udbff\udfff"
                    + "]";

Die meisten Leute wollen die XML 1.0-Version.

Hier ist das Muster zum Entfernen von Zeichen, die in XML ​​1.1 illegal sind:

// XML 1.1
// [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
String xml11pattern = "[^"
                    + "\u0001-\uD7FF"
                    + "\uE000-\uFFFD"
                    + "\ud800\udc00-\udbff\udfff"
                    + "]+";

Sie müssen String.replaceAll(...) und nicht String.replace(...) verwenden.

String illegal = "Hello, World!\0";
String legal = illegal.replaceAll(pattern, "");
72
McDowell

Sollen wir Ersatzfiguren in Betracht ziehen? Andernfalls ist '(current> = 0x10000) && (current <= 0x10FFFF)' niemals wahr.

Auch getestet, dass der Regex-Weg langsamer erscheint als die folgende Schleife.

if (null == text || text.isEmpty()) {
    return text;
}
final int len = text.length();
char current = 0;
int codePoint = 0;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
    current = text.charAt(i);
    boolean surrogate = false;
    if (Character.isHighSurrogate(current)
            && i + 1 < len && Character.isLowSurrogate(text.charAt(i + 1))) {
        surrogate = true;
        codePoint = text.codePointAt(i++);
    } else {
        codePoint = current;
    }
    if ((codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD)
            || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
            || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
            || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF))) {
        sb.append(current);
        if (surrogate) {
            sb.append(text.charAt(i));
        }
    }
}
6
Jun

Alle diese Antworten ersetzen bisher nur die Zeichen selbst. Aber manchmal hat ein XML-Dokument ungültige XML-Entitätssequenzen, die zu Fehlern führen. Wenn Sie beispielsweise &#2; in Ihrer XML-Datei haben, gibt ein Java-XML-Parser Illegal character entity: expansion character (code 0x2 at ... aus. 

Hier ist ein einfaches Java-Programm, das diese ungültigen Entitätssequenzen ersetzen kann.

  public final Pattern XML_ENTITY_PATTERN = Pattern.compile("\\&\\#(?:x([0-9a-fA-F]+)|([0-9]+))\\;");

  /**
   * Remove problematic xml entities from the xml string so that you can parse it with Java DOM / SAX libraries.
   */
  String getCleanedXml(String xmlString) {
    Matcher m = XML_ENTITY_PATTERN.matcher(xmlString);
    Set<String> replaceSet = new HashSet<>();
    while (m.find()) {
      String group = m.group(1);
      int val;
      if (group != null) {
        val = Integer.parseInt(group, 16);
        if (isInvalidXmlChar(val)) {
          replaceSet.add("&#x" + group + ";");
        }
      } else if ((group = m.group(2)) != null) {
        val = Integer.parseInt(group);
        if (isInvalidXmlChar(val)) {
          replaceSet.add("&#" + group + ";");
        }
      }
    }
    String cleanedXmlString = xmlString;
    for (String replacer : replaceSet) {
      cleanedXmlString = cleanedXmlString.replaceAll(replacer, "");
    }
    return cleanedXmlString;
  }

  private boolean isInvalidXmlChar(int val) {
    if (val == 0x9 || val == 0xA || val == 0xD ||
            val >= 0x20 && val <= 0xD7FF ||
            val >= 0x10000 && val <= 0x10FFFF) {
      return false;
    }
    return true;
  }
2

Jun's Lösung, vereinfacht. Mit StringBuffer#appendCodePoint(int) brauche ich keinen char current oder String#charAt(int). Ich kann ein Ersatzpaar erkennen, indem ich prüfe, ob codePoint größer ist als 0xFFFF.

(Es ist nicht notwendig, i ++ auszuführen, da ein niedriger Surrogat den Filter nicht passieren würde. Aber dann würde man den Code für verschiedene Codepunkte wiederverwenden, und er würde fehlschlagen. Ich bevorzuge die Programmierung dem Hacken.)

StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
    int codePoint = text.codePointAt(i);
    if (codePoint > 0xFFFF) {
        i++;
    }
    if ((codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD)
            || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
            || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
            || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF))) {
        sb.appendCodePoint(codePoint);
    }
}
2
Vlasec

Aus Mark McLarens Weblog

  /**
   * This method ensures that the output String has only
   * valid XML unicode characters as specified by the
   * XML 1.0 standard. For reference, please see
   * <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
   * standard</a>. This method will return an empty
   * String if the input is null or empty.
   *
   * @param in The String whose non-valid characters we want to remove.
   * @return The in String, stripped of non-valid characters.
   */
  public static String stripNonValidXMLCharacters(String in) {
      StringBuffer out = new StringBuffer(); // Used to hold the output.
      char current; // Used to reference the current character.

      if (in == null || ("".equals(in))) return ""; // vacancy test.
      for (int i = 0; i < in.length(); i++) {
          current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
          if ((current == 0x9) ||
              (current == 0xA) ||
              (current == 0xD) ||
              ((current >= 0x20) && (current <= 0xD7FF)) ||
              ((current >= 0xE000) && (current <= 0xFFFD)) ||
              ((current >= 0x10000) && (current <= 0x10FFFF)))
              out.append(current);
      }
      return out.toString();
  }   
1
Renaud

Von Beste Methode, um Textdaten für XML in Java zu kodieren?

String xmlEscapeText(String t) {
   StringBuilder sb = new StringBuilder();
   for(int i = 0; i < t.length(); i++){
      char c = t.charAt(i);
      switch(c){
      case '<': sb.append("&lt;"); break;
      case '>': sb.append("&gt;"); break;
      case '\"': sb.append("&quot;"); break;
      case '&': sb.append("&amp;"); break;
      case '\'': sb.append("&apos;"); break;
      default:
         if(c>0x7e) {
            sb.append("&#"+((int)c)+";");
         }else
            sb.append(c);
      }
   }
   return sb.toString();
}
0
Roger F. Gay
String xmlData = xmlData.codePoints().filter(c -> isValidXMLChar(c)).collect(StringBuilder::new,
                StringBuilder::appendCodePoint, StringBuilder::append).toString();

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

Wenn Sie Textelemente mit den verbotenen Zeichen in einer XML-ähnlichen Form speichern möchten, können Sie stattdessen XPL verwenden. Das dev-kit ermöglicht die gleichzeitige XPL-Verarbeitung in XML und XML. Das bedeutet, dass für die Übersetzung von XPL in XML keine Zeitkosten anfallen. Wenn Sie nicht die volle Leistungsfähigkeit von XML (Namespaces) benötigen, können Sie einfach XPL verwenden.

Webseite: HLL XPL

0
Roger F. Gay