Escape de caracteres XSLT

Tengo el siguiente nombre de elemento en mi xml para ser transformado

<title>abc \" &gt; &lt; script &gt; alert(1) &lt; /script &gt;</title>

Que transformo usando lo siguiente en mi archivo XSL:

<xsl:attribute name="itemTitle"><xsl:value-of select="title"/></xsl:attribute>

Estoy usando la función Transform de XSLCompiledTransform de C#. mi código es:

XPathDocument xpTemplate = new XPathDocument("articlesLookupTemplate.xsl");
XslCompiledTransform xsl = new XslCompiledTransform();
XsltArgumentList xslArg = new XsltArgumentList();
xsl.Load(xpTemplate);

using (StringReader reader = new StringReader(xmlData))
{
    xsl.Transform(XmlReader.Create(reader), xslArg, output);
} 

donde la salida es un HtmlTextWriter. Después de transformarlo a través de XSLT, quiero que permanezca escapado, es decir, la salida debe permanecer

itemTitle="abc&quot; &gt; &lt; script &gt; alert(1) &lt; /script &gt;"

Sin embargo, lo que obtengo es:

itemTitle="abc&quot;><script>alert(1)</script>"

Estoy usando el método de salida html en mi archivo xsl y no tengo escape de salida de desactivación. Si pruebo el método de salida de texto, obtengo una salida truncada. ¿Cómo puedo asegurarme de que el texto permanezca como está?

--- Actualización --- probé mi xsl y xml en www.xmlper.com

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0">
<xsl:output method="html" />
<xsl:template match="/articles">
<table id="TemplateTable">
     <xsl:for-each select="articletemplate">
        <li class="Dialog-ListItem">
           <xsl:attribute name="itemTitle"><xsl:value-of select="title"/></xsl:attribute>
           <xsl:value-of select="title"/>
        </li>
      </xsl:for-each>  
</table>
</xsl:template>
</xsl:stylesheet>

y el archivo XML es:

<articles >
  <articletemplate>  
  <title>abc " &gt; &lt; script &gt; alert(1) &lt; /script &gt;</title>
  </articletemplate>
</articles>

Para el que está en xmlattribute obtengo

itemTitle="abc &quot; > < script > alert(1) < /script >"

y por el que no me sale

abc " &gt; &lt; script &gt; alert(1) &lt; /script &gt;

Quería que el que está dentro de xmlattribute también estuviera codificado.

preguntado el 24 de agosto de 12 a las 06:08

Realmente no puede comparar la salida de xmlper.com a menos que sepa que están usando el mismo procesador Xml que usted. ¿Tiene una muestra XML simple que podría publicar, por favor? -

La muestra xml es: abc " > < script > alerta(1) < /script > -

3 Respuestas

En primer lugar, déjame comentar tu salida; estas usando lo siguiente:

<table id="TemplateTable">
     <xsl:for-each select="articletemplate">
        <li class="Dialog-ListItem">
           <xsl:attribute name="itemTitle"><xsl:value-of select="title"/></xsl:attribute>
           <xsl:value-of select="title"/>
        </li>
      </xsl:for-each>  
</table>

que estará produciendo un li como hijo de table - esto no es un buen HTML (y ciertamente no validaría cuando lo probé en w3c.org). <li> debería ser realmente un hijo de <ul> or <ol>

Con eso fuera del camino, esta es en realidad una pregunta bastante interesante. Creo que la razón de esto se debe a un desacuerdo con la especificación:

El método de salida html no debe escapar a los caracteres <que aparecen en los valores de los atributos.

(Fuente: http://www.xm.co.nz/ShoXS/xsloutput.htm)

Esto es lo que creo que está sucediendo:

El xsl:value-of en el analizador ve abc \&quot; &amp;gt; &amp;lt; script &amp;gt; alert(1) &amp;lt; /script &amp;gt; que se traduce inmediatamente a abc \&quot; > < script > alert(1) < /script >. Luego, de acuerdo con la regla anterior, esto debe colocarse textualmente en el valor del atributo (que es lo que también he observado).

Es casi seguro que esto se deba a la declaración de salida html. Si cambio la salida para que sea XML, los valores se colocan en el atributo palabra por palabra.

Así que tienes dos opciones:

  1. Transforme directamente a XML (cambiando su salida para que sea xml) e intente escribir eso en el cliente. Puede ser XML, pero si lo envía como HTML (omitiendo la declaración XML y usando el tipo de contenido correcto para HTTP), debería escribirse como se esperaba.

  2. Coloque su texto como CDATA: <![CDATA[abc " &gt; &lt; script &gt; alert(1) &lt; /script &gt;]]> - esto parece obligar al analizador .Net Xml a no tratar el texto como HTML (por lo que no se traduce antes de generarse cuando el método de salida es html) y el resultado es el que deseas

También es interesante notar que disable-output-escaping no tiene ningún efecto aquí. Es casi seguro que esto se deba a la interpretación de la especificación cuando el método de salida es html

Probado usando XmlDocument, XSLTransform, .Net 3.5

Aquí está el XSLT que escribí:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
  <xsl:output method="html" />
  <xsl:template match="/">
    <html>
      <head></head>
      <body>
        <ul>
          <xsl:apply-templates select="/articles/articletemplate" />
        </ul>
      </body>
    </html>
  </xsl:template>


  <xsl:template match="articletemplate">
    <li class="Dialog-ListItem" itemTitle="{title}">
      <xsl:value-of select="title"/>
    </li>
  </xsl:template>  
</xsl:stylesheet>

El XML de muestra que utilicé (nota CDATA vs no CDATA):

<?xml version="1.0" encoding="utf-8" ?>
<articles>
  <articletemplate>
    <title><![CDATA[abc \" &gt; &lt; script &gt; alert(1) &lt; /script &gt;]]></title>
  </articletemplate>
  <articletemplate>
    <title>abc " &gt; &lt; script &gt; alert(1) &lt; /script &gt;</title>
  </articletemplate>
  <articletemplate>
    <title>test</title>
  </articletemplate>
</articles>

Y la salida:

<html>
  <head>
    <META http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <ul>
      <li class="Dialog-ListItem" itemTitle="abc \&quot; &amp;gt; &amp;lt; script &amp;gt; alert(1) &amp;lt; /script &amp;gt;">abc \" &amp;gt; &amp;lt; script &amp;gt; alert(1) &amp;lt; /script &amp;gt;</li>
      <li class="Dialog-ListItem" itemTitle="abc &quot; > < script > alert(1) < /script >">abc " &gt; &lt; script &gt; alert(1) &lt; /script &gt;</li>
      <li class="Dialog-ListItem" itemTitle="test">test</li>
    </ul>
  </body>
</html>

Respondido 24 ago 12, 15:08

hola, gracias por responder. En mi html original tengo el <li> como hijo de <ul>, lo recorté junto con algunas etiquetas más aquí para acortar el xsl. 1. Tiene razón sobre el uso de xml ya que la salida es la misma. Tendré que comprobar si el uso de Xml no rompe nada más. 2. CDATA codifica los caracteres especiales pero convierte el original &gt; a &amp;gt; , es decir, ¡recodifica los caracteres escapados! Gracias. - gibreelchamcha

@fuehrer: sí, eso es una consecuencia de la salida HTML (pero debería aparecer como se esperaba en el navegador). Agregaré un poco más a mi respuesta. - guión

Me acabo de dar cuenta de que no puedo cambiar los datos del archivo XML para agregarle CDATA, así que tendré que intentar cambiar el método de salida a XML o hay alguna forma tonta de agregar CDATA a través de XSL. - gibreelchamcha

@feuhrer Lamentablemente no. Método de salida = XML es perfectamente válido; realmente debería apuntar a una salida HTML que sea XHTML de todos modos (qué método de salida = xml te moverá de alguna manera hacia). - guión

No hay forma de conservar la forma original del valor del atributo, porque el procesador XSLT no sabe cuál es la forma original; el analizador XML expande las referencias a la entidad en el valor del atributo y las entrega al procesador XSLT en su forma "expandida" (es decir, &lt; se convierte en < y así). El resultado final de xsl:value-of depende del método de serialización HTML, que es libre de mostrar '"' dentro de un valor de atributo como &quot; or &#34; o en varias otras formas equivalentes. No he investigado detenidamente si la salida de '<' y '>' en forma sin escape en HTML es legítima o no; mi primer instinto es que no es legítimo, y esto es un error en su procesador.

Respondido 24 ago 12, 09:08

< no es legítimo en un valor de atributo, > es, aunque es mejor evitarlo. - jon hanna

No pude reproducir tu problema.

En www.xmlper.com, obtuve resultados:

<t itemTitle="abc \&quot; &gt; &lt; script &gt; alert(1) &lt; /script &gt;" />

Y con Saxon, obtuve salida:

<t itemTitle="abc \&#34; &gt; &lt; script &gt; alert(1) &lt; /script &gt;"/>

No veo cómo es posible obtener lo que dices que tienes. O su procesador XSLT no es conforme, o ha confundido el valor del atributo de salida como lo informa algún analizador DOM, con la representación léxica del atributo de salida.

Respondido 24 ago 12, 08:08

Hola, gracias por responder. He agregado detalles para la transformación en la pregunta. Estoy comprobando la salida escribiendo HtmlTextWriter en un StreamWriter y comprobando el archivo escrito. - gibreelchamcha

Entonces ese es tu problema. No está mirando la salida XSLT. La salida XSLT será correcta. Tu manipulación corriente abajo tiene la culpa. - Sean B Durkin

Gracias nuevamente, pero dado que soy un XSLT n00b, ¿podría guiarme sobre cómo ver la salida XSLT? El código que tengo usa un HtmlTextWriter como el flujo de salida para la transformación que envío a un StreamWriter para abordar su inquietud acerca de no ver la salida XSLT. - gibreelchamcha

Sé un poco sobre XSLT, pero no sé absolutamente nada sobre C#, HtmlTextWriter y StreamWriter. Ni siquiera sé qué es StreamWriter. Probablemente necesite involucrar a los expertos de C#. La respuesta del Dr. Kay sugiere que su objetivo es obtener...<guión>... etc. como el descifrado valor de su salida (y por lo tanto el valor léxico como ..&lt;script&&gt;... . Mientras que, por el contrario, he entendido que desea... ... as the descifrado salida (y por lo tanto <script> como el léxico valor. ¿Quizás necesitas aclarar? - Sean B Durkin

Estás siendo de gran ayuda :) Utilicé el sitio que mencionaste www.xmlper.com y publiqué mis resultados en la pregunta. - gibreelchamcha

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.