Frage

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

wie

line.replace(regExp,"");

Was ist der richtige Regexp?

Ungültiges XML -Zeichen ist alles, was nicht Folgendes ist:

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

Danke.

War es hilfreich?

Lösung

Javas Regex unterstützt ergänzende Zeichen, Sie können diese hohen Bereiche mit zwei utf-16-codierten Zeichen angeben.

Hier ist das Muster zum Entfernen von Charakteren, die illegal sind XML 1.0:

// 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 Charakteren, die illegal sind XML 1.1:

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

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

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

Andere Tipps

Sollten wir Ersatzfiguren in Betracht ziehen? Andernfalls '(aktuell> = 0x10000) && (aktuell <= 0x10ffff)' wird niemals wahr sein.

Testete auch, 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));
        }
    }
}

Juns Lösung, vereinfacht. Verwendung StringBuffer#appendCodePoint(int), Ich brauche nein char current oder String#charAt(int). Ich kann ein Ersatzpaar sagen, indem ich prüfe, ob codePoint ist größer als 0xFFFF.

(Es ist nicht notwendig, das i ++ zu machen, da ein niedriger Ersatz den Filter nicht übergeben würde. Aber dann würde man den Code für verschiedene Codepunkte wiederverwenden und es würde fehlschlagen. Ich bevorzuge es, das Hacken zu programmieren.)

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

All diese Antworten ersetzen bisher nur die Charaktere selbst. Manchmal hat ein XML -Dokument jedoch ungültige XML -Entitätssequenzen, die zu Fehlern führen. Zum Beispiel, wenn Sie haben &#2; In Ihrem XML wird ein Java XML -Parser werfen Illegal character entity: expansion character (code 0x2 at ....

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

Aus Mark McLaren's 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();
  }   

Aus Bester Weg, um Textdaten für XML in Java zu codieren?

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

Wenn Sie Textelemente mit den verbotenen Zeichen in XML-ähnlicher Form speichern möchten, können Sie stattdessen XPL verwenden. Der Dev -Kit liefert eine gleichzeitige XPL XML- und XML -Verarbeitung - was bedeutet, dass die Übersetzung von XPL auf XML keine Zeitkosten für die Übersetzung bedeutet. Wenn Sie nicht die volle Leistung von XML (Namespaces) benötigen, können Sie einfach XPL verwenden.

Webseite: HLL XPL

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

Ich glaube, dass die folgenden Artikel Ihnen helfen können.

http://commons.apache.org/lang/api-2.1/org/apache/commons/lang/stringescapeutils.htmlhttp://www.javapractices.com/topic/topicaction.do?id=96

Versuchen Sie in Kürze, StringScapetils vom Jakarta -Projekt zu verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top