Las soluciones anteriores no me funcionaron si el código hexadecimal estaba presente en el xml. p.ej.
<element></element>
El siguiente código se rompería:
string xmlFormat = "<element>{0}</element>";
string invalid = " ";
string xml = string.Format(xmlFormat, invalid);
xml = Regex.Replace(xml, @"[\x01-\x08\x0B\x0C\x0E\x0F\u0000-\u0008\u000B\u000C\u000E-\u001F]", "");
XDocument.Parse(xml);
Devuelve:
XmlException: '', valor hexadecimal 0x08, es un carácter no válido. Línea 1, posición 14.
La siguiente es la expresión regular mejorado y fijado el problema mencionado anteriormente:
& #x ([0-8BCEFbcef] | 1 [0-9A-Fa-f]); | [\ x01- \ x08 \ x0B \ x0c \ X0E \ x0F \ u0000- \ u0008 \ u000B \ u000C \ u000E- \ u001F]
Aquí está una prueba unidad para los primeros 300 caracteres Unicode y verifica que sólo los caracteres no válidos son eliminados:
[Fact]
public void validate_that_RemoveInvalidData_only_remove_all_invalid_data()
{
string xmlFormat = "<element>{0}</element>";
string[] allAscii = (Enumerable.Range('\x1', 300).Select(x => ((char)x).ToString()).ToArray());
string[] allAsciiInHexCode = (Enumerable.Range('\x1', 300).Select(x => "&#x" + (x).ToString("X") + ";").ToArray());
string[] allAsciiInHexCodeLoweCase = (Enumerable.Range('\x1', 300).Select(x => "&#x" + (x).ToString("x") + ";").ToArray());
bool hasParserError = false;
IXmlSanitizer sanitizer = new XmlSanitizer();
foreach (var test in allAscii.Concat(allAsciiInHexCode).Concat(allAsciiInHexCodeLoweCase))
{
bool shouldBeRemoved = false;
string xml = string.Format(xmlFormat, test);
try
{
XDocument.Parse(xml);
shouldBeRemoved = false;
}
catch (Exception e)
{
if (test != "<" && test != "&") //these char are taken care of automatically by my convertor so don't need to test. You might need to add these.
{
shouldBeRemoved = true;
}
}
int xmlCurrentLength = xml.Length;
int xmlLengthAfterSanitize = Regex.Replace(xml, @"&#x([0-8BCEF]|1[0-9A-F]);|[\u0000-\u0008\u000B\u000C\u000E-\u001F]", "").Length;
if ((shouldBeRemoved && xmlCurrentLength == xmlLengthAfterSanitize) //it wasn't properly Removed
||(!shouldBeRemoved && xmlCurrentLength != xmlLengthAfterSanitize)) //it was removed but shouldn't have been
{
hasParserError = true;
Console.WriteLine(test + xml);
}
}
Assert.Equal(false, hasParserError);
}
Si bien esta es una sugerencia de implementación útil, realmente no responde mi pregunta. Supongamos, por los argumentos, que la implementación tiene soporte de primera clase para los caracteres que no son BMP, por lo que los caracteres sustitutos no son necesarios en absoluto. –