Pergunta

Eu queria saber se existe alguma maneira de escapar de uma final CDATA símbolo (]]>) dentro de uma seção CDATA em um documento XML. Ou, mais geralmente, se há alguma sequência de escape para usar dentro de um CDATA (mas se ele existe, eu acho que provavelmente só fazem sentido para escapar começar ou fichas finais, de qualquer maneira).

Basicamente, você pode ter um início ou fim de token incorporado em um CDATA e dizer o analisador não interpretá-lo, mas a tratá-lo como apenas mais uma sequência de caracteres.

Provavelmente, você deve apenas refatorar seu estrutura XML ou seu código se você encontrar-se tentando fazer isso, mas mesmo que eu tenho trabalhado com xml em uma base diária para os últimos 3 anos ou mais e eu nunca tive este problema, eu queria saber se era possível. Só por curiosidade.

Editar:

Além de usar html codificação ...

Foi útil?

Solução

Claramente, esta questão é puramente académica. Felizmente, ele tem uma resposta muito clara.

Você não pode escapar uma seqüência final CDATA. regra de produção 20 do XML especificação é bastante clara:

[20]    CData      ::=      (Char* - (Char* ']]>' Char*))

EDIT:. Esta regra do produto significa literalmente ". Secção A CData pode conter qualquer coisa que você quiser, mas a seqüência ']]>' Nenhuma exceção"

EDIT2: A mesma seção também lê:

Dentro de uma seção CDATA, somente a seqüência de CDEnd é reconhecida como marcação, para que colchetes de abertura e ampersands pode ocorrer em sua forma literal; eles não precisam (e não pode) ser escapou usando "<" e "&". seções CDATA não pode aninhar.

Em outras palavras, não é possível usar referência de entidade, marcação ou qualquer outra forma de sintaxe interpretado. O texto única analisado dentro de uma seção CDATA é ]]>, e termina a seção.

Por isso, não é possível escapar ]]> dentro de uma seção CDATA.

EDIT3: A mesma seção também lê:

2,7 CDATA secções

[Definição: seções CDATA podem ocorrer em qualquer lugar pode ocorrer dados de caracteres; eles são usados ??para escapar blocos de caracteres de texto que contém o que de outra forma seriam reconhecidos como marcação. seções CDATA começar com "":]

Em seguida, pode haver uma seção CDATA dados de caracteres em qualquer lugar pode ocorrer, incluindo várias seções CDATA adjacentes INPLACE de uma seção CDATA única. Isso permite que ele seja possível dividir a ]]> token e colocar as duas partes dele em seções CDATA adjacentes.

ex:

<![CDATA[Certain tokens like ]]> can be difficult and <invalid>]]> 

deve ser escrita como

<![CDATA[Certain tokens like ]]]]><![CDATA[> can be difficult and <valid>]]> 

Outras dicas

Você tem que quebrar seus dados em pedaços para esconder o ]]>.

Aqui está a coisa toda:

<![CDATA[]]]]><![CDATA[>]]>

O primeiro <![CDATA[]]]]> tem a ]]. A segunda <![CDATA[>]]> tem a >.

Você não escapar da ]]> mas você escapar do > após ]] inserindo ]]><![CDATA[ antes do >, pense nisso como um \ na cadeia de C / Java / PHP / Perl mas apenas necessários antes de uma > e depois de um ]].

BTW,

A resposta de S. Lott é o mesmo que este, assim redigida de forma diferente.

S. A resposta de Lott está certo: você não codificar o tag final, você quebrá-lo em várias seções CDATA

.

Como executar através deste problema no mundo real: usando um editor XML para criar um documento XML que será alimentado em um sistema de gerenciamento de conteúdo, tentar escrever um artigo sobre seções CDATA. Seu truque comum de incorporar exemplos de código em uma seção CDATA lhe faltará aqui. Você pode imaginar como eu aprendi isso.

Mas na maioria das circunstâncias, você não vai encontrar isso, e aqui está o porquê: se você deseja armazenar (digamos) o texto de um documento XML como o conteúdo de um elemento XML, você provavelmente vai usar um método DOM, por exemplo:

XmlElement elm = doc.CreateElement("foo");
elm.InnerText = "<[CDATA[[Is this a problem?]]>";

E o DOM bastante razoável escapa o , o que significa que você não inadvertidamente incorporados uma seção CDATA no documento.

Oh, e isso é interessante:

XmlDocument doc = new XmlDocument();

XmlElement elm = doc.CreateElement("doc");
doc.AppendChild(elm);

string data = "<![[CDATA[This is an embedded CDATA section]]>";
XmlCDataSection cdata = doc.CreateCDataSection(data);
elm.AppendChild(cdata);

Este é provavelmente um ideosyncrasy do .NET DOM, mas isso não lançar uma exceção. A exceção é jogado aqui:

Console.Write(doc.OuterXml);

Eu acho que o que está acontecendo sob o capô é que o XmlDocument está usando um XmlWriter produzir sua saída, e as verificações XmlWriter para boa formação, uma vez que escreve.

simplesmente substituir ]]> com ]]]]><![CDATA[>

Aqui está um outro caso em que ]]> precisa ser escapado. Suponha que precisamos para salvar um documento HTML perfeitamente válida dentro de um bloco CDATA de um documento XML e HTML passa a ter o seu bloco própria CDATA. Por exemplo:

<htmlSource><![CDATA[ 
    ... html ...
    <script type="text/javascript">
        /* <![CDATA[ */
        -- some working javascript --
        /* ]]> */
    </script>
    ... html ...
]]></htmlSource>

os comentadas necessidades sufixo CDATA de ser alterado para:

        /* ]]]]><![CDATA[> *//

desde um analisador XML não vai saber como lidar com blocos de comentários javascript

Em PHP: '<![CDATA['.implode(explode(']]>', $string), ']]]]><![CDATA[>').']]>'

A maneira mais limpa em PHP:

   function safeCData($string)
   {
      return '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', $string) . ']]>';
   }

Não se esqueça de usar um str_replace multibyte-safe, se necessário ($string não latin1):

   function mb_str_replace($search, $replace, $subject, &$count = 0)
   {
      if (!is_array($subject))
      {
         $searches = is_array($search) ? array_values($search) : array ($search);
         $replacements = is_array($replace) ? array_values($replace) : array ($replace);
         $replacements = array_pad($replacements, count($searches), '');
         foreach ($searches as $key => $search)
         {
            $parts = mb_split(preg_quote($search), $subject);
            $count += count($parts) - 1;
            $subject = implode($replacements[$key], $parts);
         }
      }
      else
      {
         foreach ($subject as $key => $value)
         {
            $subject[$key] = mb_str_replace($search, $replace, $value, $count);
         }
      }
      return $subject;
   }

Outra solução é substituir ]]> por ]]]><![CDATA[]>.

Veja a seguinte estrutura:

<![CDATA[
   <![CDATA[
      <div>Hello World</div>
   ]]]]><![CDATA[>
]]>

Para a tag CDATA interna (s) você deve fechar com ]]]]><![CDATA[> vez de ]]>. Simples como isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top