¿Qué son los caracteres no válidos en XML?

229

Estoy trabajando con algún XML que contiene cadenas como:

<node>This is a string</node>

Algunas de las cadenas que estoy pasando a los nodos tendrán personajes como &, #, $, etc .:

<node>This is a string & so is this</node>

Esto no es válido debido a &.

No puedo envolver estas cadenas en CDATA, ya que deben ser como son. Intenté buscar una lista de caracteres que no se pueden poner en nodos XML sin estar en un CDATA.

¿Alguien puede señalarme en la dirección de uno o proporcionarme una lista de caracteres ilegales?

CarrilesHijo
fuente
44
¿Alguna razón válida para no usar CDATA?
Peter Perháč
1
Sí, estoy pasando la cadena a un CMS llamado Fatwire y el nodo con los datos no puede estar en un CDATA, no estoy seguro de por qué funciona Fatwire :(
RailsSon
@ Peter: ¿Cómo puedo usar CDATA en mi caso? stackoverflow.com/questions/6906705/…
Radek

Respuestas:

147

Los únicos caracteres ilegales son &, <y >(así como "o 'en atributos).

Están escapada utilizando entidades XML , en este caso de que desee &amp;para &.

Realmente, sin embargo, debe usar una herramienta o biblioteca que escriba XML para usted y resuma este tipo de cosas para que no tenga que preocuparse por eso.

Welbog
fuente
82
Algunos caracteres de control tampoco están permitidos. Vea mi respuesta a continuación.
dolmen
43
En realidad eso no es del todo cierto. Varios caracteres ascii inferiores también son inválidos. Si intenta escribir 0x03 en un documento Xml, generalmente obtiene un error y si logra escapar correctamente en un documento XML, la mayoría de los lectores se quejarán del carácter no válido. Caso de borde pero sucede.
Rick Strahl el
16
Esta respuesta es absolutamente incorrecta. Aquí está mi excepción XML con el carácter ilegal 0x12 'System.Xml.XmlException:' ', el valor hexadecimal 0x12, es un carácter no válido'
George
8
También está mal en la otra dirección; además de perder todos los caracteres ilegales, los caracteres que afirma son ilegales son perfectamente legales, aunque con un significado especial en el contexto.
Jon Hanna
66
En XML 1.0 hay muchos caracteres ilegales. De hecho, incluso el uso de una entidad de caracteres para la mayoría de los caracteres de control provocará un error al analizar.
Thayne
218

OK, separemos la pregunta de los personajes que:

  1. no son válidos en absoluto en ningún documento XML.
  2. Necesito ser escapado.

La respuesta proporcionada por @dolmen en " Qué son los caracteres no válidos en XML " sigue siendo válida, pero debe actualizarse con la especificación XML 1.1.

1. Caracteres inválidos

Los caracteres descritos aquí son todos los caracteres que pueden insertarse en un documento XML.

1.1. En XML 1.0

La lista global de caracteres permitidos es:

[2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */

Básicamente, los caracteres de control y los caracteres fuera de los rangos Unicode no están permitidos. Esto significa también que &#x3;está prohibido llamar, por ejemplo, a la entidad del personaje .

1.2. En XML 1.1

La lista global de caracteres permitidos es:

[2] Char ::= [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */

[2a] RestrictedChar ::= [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]

Esta revisión de la recomendación XML ha extendido los caracteres permitidos para que los caracteres de control estén permitidos y tenga en cuenta una nueva revisión del estándar Unicode, pero estos todavía no están permitidos: NUL (x00) , xFFFE , xFFFF ...

Sin embargo, se desaconseja el uso de caracteres de control y caracteres Unicode indefinidos.

También se puede notar que todos los analizadores no siempre tienen esto en cuenta y los documentos XML con caracteres de control pueden ser rechazados.

2. Caracteres que deben escaparse (para obtener un documento bien formado):

Se <debe escapar con una &lt;entidad, ya que se supone que es el comienzo de una etiqueta.

Se &debe escapar con una &amp;entidad, ya que se supone que es el comienzo de una referencia de entidad

El >debe escaparse con &gt;entidad. No es obligatorio, depende del contexto, pero se recomienda encarecidamente escapar de él.

Se 'debe escapar con una &apos;entidad, obligatoria en los atributos definidos entre comillas simples, pero se recomienda encarecidamente escapar siempre de ella.

Se "debe escapar con una &quot;entidad, obligatoria en los atributos definidos entre comillas dobles, pero se recomienda encarecidamente escapar siempre de ella.

Potame
fuente
171

La lista de caracteres válidos está en la especificación XML :

Char       ::=      #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]  /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
dolmen
fuente
77
Debe tener en cuenta que, aunque son caracteres legales, & < > " 'se deben escapar en ciertos contextos.
D.Shawley
77
"Legal" en este contexto significa que sus valores decodificados finales son legales, no que sean legales en la secuencia. Como se indicó anteriormente, algunos valores legales tienen que escaparse in-stream.
SilverbackNet
Tengo un problema en el que 0x1c es un personaje ilegal ... Buscando una posibilidad en Java para evitar estos ...
basZero
Una buena descripción de qué caracteres son válidos y cuáles no se pueden encontrar aquí validchar.com/d/xml10/xml10_namestart
Dr. Max Völkel
8
@xamde Esa lista es buena, pero solo muestra los caracteres que pueden usarse para iniciar un elemento XML. El problema en cuestión es qué caracteres son válidos en un archivo XML en general. Hay ciertos personajes que no están permitidos en ninguna parte.
Jon Senchyna
59

Este es un código C # para eliminar los caracteres inválidos XML de una cadena y devolver una nueva cadena válida.

public static string CleanInvalidXmlChars(string text) 
{ 
    // From xml spec valid chars: 
    // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]     
    // any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. 
    string re = @"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]"; 
    return Regex.Replace(text, re, ""); 
}
mathifonseca
fuente
66
Para Java, el patrón regex sería el mismo. Y luego puede usar el método llamado replaceAll en la clase String que espera un patrón regex como parámetro. Mira esto: docs.oracle.com/javase/6/docs/api/java/lang/…
mathifonseca
2
Tengo caracteres no válidos en mi cadena: SUSITARIMO D & # x5; L DARBO SUTARTIES Este código no elimina & # x5; Entonces el documento xml no se inicia.
Dainius Kreivys
Creo que no puedes simplemente poner este patrón en un constructor de expresiones regulares .NET. No creo que reconozca \u10000y \u10FFFFcomo caracteres individuales, ya que requieren dos charinstancias utf-16 cada uno, y de acuerdo con los documentos , puede que no haya más de 4 dígitos. [\u10000-\u10FFFF]es más probable que se analiza como [ \u1000, 0-\u10FF, F, F] que es de aspecto extraño pero legal.
GSerg
7

Además de la respuesta de potame, si desea escapar utilizando un bloque CDATA.

Si coloca su texto en un bloque CDATA, entonces no necesita usar escape . En ese caso, puede usar todos los caracteres en el siguiente rango :

representación gráfica de posibles personajes

Nota: Además de eso, no puedes usar la ]]>secuencia de caracteres. Porque coincidiría con el final del bloque CDATA.

Si todavía hay caracteres no válidos (por ejemplo, caracteres de control), entonces probablemente sea mejor usar algún tipo de codificación (por ejemplo, base64).

bvdb
fuente
3
Ya sea en un bloque CDATA o no, algunos caracteres están prohibidos en XML.
dolmen
44
exactamente, ¿no es eso lo que escribí? cita: "todos los caracteres en el siguiente rango ". Por lo que quiero decir, solo los personajes en este rango específico. No se permiten otros personajes. - completamente de acuerdo ; Pero no entiendo el voto negativo. - Sin resentimientos.
bvdb
6

Otra forma fácil de escapar de caracteres XML / XHTML potencialmente no deseados en C # es:

WebUtility.HtmlEncode(stringWithStrangeChars)
tiands
fuente
Personajes inválidos
dolmen
1
Escribió Xml no Html.
Emanuele
6

Otra forma de eliminar caracteres XML incorrectos en C # es usar XmlConvert.IsXmlChar(Disponible desde .NET Framework 4.0)

public static string RemoveInvalidXmlChars(string content)
{
   return new string(content.Where(ch => System.Xml.XmlConvert.IsXmlChar(ch)).ToArray());
}

o puede verificar que todos los caracteres sean válidos para XML:

public static bool CheckValidXmlChars(string content)
{
   return content.All(ch => System.Xml.XmlConvert.IsXmlChar(ch));
}

.Net Fiddle

Por ejemplo, el símbolo de tabulación vertical ( \v) no es válido para XML, es UTF-8 válido, pero no es válido XML 1.0, e incluso muchas bibliotecas (incluido libxml2) lo omiten y generan silenciosamente XML no válido.

Alex Vazhev
fuente
2

En resumen, los caracteres válidos en el texto son:

  • pestaña, avance de línea y retorno de carro.
  • Todos los caracteres sin control son válidos excepto & y <.
  • >no es válido si sigue ]].

Las secciones 2.2 y 2.4 de la especificación XML proporcionan la respuesta en detalle:

Caracteres

Los caracteres legales son tabulación, retorno de carro, avance de línea y los caracteres legales de Unicode e ISO / IEC 10646

Datos del personaje

El carácter de y comercial (&) y el paréntesis angular izquierdo (<) no deben aparecer en su forma literal, excepto cuando se usan como delimitadores de marcado, o dentro de un comentario, una instrucción de procesamiento o una sección CDATA. Si se necesitan en otro lugar, se deben escapar utilizando referencias de caracteres numéricos o las cadenas "&" y "<" respectivamente. El paréntesis angular derecho (>) puede representarse usando la cadena ">", y debe, por compatibilidad, escapar usando ">" o una referencia de caracteres cuando aparece en la cadena "]]>" en el contenido, cuando eso la cadena no marca el final de una sección CDATA.

rghome
fuente
1
ampersand (&) is escaped to &amp;

double quotes (") are escaped to &quot;

single quotes (') are escaped to &apos; 

less than (<) is escaped to &lt; 

greater than (>) is escaped to &gt;

En C #, use System.Security.SecurityElement.Escapeo System.Net.WebUtility.HtmlEncodepara escapar de estos caracteres ilegales.

string xml = "<node>it's my \"node\" & i like it 0x12 x09 x0A  0x09 0x0A <node>";
string encodedXml1 = System.Security.SecurityElement.Escape(xml);
string encodedXml2= System.Net.WebUtility.HtmlEncode(xml);


encodedXml1
"&lt;node&gt;it&apos;s my &quot;node&quot; &amp; i like it 0x12 x09 x0A  0x09 0x0A &lt;node&gt;"

encodedXml2
"&lt;node&gt;it&#39;s my &quot;node&quot; &amp; i like it 0x12 x09 x0A  0x09 0x0A &lt;node&gt;"
vive el amor
fuente
1

Para la gente de Java, Apache tiene una clase de utilidad ( StringEscapeUtils) que tiene un método auxiliar escapeXmlque se puede usar para escapar caracteres en una cadena usando entidades XML.

Un puntero nulo
fuente
1

En el procesador XML Woodstox, los caracteres no válidos se clasifican por este código:

if (c == 0) {
    throw new IOException("Invalid null character in text to output");
}
if (c < ' ' || (c >= 0x7F && c <= 0x9F)) {
    String msg = "Invalid white space character (0x" + Integer.toHexString(c) + ") in text to output";
    if (mXml11) {
        msg += " (can only be output using character entity)";
    }
    throw new IOException(msg);
}
if (c > 0x10FFFF) {
    throw new IOException("Illegal unicode character point (0x" + Integer.toHexString(c) + ") to output; max is 0x10FFFF as per RFC");
}
/*
 * Surrogate pair in non-quotable (not text or attribute value) content, and non-unicode encoding (ISO-8859-x,
 * Ascii)?
 */
if (c >= SURR1_FIRST && c <= SURR2_LAST) {
    throw new IOException("Illegal surrogate pair -- can only be output via character entities, which are not allowed in this content");
}
throw new IOException("Invalid XML character (0x"+Integer.toHexString(c)+") in text to output");

Fuente de aquí

Jerome Saint-Yves
fuente
-1

Alguien ha intentado esto System.Security.SecurityElement.Escape(yourstring)? Esto reemplazará los caracteres XML no válidos en una cadena con su equivalente válido.

klaydze
fuente
-5

Para XSL (en días realmente flojos) uso:

capture="&amp;(?!amp;)" capturereplace="&amp;amp;"

para traducir todos los signos & que no se siguen på amp; a los propios.

Tenemos casos en los que la entrada está en CDATA pero el sistema que usa el XML no lo tiene en cuenta. Es una solución descuidada, cuidado ...

Samson Wiklund
fuente
8
Si es descuidado, ¿es realmente necesario publicarlo aquí?
dolmen