O que são caracteres inválidos no XML

229

Estou trabalhando com algum XML que contém seqüências de caracteres como:

<node>This is a string</node>

Algumas das cordas que estou passando para os gânglios terá personagens como &, #, $, etc .:

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

Isso não é válido devido a &.

Não consigo agrupar essas seqüências no CDATA, pois elas precisam ser como são. Tentei procurar uma lista de caracteres que não podem ser colocados em nós XML sem estar em um CDATA.

Alguém pode me apontar na direção de um ou fornecer uma lista de caracteres ilegais?

RailsSon
fonte
4
Algum motivo válido para não usar o CDATA?
Peter Perháč
1
Sim, eu estou passando a cadeia a um CMS chamado FatWire eo nó com os dados não podem estar em um CDATA, eu não sei por que ele é o caminho FatWire funciona :(
RailsSon
@ Peter: Como posso usar o CDATA no meu caso? stackoverflow.com/questions/6906705/…
Radek

Respostas:

147

Os únicos caracteres ilegais são &, <e >(assim como "ou 'nos atributos).

Eles escaparam usando XML entidades , neste caso você deseja &amp;para &.

Na verdade, você deve usar uma ferramenta ou biblioteca que grave XML para você e abstraia esse tipo de coisa, para que você não precise se preocupar com isso.

Welbog
fonte
82
Alguns caracteres de controle também não são permitidos. Veja minha resposta abaixo.
dolmen
43
Na verdade, isso não é bem verdade. Um número de caracteres ASCII inferiores também é inválido. Se você tentar escrever 0x03 em um documento Xml, normalmente recebe um erro e, se conseguir escapar adequadamente em um documento XML, a maioria dos visualizadores reclamará do caractere inválido. Caso Edge, mas acontece.
Rick Strahl
16
Esta resposta está absolutamente errada. Aqui está minha exceção XML com o caractere ilegal 0x12 'System.Xml.XmlException:' ', valor hexadecimal 0x12, é um caractere inválido'
George
8
Também está errado na outra direção; além de perder todos os caracteres ilegais, os caracteres que afirma serem ilegais são perfeitamente legais, embora com significado especial no contexto.
Jon Hanna
6
No XML 1.0, existem muitos caracteres ilegais. De fato, mesmo o uso de uma entidade de caractere para a maioria dos caracteres de controle causará um erro ao analisar.
Thayne
218

OK, vamos separar a questão dos caracteres que:

  1. não são válidos em nenhum documento XML.
  2. precisa ser escapado.

A resposta fornecida por @dolmen em " O que são caracteres inválidos no XML " ainda é válida, mas precisa ser atualizada com a especificação XML 1.1.

1. Caracteres inválidos

Os caracteres descritos aqui são todos os caracteres que podem ser inseridos em um documento XML.

1.1 No XML 1.0

A lista global de caracteres permitidos é:

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

Basicamente, os caracteres de controle e caracteres fora dos intervalos Unicode não são permitidos. Isso significa também que &#x3;é proibido chamar, por exemplo, a entidade de caractere .

1.2 No XML 1.1

A lista global de caracteres permitidos é:

[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 revisão da recomendação XML estendeu os caracteres permitidos para que caracteres de controle sejam permitidos e leva em consideração uma nova revisão do padrão Unicode, mas esses ainda não são permitidos: NUL (x00) , xFFFE , xFFFF ...

No entanto, o uso de caracteres de controle e caracteres Unicode indefinidos é desencorajado.

Também é possível notar que nem todos os analisadores levam isso em consideração e os documentos XML com caracteres de controle podem ser rejeitados.

2. Caracteres que precisam ser escapados (para obter um documento bem formado):

O <deve ser escapado com uma &lt;entidade, pois é assumido o início de uma tag.

A &devem ser precedidos por uma &amp;entidade, uma vez que se presume ser o início de uma referência de entidade

O >deve ser escapado com a &gt;entidade. Não é obrigatório - depende do contexto - mas é altamente recomendável evitá-lo.

Ele 'deve ser escapado com uma &apos;entidade - obrigatório nos atributos definidos entre aspas simples, mas é altamente recomendável sempre escapá-lo.

Ele "deve ser escapado com uma &quot;entidade - obrigatório nos atributos definidos entre aspas duplas, mas é altamente recomendável sempre escapá-lo.

potame
fonte
171

A lista de caracteres válidos está na especificação XML :

Char       ::=      #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]  /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
dolmen
fonte
7
Você deve observar que, embora sejam caracteres legais, & < > " 'precisam ser escapados em determinados contextos.
D.Shawley
7
"Legal" neste contexto significa que seus valores finais decodificados são legais, não que eles sejam legais no fluxo. Como acima, alguns valores legais precisam ser escapados in-stream.
precisa
Eu tenho um problema onde 0x1C é um caractere ilegal ... Procura uma possibilidade em java como evitar estes ....
basZero
Uma boa visão geral de quais caracteres são válidos e quais não são podem ser encontrados aqui validchar.com/d/xml10/xml10_namestart
Dr. Max Völkel
8
@ xamde Essa lista é boa, mas mostra apenas os caracteres que podem ser usados ​​para iniciar um elemento XML. O problema em questão é quais caracteres são válidos em um arquivo XML em geral. Existem certos caracteres que não são permitidos em nenhum lugar.
22814 Jon Senchyna
59

Este é um código C # para remover os caracteres inválidos de XML de uma string e retornar uma nova string 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
fonte
6
Para Java, o padrão regex seria o mesmo. E então você pode usar o método chamado replaceAll na classe String que espera um padrão regex como parâmetro. Verifique isso: docs.oracle.com/javase/6/docs/api/java/lang/…
mathifonseca
2
Eu tenho caracteres inválidos na minha string: SUSITARIMO D & # x5; L DARBO SUTARTIES Este código não remove & # x5; Portanto, o documento xml falha ao iniciar.
Dainius Kreivys
Eu acredito que você não pode simplesmente colocar esse padrão em um construtor de regex do .NET. Eu não acho que ele reconheça \u10000e tenha \u10FFFFcaracteres tão únicos quanto eles exigem duas charinstâncias utf-16 cada e, de acordo com os documentos , pode não haver mais do que 4 dígitos. [\u10000-\u10FFFF]é mais provável analisado como [ \u1000, 0-\u10FF, F, F] o que é estranho à procura, mas legal.
GSerg 23/05
17

Os caracteres pré-declarados são:

& < > " '

Consulte " Quais são os caracteres especiais em XML? " Para obter mais informações.

cgp
fonte
Errado. Estes não são todos inválidos. Somente & e <são sempre inválidos no texto.
Rgome #
7

Além da resposta da potame, se você quiser escapar usando um bloco CDATA.

Se você colocar seu texto em um bloco CDATA, não precisará usar escape . Nesse caso, você pode usar todos os caracteres no seguinte intervalo :

representação gráfica de possíveis caracteres

Nota: Além disso, você não tem permissão para usar a ]]>sequência de caracteres. Porque corresponderia ao final do bloco CDATA.

Se ainda houver caracteres inválidos (por exemplo, caracteres de controle), provavelmente é melhor usar algum tipo de codificação (por exemplo, base64).

bvdb
fonte
3
Seja em um bloco CDATA ou não, alguns caracteres são proibidos em XML.
anta
4
exatamente, não foi isso que eu escrevi? citação: "todos os caracteres no seguinte intervalo ". Com o que quero dizer, apenas os caracteres nesse intervalo específico. Outros caracteres não são permitidos. - Concordo plenamente ; mas eu não entendo o voto negativo. - sem ressentimentos.
bvdb
6

Outra maneira fácil de escapar de caracteres XML / XHTML potencialmente indesejados em C # é:

WebUtility.HtmlEncode(stringWithStrangeChars)
tiands
fonte
Caracteres inválidos
dolmen
1
Ele escreveu Xml, não Html.
Emanuele
6

Outra maneira de remover caracteres XML incorretos em C # está usando XmlConvert.IsXmlChar(Disponível desde o .NET Framework 4.0)

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

ou você pode verificar se todos os caracteres são válidos para XML:

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

.Net Fiddle

Por exemplo, o símbolo da guia vertical ( \v) não é válido para XML, é válido UTF-8, mas não é válido para XML 1.0 e até mesmo muitas bibliotecas (incluindo a libxml2) o perdem e emitem XML inválido silenciosamente.

Alex Vazhev
fonte
2

Em resumo, os caracteres válidos no texto são:

  • guia, alimentação de linha e retorno de carro.
  • todos os caracteres que não são de controle são válidos, exceto & e <.
  • >não é válido se a seguir ]].

As seções 2.2 e 2.4 da especificação XML fornecem a resposta em detalhes:

Personagens

Caracteres legais são guia, retorno de carro, avanço de linha e caracteres legais de Unicode e ISO / IEC 10646

Dados do personagem

O caractere e comercial (&) e o colchete angular esquerdo (<) não devem aparecer em sua forma literal, exceto quando usados ​​como delimitadores de marcação, ou dentro de um comentário, uma instrução de processamento ou uma seção CDATA. Se forem necessários em outro lugar, eles devem ser escapados usando referências de caracteres numéricos ou as cadeias "&" e "<" respectivamente. O colchete angular direito (>) pode ser representado usando a string ">" e, para compatibilidade, deve ser escapado usando ">" ou uma referência de caractere quando aparecer na string "]]>" no conteúdo, quando string não está marcando o final de uma seção CDATA.

rghome
fonte
2

" XmlWriter e caracteres ASCII inferiores " funcionou para mim

string code = Regex.Replace(item.Code, @"[\u0000-\u0008,\u000B,\u000C,\u000E-\u001F]", "");
Kalpesh Popat
fonte
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;

Em C #, use System.Security.SecurityElement.Escapeou System.Net.WebUtility.HtmlEncodepara escapar desses caracteres ilegais.

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;"
amor ao vivo
fonte
1

Para o pessoal de Java, o Apache possui uma classe de utilitário ( StringEscapeUtils) que possui um método auxiliar escapeXmlque pode ser usado para escapar caracteres em uma string usando entidades XML.

Um ponteiro nulo
fonte
1

No processador XML Woodstox, caracteres inválidos são classificados 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");

Fonte daqui

Jerome Saint-Yves
fonte
-1

Alguém tentou isso System.Security.SecurityElement.Escape(yourstring)? Isso substituirá caracteres XML inválidos em uma sequência pelo seu equivalente válido.

klaydze
fonte
-5

Para XSL (em dias realmente preguiçosos) eu uso:

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

traduzir todos os sinais & que não são seguidos på amp; para os adequados.

Temos casos em que a entrada está no CDATA, mas o sistema que usa o XML não leva em consideração. É uma correção desleixada, cuidado ...

Samson Wiklund
fonte
8
Se estiver desleixado, é realmente necessário publicá-lo aqui?
Dolmen