eliminar caracteres XML no válidos de una cadena en java
regex invalid-characters (9)
Hola, me gustaría eliminar todos los caracteres XML no válidos de una cadena. Me gustaría usar una expresión regular con el método string.replace.
me gusta
line.replace(regExp,"");
¿Cuál es el regExp correcto para usar?
Carácter XML inválido es todo lo que no es esto:
[#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
Gracias.
¿De la mejor manera de codificar datos de texto para 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("<"); break;
case ''>'': sb.append(">"); break;
case ''/"'': sb.append("""); break;
case ''&'': sb.append("&"); break;
case ''/''': sb.append("'"); break;
default:
if(c>0x7e) {
sb.append("&#"+((int)c)+";");
}else
sb.append(c);
}
}
return sb.toString();
}
¿Debemos considerar personajes sustitutos? de lo contrario, ''(current> = 0x10000) && (current <= 0x10FFFF)'' nunca será verdadero.
También se probó que la forma de expresión regular parece más lenta que el siguiente bucle.
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));
}
}
}
Creo que los siguientes artículos pueden ayudarte.
http://commons.apache.org/lang/api-2.1/org/apache/commons/lang/StringEscapeUtils.html http://www.javapractices.com/topic/TopicAction.do?Id=96
En breve, intente utilizar el proyecto StringEscapeUtils from Jakarta.
/**
* 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();
}
La solución de Jun, simplificada. Al usar StringBuffer#appendCodePoint(int)
, no necesito char current
o String#charAt(int)
. Puedo decirle a un par sustituto verificando si codePoint
es mayor que 0xFFFF
.
(No es necesario hacer el i ++, ya que un sustituto bajo no pasaría el filtro. Pero luego se reutilizaría el código para diferentes puntos de código y fallaría. Prefiero la programación a la piratería).
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);
}
}
Si desea almacenar elementos de texto con los caracteres prohibidos en forma similar a XML, puede utilizar XPL en su lugar. El dev-kit proporciona procesamiento simultáneo de XPL a XML y XML, lo que significa que no hay costos de tiempo para la traducción de XPL a XML. O, si no necesita toda la potencia de XML (espacios de nombres), simplemente puede usar XPL.
Todas estas respuestas hasta ahora solo reemplazan a los personajes. Pero a veces un documento XML tendrá secuencias de entidad XML no válidas que darán como resultado errores. Por ejemplo, si tiene 
en su xml, un analizador java xml lanzará una Illegal character entity: expansion character (code 0x2 at ...
Aquí hay un programa Java simple que puede reemplazar esas secuencias de entidades no válidas.
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;
}
La expresión regular de Java admite caracteres suplementarios , por lo que puede especificar esos altos rangos con dos caracteres codificados en UTF-16.
Aquí está el patrón para eliminar caracteres que son ilegales en 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 mayoría de la gente querrá la versión XML 1.0.
Aquí está el patrón para eliminar caracteres que son ilegales en XML 1.1 :
// XML 1.1
// [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
String xml11pattern = "[^"
+ "/u0001-/uD7FF"
+ "/uE000-/uFFFD"
+ "/ud800/udc00-/udbff/udfff"
+ "]+";
Deberá usar String.replaceAll(...)
y no String.replace(...)
.
String illegal = "Hello, World!/0";
String legal = illegal.replaceAll(pattern, "");
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;
}