2010-02-20 11 views
8

У меня есть структура, которая генерирует XML на основе HTTP-запроса и текущего состояния сеанса. Я могу протестировать в HTML, но выпуск продукции будет VXML - возможно, один или два «аромата» по разным причинам.Я хочу улучшить производительность xslt

Вот медленная часть моей 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); 

Это в настоящее время занимает ~ 200мс. Я бы хотел, чтобы это было намного быстрее. Возможно < 10 мс?

  1. Предложения по кешированию? - видя, что xsl-файлы остаются неизменными во время развертывания, объекты Transformer могут кэшироваться неограниченно долго. Я подумываю о том, чтобы кэшировать его на уровне сеанса, поэтому каждый сеанс (одновременно 1000) имеет свои собственные. Какие-либо предложения? Должен ли я использовать какие-либо рамки для кеширования по какой-либо причине?
  2. Есть ли более быстрый способ преобразования xml в поток ответов?
  3. Должен ли я отказаться от этого и пойти другим путем? Если вы заметили sb.toString, я использую StringBuilder для получения XML-представления объектов (объекты используют строковый конструктор для создания строки XML). Для создания XML-документа с использованием StringBuilders требуется около 1 миллисекунды, поэтому на данный момент меня это не беспокоит.

Edit:

Вот XSL документ. XML-документ обычно очень мал. Всего несколько элементов. Образец XML ниже 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> 

Вот некоторые 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

Можете ли вы показать нам свой XSLT с помощью образца входного документа? Возможно, ваш XSLT содержит неэффективные запросы, которые могут быть оптимизированы (неэффективные запросы могут быть созданы практически на любом языке запросов, так что обвинение XLST в замедлении обычно невелико). –

+0

Я добавлю XSLT, но, возможно, это может быть еще один вопрос :) – ericp

+1

Можете ли вы также показать документ * ввода *? Это важнее, чем результат. –

ответ

12

Трудно диагностировать проблемы с производительностью, не видя XSLT или не зная, насколько велики/сложны XML и XSLT.

Вы можете оплатить стоимость анализа файлов (ов), XSLT или XML и/или у вас может быть очень неэффективная таблица стилей XSLT.

Например:

  1. Много // XPATH заявлений, которые, если не нужны может повредить производительности для очень больших файлов XML.
  2. Logic похож на внутри шаблонов, которые могут быть перенесены в шаблон @match критериев, что дает возможность оптимизировать XSLT-двигатели.

Есть прошивки XSLT, которые вы можете использовать, чтобы увидеть, где узкие места находятся в вашем XSLT. Например, oXygen имеет очень хороший debugger/profiler: alt text alt text

Если вы будете запускать XSLT много раз, то вы должны cache the transformer object.Таким образом, вы платите только за загрузку и инстанцируете ее один раз и повторно используете много раз.

Например, переместить экземпляр вашего объекта XSLT Template в ваш severlet init()

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

, а затем, когда вы выполняете преобразование, используйте кэшированные TransformerFactory OBJ:

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

+1 для использования шаблонов. Если вы используете Xalan в качестве XSLT-трансформатора, попробуйте использовать версию XSLTC, которая собирает таблицы стилей и работает намного быстрее. См. Http://xml.apache.org/xalan-j/xsltc_usage.html#api Если вы используете Xalan, я бы проверял DOM, TinyTree имеет некоторые основные преимущества перед нормальным Java DOM в некоторых случаях (результаты могут но использование памяти намного лучше для TinyTree). –

-1

я встретил какой-то инструмент, который преобразует файл XSLT в код синтаксического анализа Java, но не могу найти ссылку прямо сейчас. Извините за неполный ответ, но мне интересно его найти.

+0

Этот инструмент Саксон и Майкл Кей просто попросили список помощи саксона, если кому-то это понадобилось, чтобы он знал, продолжать ли его поддерживать. Отправьте свой ответ там. –

5

Даже с кеширование, причина неприемлемой производительности часто в самом коде XSLT - который вы вообще не показывали.

По моему опыту были случаи, когда я смог изменить неэффективную реализацию XSLT таким образом, чтобы ее ускоряли тысячи раз.

Довольно часто автор реализует алгоритм O (N^2) или хуже, когда существуют O (N) или даже O (log (N)) алгоритмы.

Сообщите нам, чтобы решить проблему и предоставить XSLT-код, который разрешает его. Тогда было бы возможно, чтобы кто-то дал вам более эффективное решение.

Смежные вопросы