2011-07-19 19 views
8

Estoy tratando de encontrar una manera de "cortar" el contenido de un archivo XML. En la raíz de esto, es necesario comparar algunos nodos de texto que se pasan a los nodos de texto, y espero asegurarme de que la suma de comprobación sea la misma. Los nodos de texto pasados ​​han regresado de un envío de formulario y debo asegurarme de que no se hayan modificado (dentro de lo razonable, excluyendo las colisiones).Uso de XSL para hacer un hash de archivo XML

La arquitectura es horrible, así que no preguntes sobre ella. Estoy atrapado en una implementación determinada de compartir con algún código personalizado muy malo que necesito solucionar.

¿Se puede implementar una función de suma de comprobación/hash que funcione correctamente? Necesitaría verificar aproximadamente 100 nodos de texto.

+0

¿No puede copiar el XML fuera de XSL, digamos con MD5? – Oded

+0

No puedo; el XSL es lo único sobre lo que tengo control. Este XSL básicamente se llama en el envío de formularios para generar un correo electrónico HTML. Como no hay forma de ir y consultar el enlace, el texto y la información de resumen, necesito analizarlo desde el XML devuelto. Sin embargo, podría haber cambiado el lado del cliente, así que tengo que encontrar una manera de comparar el texto devuelto con el hash de lo que inicialmente puse. – electrichead

Respuesta

13

Parece que necesita un position-dependent checksum. ¿Estás pidiendo una implementación XSLT, o solo el algoritmo?

Aquí hay un implementation of Fletcher's checksum en C, que no debería ser muy difícil de portar a XSLT.

Actualización: A continuación se muestra una adaptación XSLT 2.0 de la suma de comprobación de Fletcher. Si es lo suficientemente rápido, depende del tamaño de sus datos y de la cantidad de tiempo que tenga. Me interesaría saber cómo van tus exámenes. Para optimizar, intentaría cambiar xs:integer a xs:int.

Tenga en cuenta que he sustituido la adición simple para el O bit a bit (|) de la implementación a la que he vinculado anteriormente. No estoy realmente calificado para analizar las ramificaciones de este cambio con respecto a uniformity o non-invertibility, pero parece correcto siempre y cuando no tenga un hacker inteligente que intente omitir maliciosamente sus comprobaciones de suma de comprobación.

Tenga en cuenta que, debido al cambio anterior, esta implementación no dará los mismos resultados que las implementaciones verdaderas de la suma de comprobación de Fletcher (@MDBiker). Por lo tanto, no puede comparar la salida de esta función con la de Fletcher16 de Java, por ejemplo. Sin embargo, mostrará siempre devolverá el mismo resultado para la misma entrada (es determinista), por lo que puede comparar la salida de esta función en dos cadenas de texto.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:foo="my.foo.org"> 

    <xsl:variable name="str1">The quick brown fox jumps over the lazy dog.</xsl:variable> 
    <xsl:variable name="str2">The quick frown box jumps over the hazy frog.</xsl:variable> 

    <xsl:template match="/"> 
     Checksum 1: <xsl:value-of select="foo:checksum($str1)"/>  
     Checksum 2: <xsl:value-of select="foo:checksum($str2)"/>  
    </xsl:template> 

    <xsl:function name="foo:checksum" as="xs:int"> 
     <xsl:param name="str" as="xs:string"/> 
     <xsl:variable name="codepoints" select="string-to-codepoints($str)"/> 
     <xsl:value-of select="foo:fletcher16($codepoints, count($codepoints), 1, 0, 0)"/> 
    </xsl:function> 

    <!-- can I change some xs:integers to xs:int and help performance? --> 
    <xsl:function name="foo:fletcher16"> 
     <xsl:param name="str" as="xs:integer*"/> 
     <xsl:param name="len" as="xs:integer" /> 
     <xsl:param name="index" as="xs:integer" /> 
     <xsl:param name="sum1" as="xs:integer" /> 
     <xsl:param name="sum2" as="xs:integer"/> 
     <xsl:choose> 
      <xsl:when test="$index gt $len"> 
       <xsl:sequence select="$sum2 * 256 + $sum1"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:variable name="newSum1" as="xs:integer" 
        select="($sum1 + $str[$index]) mod 255"/> 
       <xsl:sequence select="foo:fletcher16($str, $len, $index + 1, $newSum1, 
         ($sum2 + $newSum1) mod 255)" /> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:function> 
</xsl:stylesheet> 

La salida:

Checksum 1: 65256  
    Checksum 2: 25689 

Nota sobre el uso: Usted dijo que necesitaba para funcionar suma de comprobación en "el contenido de un archivo XML En la raíz de esto es necesario comparar un texto. nodos ". Si pasa un nodo de texto a foo: suma de comprobación(), funcionará bien: se extraerá su valor de cadena.

FYI, ejecuté una prueba de rendimiento, para calcular la suma de comprobación de los nodos de texto en un archivo de entrada XML de 535KB. Aquí estaba la plantilla inicial que utilicé:

<xsl:template match="/"> 
    Checksum of input: <xsl:value-of 
     select="sum(for $t in //text() return foo:checksum($t)) mod 65536"/>  
</xsl:template> 

Terminó en 0.8s, usando Saxon PE.

alternativa:

Si la cantidad de texto no es muy grande, probablemente sería más rápido y más preciso para comparar simplemente las propias cadenas (en lugar de sumas de control) entre sí. Pero tal vez no pueda obtener acceso a ambos nodos de texto al mismo tiempo, debido a las restricciones de su arquitectura ... No lo tengo claro por su descripción.

+0

@electrichead: Quería asegurarme de que viera que había agregado una implementación. – LarsH

+0

Dicho sea de paso, para aquellos que puedan estar interesados: intenté cambiar la opción-cuando-de otro modo a un XPath-only "si ... entonces ... más ...". Pensé que eso podría hacerlo más rápido. Para hacerlo funcionar, tuve que unir '$ newSum1' usando una declaración singleton" for ". El resultado: consistentemente 0.9s en mi prueba de rendimiento, en lugar de 0.8s. – LarsH

+1

Hay un error en la implementación. La función devolverá '0' para cualquier cadena que consista en un solo carácter. Para que se considere el último carácter, debemos cambiar la condición para la cláusula 'xsl: when' de' $ index ge $ len' a '$ index gt $ len'. –

Cuestiones relacionadas