Pregunta

Tengo que poner en marcha un editor de configuración rápido y sucio. El flujo va más o menos así:

La configuración

(POCO en el servidor) se serializa en XML.
El XML está bien formado en este punto. La configuración se envía al servidor web en XElements.
En el servidor web, el XML (Sí, TODO) se descarga en un área de texto para su edición.
El usuario edita el XML directamente en la página web y hace clic en Enviar.
En la respuesta, recupero el texto alterado de la configuración XML. En este punto, TODOS los escapes han sido revertidos por el proceso de mostrarlos en una página web.
Intento cargar la cadena en un objeto XML (XmlElement, XElement, lo que sea). KABOOM.

El problema es que la serialización escapa a las cadenas de atributos, pero esto se pierde en la traducción en el camino.

Por ejemplo, digamos que tengo un objeto que tiene una expresión regular. Aquí está la configuración del servidor web:

<Configuration>
  <Validator Expression="[^&lt;]" />
</Configuration>

Entonces, puse esto en un área de texto, donde se ve así para el usuario:

<Configuration>
  <Validator Expression="[^<]" />
</Configuration>

Por lo tanto, el usuario realiza una ligera modificación y envía los cambios nuevamente. En el servidor web, la cadena de respuesta se ve así:

<Configuration>
  <Validator Expression="[^<]" />
  <Validator Expression="[^&]" />
</Configuration>

Entonces, el usuario agregó otra cosa de validación, y ahora AMBOS tienen atributos con caracteres ilegales. Si intento cargar esto en cualquier objeto XML, arroja una excepción porque & Lt; y & amp; no son válidos dentro de una cadena de texto. NO PUEDO NO PUEDO NO PUEDO NO PUEDO usar ningún tipo de función de codificación, ya que codifica todo lo sangriento:

var result = Server.HttpEncode (editedConfig);

resulta en

&lt;Configuration&gt;
  &lt;Validator Expression="[^&lt;]" /&gt;
  &lt;Validator Expression="[^&amp;]" /&gt;
&lt;/Configuration&gt;

Esto NO es XML válido. Si trato de cargar esto en un elemento XML de cualquier tipo, seré golpeado por un yunque que cae. No me gusta caer yunques.

Entonces, la pregunta sigue siendo ... ¿La ÚNICA forma en que puedo preparar esta cadena XML para analizar en un objeto XML es mediante el uso de regex reemplaza? ¿Hay alguna forma de & "; Desactivar las restricciones &"; cuando cargo? ¿Cómo se soluciona esto ???


Una última respuesta y luego wiki-izing esto, ya que no creo que haya una respuesta válida.

El XML que coloco en el área de texto ES válido, XML escapado. El proceso de 1) ponerlo en el área de texto 2) enviarlo al cliente 3) mostrarlo al cliente 4) enviar el formulario en el que está 5) enviarlo de vuelta al servidor y 6) recuperar el valor del formulario ELIMINA CUALQUIERA Y TODAS LAS ESCAPADAS.

Permítanme decir esto de nuevo: no voy a escapar de nada. ¡Solo mostrarlo en el navegador hace esto!

Cosas para reflexionar: ¿Hay alguna manera de evitar que esto suceda en primer lugar? ¿Hay alguna manera de tomar XML casi válido y & Quot; clean & Quot; ¿de manera segura?


Esta pregunta ahora tiene una recompensa. Para recopilar la recompensa, demuestra cómo editar XML VÁLIDO en una ventana del navegador SIN una herramienta de terceros / de código abierto que no requiera que use regex para escapar de los valores de atributo manualmente, que no requiera que los usuarios escapen de sus atributos, y eso no falla cuando se realiza un viaje de ida y vuelta (& amp; amp; amp; amp; amp; etc;)

¿Fue útil?

Solución

Erm & # 8230; & nbsp; ¿Cómo serializas? Por lo general, el serializador XML nunca debe producir XML no válido.

/ EDITAR en respuesta a su actualización: no muestre XML inválido a su usuario para editarlo. En su lugar, muestre el XML escapado correctamente en el cuadro de texto. Reparar XML roto no es divertido y en realidad no veo ninguna razón para no mostrar / editar el XML en un formulario válido y escapado.

Nuevamente podría preguntar: ¿cómo muestra el XML en el cuadro de texto? Parece que has escapado intencionalmente del XML en algún momento.

/ EDITAR en respuesta a su último comentario: Bueno, sí, obviamente, ya que puede contener HTML. Debe escapar de su XML correctamente antes de escribirlo en una página HTML. Con eso, me refiero al XML entero . Entonces esto:

<foo mean-attribute="&lt;">

se convierte en esto:

&lt;foo mean-attribute="&amp;&lt;"&gt;

Otros consejos

Por supuesto, cuando coloca referencias de entidad dentro de un área de texto, salen sin escape. Las áreas de texto no son mágicas, tienes que & Amplificar; escapar; todo lo que pones en ellos como cualquier otro elemento. Los navegadores pueden mostrar un '& Lt;' sin formato en un área de texto, pero solo porque están tratando de limpiar tus errores.

Entonces, si está poniendo XML editable en un área de texto, debe escapar del valor del atributo una vez para que sea XML válido, y luego debe escapar del XML completo nuevamente para hacerlo HTML válido. La fuente final que desea que aparezca en la página sería:

<textarea name="somexml">
    &lt;Configuration&gt;
        &lt;Validator Expression="[^&amp;lt;]" /&gt;
        &lt;Validator Expression="[^&amp;amp;]" /&gt;
    &lt;/Configuration&gt;
</textarea>

La pregunta se basa en un malentendido del modelo de contenido del elemento textarea: un validador habría resuelto el problema de inmediato.

ETA re comentario: Bueno, ¿qué problema persiste? Ese es el problema en el lado de la serialización. Todo lo que queda es analizarlo nuevamente, y para eso debes asumir que el usuario puede crear XML bien formado.

Intentando analizar XML mal formado, para permitir errores como tener '<' o '& amp;' sin escapes en un valor de atributo es una pérdida, totalmente en contra de cómo se supone que funciona XML. Si no puede confiar en sus usuarios para que escriban XML bien formados, bríndeles una interfaz que no sea XML más fácil, como una simple lista de cadenas de expresiones regulares separadas por una nueva línea.

Como usted dice, el serializador normal debería escapar de todo por usted.

El problema, entonces, es el bloque de texto: debe manejar todo lo que haya pasado a través del bloque de texto usted mismo.

Puede probar HttpUtility.HtmlEncode (), pero creo que el método más simple es encapsular todo lo que pasa a través del bloque de texto en una sección CDATA.

Normalmente, por supuesto, me gustaría que todo se escapara correctamente en lugar de depender de CDATA & "; muleta &"; pero también me gustaría utilizar las herramientas integradas para hacer el escape. Para algo que se edita es & "; Hibernado &"; estado por un usuario, creo que CDATA podría ser el camino a seguir.

También vea esta pregunta anterior:
La mejor manera de codificar datos de texto para XML


Actualizar
Basado en un comentario a otra respuesta, me di cuenta de que le estás mostrando a los usuarios el marcado, no solo el contenido. Los analizadores XML son, bueno, exigentes. Creo que lo mejor que puede hacer en este caso es verificar si está bien formado antes de aceptar el xml editado.

Quizás intente corregir automáticamente ciertos tipos de errores (como los símbolos incorrectos de mi pregunta vinculada), pero luego obtenga el número de línea y el número de columna del primer error de validación del analizador .Net xml y utilícelo para mostrar a los usuarios dónde El error es hasta que te den algo aceptable. Puntos de bonificación si también valida con un esquema.

Podría echar un vistazo a algo como TinyMCE , que le permite editar html en un texto enriquecido caja. Si no puede configurarlo para que haga exactamente lo que desea, puede usarlo como inspiración.

Nota: firefox (en mi prueba) no se escapa en las áreas de texto como usted describe. Específicamente, este código:

<textarea cols="80" rows="10" id="1"></textarea>

<script>
elem = document.getElementById("1");

elem.value = '\
<Configuration>\n\
  <Validator Expression="[^&lt;]" />\n\
</Configuration>\
'
alert(elem.value);
</script>

Se alerta y se muestra al usuario sin cambios , como:

<Configuration>
  <Validator Expression="[^&lt;]" />
</Configuration>

Entonces, tal vez una solución (¿no viable?) es que sus usuarios usen Firefox.


Parece que se han revelado dos partes de su pregunta:

1 XML que muestra no se escapa.

Por ejemplo, " &lt; " no tiene escape como " < " ;. Pero desde & Quot; & Lt; & Quot; también se escapa como " < " ;, la información se pierde y no puede recuperarla.

Una solución es escapar de todos los " & " caracteres, de modo que " &amp;lt; " se convierte en " &amp; " ;. Esto no se escapará por el área de texto como & Quot; \ & Quot ;. Cuando lo lea de nuevo, será como era en primer lugar. (Supongo que el área de texto en realidad cambia la cadena, pero firefox no se comporta como usted informa, por lo que no puedo verificar esto)

Otra solución (mencionada ya creo) es construir / comprar / tomar prestada un área de texto personalizada (no está mal si es simple, pero hay todas las teclas de edición, ctrl-C, ctrl-shift-left y así sucesivamente).

2 Desea que los usuarios no tengan que molestarse en escapar.

Estás en el infierno de escape:

Un reemplazo de expresiones regulares funcionará principalmente ... pero ¿cómo puede detectar de manera confiable la cotización final ("), cuando el usuario podría (legítimamente, dentro de los términos que ha dado) ingresar:

<Configuration>
  <Validator Expression="[^"<]" />
</Configuration>

Mirándolo desde el punto de vista de la sintaxis de expresiones regulares, tampoco puede decir si el & final; es parte de la expresión regular, o el final de la misma. La sintaxis de expresiones regulares generalmente resuelve este problema con un terminador explícito, por ejemplo:

/[^"<]/

Si los usuarios usaron esta sintaxis (con el terminador), y usted escribió un analizador sintáctico para ello, entonces podría determinar cuándo ha finalizado la expresión regular y, por lo tanto, el siguiente " El carácter no es parte de la expresión regular, sino parte del XML y, por lo tanto, qué partes deben escaparse. ¡No digo que debas esto! Estoy diciendo que es teóricamente posible. Está bastante lejos de ser rápido y sucio.

Por cierto: el mismo problema surge para el texto dentro de un elemento. Lo siguiente es legítimo, dentro de los términos que ha indicado, pero tiene los mismos problemas de análisis:

<Configuration>
  <Expression></Expression></Expression>
</Configuration>

La regla básica en una sintaxis que permite " cualquier texto " es que se debe escapar el delimitador debe (por ejemplo, " o <), para que se pueda reconocer el final. La mayoría de la sintaxis también escapa a un montón de otras cosas, por conveniencia / inconveniencia. ( EDITAR necesitará tener un escape para el carácter de escape en sí: para XML, es " \\ " ;, que cuando literal se escapa como " &lt " Para regex, es el estilo C / unix " <=> " ;, que cuando literal se escapa como " <=> < !> quot;).

Sintaxis de nidos, y estás en el infierno de escape.

Una solución simple para usted es decirles a sus usuarios: se trata de un editor de configuración rápido y sucio , por lo que no obtendrá " no es necesario escapar " mamby-pamby:

  • Enumera los personajes y escapa después al área de texto, por ejemplo: " < " como " <=> " ;.
  • Para XML que no validar, mostrarles la lista nuevamente.

Mirando hacia atrás, veo bobince me dio la misma respuesta básica antes que yo.

Insertar CDATA alrededor de todo el texto le daría otro mecanismo de escape que (1) evitaría que los usuarios escapen manualmente, y (2) permitiría que el texto que fue automáticamente escapado por el área de texto se lea de nuevo correctamente.

 <Configuration>
   <Validator Expression="<![CDATA[  [^<]   ]]>" />
 </Configuration>

:-)

Este carácter especial - " < " - debería haber sido reemplazado por otros caracteres para que su XML sea válido. Consulte este enlace para ver los caracteres especiales XML:

http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references

Intente también codificar su contenido TextBlock antes de enviarlo al deserializador:

HttpServerUtility utility = new HttpServerUtility();
string encodedText = utility.HtmlEncode(text);

¿Es esta realmente mi única opción? ¿No es un problema lo suficientemente común como para que tenga una solución en algún lugar del marco?

private string EscapeAttributes(string configuration)
{
    var lt = @"(?<=\w+\s*=\s*""[^""]*)<(?=[^""]*"")";
    configuration = Regex.Replace(configuration, lt, "&lt;");

    return configuration;
}

(editar: reemplazo de ampersand eliminado porque causa problemas de ida y vuelta)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top