2010-02-20 11 views
8

Tengo un marco que genera el XML, en función de la solicitud HTTP y el estado de la sesión actual. Puedo probar en HTML, pero la salida de producción será VXML, quizás uno o dos "sabores" por diferentes razones.Quiero mejorar el rendimiento de xslt

Aquí está la parte lenta de mi HttpServlet:

jsp InputStream ms = new java.io.ByteArrayInputStream(sb.toString().getBytes()); 
Source xmlSource = new javax.xml.transform.stream.StreamSource(ms); 
String filePath = getServletContext().getRealPath(("/GetNextEvent-"). 
     concat(req.getSession().getAttribute("client").toString().toUpperCase()).concat(".xsl")); 
Source xsltSource = new javax.xml.transform.stream.StreamSource(filePath); 
Result result = new javax.xml.transform.stream.StreamResult(resp.getWriter()); 
TransformerFactory tf = TransformerFactory.newInstance(); 
Transformer t = tf.newTransformer(xsltSource); 
t.transform(xmlSource, result); 

lleva este momento ~ 200 ms. Me gustaría que sea mucho más rápido. ¿Quizás < 10ms?

  1. Sugerencias para almacenar en caché? - Al ver que los archivos xsl permanecen iguales durante todo el despliegue, los objetos de Transformer se pueden almacenar en caché de forma indefinida. Estoy pensando en almacenarlo en caché en el nivel de la sesión, por lo que cada sesión (1000 simultánea) tiene la suya. ¿Alguna sugerencia? ¿Debería usar algún framework para el almacenamiento en caché, por algún motivo?
  2. ¿Hay una forma más rápida de transformar el xml en el flujo de respuesta?
  3. ¿Debo eliminar esto e ir a otra ruta? Si notó el sb.toString, estoy usando un StringBuilder para obtener la representación XML de los objetos (los objetos usan un generador de cadenas para crear cadenas XML). Se tarda aproximadamente 1 milisegundo en crear el documento XML utilizando StringBuilders, por lo que no me preocupa en este momento.

Editar:

Aquí está el documento XSL. El documento XML suele ser muy pequeño. Solo un par de elementos. XML de ejemplo está por debajo de XSL:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:regexp="http://exslt.org/regular-expressions" 
    xmlns:str="http://exslt.org/strings" xmlns:twc="http://twc.com/2009/01/ivr/framework" 
    exclude-result-prefixes="twc regexp str" extension-element-prefixes="str"> 
    <xsl:output method="xml" encoding="ISO-8859-1" /> 
    <xsl:template match="/"> 
     <vxml xmlns="http://www.w3.org/2001/vxml" version="2.1" xml:lang="en-US" 
      application="root.xml"> 
      <xsl:attribute name="xml:lang"><xsl:value-of 
       select="//twc:response/@language" /></xsl:attribute> 
      <form id="ivrFramework"> 
       <var name="logDebug"> 
        <xsl:attribute name="expr"><xsl:value-of 
         select="//twc:response/@debug" /></xsl:attribute> 
       </var> 
       <var name="event" expr="'OK'" /> 
       <var name="lastResult" expr="''" /> 
       <var name="lastResultMode" expr="''" /> 
       <var name="lastResultValue" expr="''" /> 
       <var name="srConfidence" expr="'1000'" /> 

       <xsl:apply-templates select="//twc:command" /> 
       <xsl:if test="count(//twc:command)=0"> 
        <block> 
         <log cond="logDebug" expr="'No more commands. Exiting.'" /> 
         <exit /> 
        </block> 
       </xsl:if> 
      </form> 
     </vxml> 
    </xsl:template> 

    <xsl:template 
     match="twc:command[@type='prompt' and contains(text(), 'TransferDialog')]"> 
     <transfer name="quicktransfer" type="consultation"> 
      <xsl:attribute name="destexpr"><xsl:choose> 
       <xsl:when test="//twc:parameter[twc:name='destination']">'<xsl:value-of 
       select="//twc:parameter[twc:name='destination']/twc:value" />'</xsl:when> 
       <xsl:otherwise>'tel:1136300'</xsl:otherwise> 
      </xsl:choose> 
      </xsl:attribute> 
      <xsl:if test="//twc:parameter[twc:name='initial']"> 
       <prompt> 
        <xsl:call-template name="process_prompt"> 
         <xsl:with-param name="prompt_type" select="'initial'" /> 
        </xsl:call-template> 
       </prompt> 
      </xsl:if> 
     </transfer> 
    </xsl:template> 

    <xsl:template 
     match="twc:command[@type='prompt' and contains(text(), 'BasicDialog')]"> 
     <xsl:choose> 
      <xsl:when test="//twc:parameter[twc:name='grammar']/twc:value"> 
       <field> 
        <xsl:attribute name="name"><xsl:value-of 
         select="//twc:parameter[twc:name='variable']/twc:value" /></xsl:attribute> 
        <noinput count="3"> 
         <assign name="event" expr="'noinput'" /> 
         <submit next="GetNextEvent2.jsp" 
          namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
        </noinput> 
        <nomatch count="3"> 
         <assign name="event" expr="'invalid'" /> 
         <submit next="GetNextEvent2.jsp" 
          namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
        </nomatch> 

        <xsl:for-each select="//twc:parameter[twc:name='grammar']/twc:value"> 
         <grammar> 
          <xsl:attribute name="src"><xsl:if test="//twc:response/@base!=''"><xsl:value-of select="//twc:response/@base" /></xsl:if><xsl:value-of 
           select="." /></xsl:attribute> 
         </grammar> 
        </xsl:for-each> 
        <xsl:if test="//twc:parameter[twc:name='help']"> 
         <help> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'help'" /> 
          </xsl:call-template> 
         </help> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='noinput1']"> 
         <noinput count="1"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'noinput1'" /> 
          </xsl:call-template> 
         </noinput> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='noinput2']"> 
         <noinput count="2"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'noinput2'" /> 
          </xsl:call-template> 
         </noinput> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='invalid1']"> 
         <nomatch count="1"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'invalid1'" /> 
          </xsl:call-template> 
         </nomatch> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='invalid2']"> 
         <nomatch count="2"> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'invalid2'" /> 
          </xsl:call-template> 
         </nomatch> 
        </xsl:if> 
        <xsl:if test="//twc:parameter[twc:name='initial']"> 
         <prompt> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'initial'" /> 
          </xsl:call-template> 
         </prompt> 
        </xsl:if> 
        <filled> 
         <log cond="logDebug" expr="'Filled.'" /> 
         <assign name="event" expr="'OK'" /> 
         <assign name="lastResult" expr="application.lastresult$.utterance" /> 
         <assign name="lastResultMode" expr="application.lastresult$.inputmode" /> 
         <assign name="lastResultValue" expr="application.lastresult$.interpretation" /> 
         <assign name="srConfidence" expr="application.lastresult$.confidence " /> 
         <submit next="GetNextEvent2.jsp" 
          namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
        </filled> 

       </field> 
      </xsl:when> 
      <xsl:when test="//twc:parameter[twc:name='initial']/twc:value"> 
       <block> 
        <xsl:if test="//twc:parameter[twc:name='initial']"> 
         <prompt> 
          <xsl:call-template name="process_prompt"> 
           <xsl:with-param name="prompt_type" select="'initial'" /> 
          </xsl:call-template> 
         </prompt> 
        </xsl:if> 
        <submit next="GetNextEvent2.jsp" 
         namelist="event lastResult lastResultMode lastResultValue srConfidence" /> 
       </block> 
      </xsl:when> 
      <xsl:otherwise> 
       <block> 
        <log cond="logDebug" expr="'Didn't find values for grammar or initial. Exiting.'" /> 
        <exit /> 
       </block> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template name="process_prompt"> 
     <xsl:param name="prompt_type" /> 
     <xsl:for-each select="//twc:parameter[twc:name=$prompt_type]/twc:value"> 
      <xsl:if test="contains(., '::')"> 
       <audio> 
        <xsl:for-each select="str:split(., '::')"> 
         <xsl:if test="position()=1"> 
          <xsl:attribute name="src"><xsl:if test="//twc:response/@base!=''"><xsl:value-of select="//twc:response/@base" /></xsl:if><xsl:value-of 
           select="." /></xsl:attribute> 
         </xsl:if> 
         <xsl:if test="position()=2"> 
          <xsl:value-of select="." /> 
         </xsl:if> 
        </xsl:for-each> 
       </audio> 
      </xsl:if> 
      <xsl:if test="contains(., 'Date:')"> 
       <say-as interpret-as="date" format="ymd"> 
        <xsl:for-each select="str:split(., ':')"> 
         <xsl:if test="position()=2"> 
          <xsl:value-of select="." /> 
         </xsl:if> 
        </xsl:for-each> 
       </say-as> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

He aquí algunos XML:

<?xml version="1.0"?> 
<response xmlns="http://twc.com/2009/01/ivr/framework" language="en-us" debug="true" 
    base="/IVRFrameworkResources/Outage/"> 
    <command type="prompt"> BasicDialog <parameter> 
      <name>initial</name> 
      <value>en-us/prompts/OutageCleared.wav::Hello. I'm letting you know the 
       incident that caused your outage has been fixed. </value> 
     </parameter> 
    </command> 
</response> 
+0

¿Puede mostrarnos su XSLT con un documento de entrada de muestra? Es posible que su XSLT contenga consultas ineficaces que pueden optimizarse (las consultas ineficientes se pueden crear en casi cualquier lenguaje de consulta por cierto, por lo que culpar a XLST por ser lento generalmente no es justo). –

+0

Adjuntaré XSLT, pero quizás esa sea otra pregunta :) – ericp

+1

¿Puede mostrar el documento * input * también? Eso importa más que la salida. –

Respuesta

12

Es difícil diagnosticar problemas de rendimiento sin ver el XSLT o saber qué tan grandes/complejos son el XML y el XSLT.

Podría estar pagando el costo de analizar el archivo (s), ya sea XSLT o XML y/o podría tener una hoja de estilo XSLT muy ineficiente.

Por ejemplo:

  1. Mucha // declaraciones XPath, que si no es necesario puede perjudicar el rendimiento para grandes archivos XML.
  2. Lógica enterrada dentro de plantillas que se podría mover hacia arriba en los criterios de plantilla @match, lo que brinda la oportunidad a los motores XSLT de optimizar.

Hay perfiladores XSLT que puede utilizar para ver dónde están los cuellos de botella en su XSLT. Por ejemplo, oXygen tiene un muy buen debugger/profiler: alt text alt text

Si va a correr los XSLT muchas veces, entonces usted debe cache the transformer object.De esta forma, solo paga el costo de cargar e instanciarlo una vez y reutilizarlo muchas veces.

Por ejemplo, mueva la creación de instancias de su objeto XSLT Template en su severlet init()

TransformerFactory transFact = TransformerFactory.newInstance(); 
Templates cachedXSLT = transFact.newTemplates(xsltSource); 

y luego donde se realiza la transformación, utilizar el caché TransformerFactory obj:

Transformer t= cachedXSLT.newTransformer(); 
t.transform(xmlSource, result); 
+3

+1 para usar plantillas. Si usa Xalan como un transformador XSLT intente utilizar la versión XSLTC que compila hojas de estilo y es mucho más rápido. Ver http://xml.apache.org/xalan-j/xsltc_usage.html#api Si utilizo Xalan verificaría el DOM utilizado, TinyTree tiene algunas ventajas importantes sobre el DOM Java normal en algunos casos (los resultados pueden varían, pero el uso de la memoria es mucho mejor para TinyTree). –

-1

he conocido alguna herramienta que convierte el archivo XSLT en el código de análisis de Java, pero no puede encontrar ninguna referencia en este momento. Perdón por una respuesta incompleta, pero también estoy interesado en encontrarla.

+0

Esta herramienta es Saxon y Michael Kay acaba de pedirle a la lista de ayuda de saxon si alguien la necesita, para que sepa si continuará manteniéndola. Publica tu respuesta allí. –

5

Incluso con el almacenamiento en caché, la razón del rendimiento inaceptable suele estar en el código XSLT mismo, que no ha mostrado en absoluto.

En mi experiencia, ha habido casos en los que he podido cambiar una implementación ineficiente de XSLT de tal manera que se ha acelerado miles de veces.

Muy a menudo el autor implementa un algoritmo O (N^2) o peor, cuando existen algoritmos O (N) o incluso O (log (N)).

Indíquenos el problema que se está solucionando y proporcione el código XSLT que lo resuelve. Entonces es posible que alguien le brinde una solución de mejor rendimiento.

Cuestiones relacionadas