web-dev-qa-db-fra.com

supprimer les caractères XML non valides d'une chaîne en java

Bonjour, j'aimerais supprimer tous les caractères XML non valides d'une chaîne. J'aimerais utiliser une expression régulière avec la méthode string.replace.

comme

line.replace(regExp,"");

quel est le bon regExp à utiliser?

caractère XML invalide est tout ce qui n'est pas ceci:

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

merci.

20
yossi

Les expressions rationnelles de Java prennent en charge les caractères supplémentaires , vous pouvez donc spécifier ces plages hautes avec deux caractères codés UTF-16.

Voici le modèle de suppression des caractères interdits dans 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"
                    + "]";

La plupart des gens voudront la version XML 1.0.

Voici le modèle de suppression des caractères interdits dans XML ​​1.1 :

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

Vous devrez utiliser String.replaceAll(...) et non String.replace(...).

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

Devrions-nous envisager des personnages de substitution? sinon '(actuel> = 0x10000) && (actuel <= 0x10FFFF)' ne sera jamais vrai.

Également testé que le mode regex semble plus lent que la boucle suivante.

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

Jusqu'à présent, toutes ces réponses ne font que remplacer les personnages eux-mêmes. Mais parfois, un document XML aura des séquences d'entités XML non valides entraînant des erreurs. Par exemple, si vous avez &#2; dans votre xml, un analyseur syntaxique Java jettera Illegal character entity: expansion character (code 0x2 at ...

Voici un programme Java simple qui peut remplacer ces séquences d'entités non valides.

  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
Nicholas DiPiazza

La solution de Jun, simplifiée. En utilisant StringBuffer#appendCodePoint(int), je n’ai besoin ni de char current ni de String#charAt(int). Je peux identifier une paire de substitution en vérifiant si codePoint est supérieur à 0xFFFF.

(Il n'est pas nécessaire de faire le i ++, car un substitut bas ne passerait pas le filtre. Mais ensuite, on utiliserait le code pour différents points de code et cela échouerait. Je préfère la programmation au piratage.)

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

De Weblog de Mark McLaren

  /**
   * 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

De Le meilleur moyen de coder des données texte pour XML en Java?

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

Si vous souhaitez stocker des éléments de texte avec les caractères interdits sous une forme semblable à XML, vous pouvez utiliser XPL à la place. Le dev-kit assure le traitement simultané de fichiers XPL vers XML et XML, ce qui signifie que la traduction de XPL en XML ne coûte rien. Ou, si vous n'avez pas besoin de toute la puissance de XML (espaces de noms), vous pouvez simplement utiliser XPL.

Page Web: HLL XPL

0
Roger F. Gay