Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Xalan, Saxon и 8 ферзей

Anna | 3.06.2014 | нет комментариев
Сегодня я хочу рассказать об XSLT. Данный, крайне оригинальный, язык может оказаться крайне пригоден в тех случаях, когда требуется обработать XML-данные, сколь нибудь не банальным образом. Я расскажу о 2-х особенно знаменитых (в среде Java-разработчиков) реализациях XSLT-процессора, детально остановлюсь на вопросах их применения из Java-кода и попытаюсь сравнить их эффективность. В качестве теста для сопоставления продуктивности, я буду применять обширно вестимую задачу о расстановке 8-ми ферзей на шахматной доске.

От того что решение сходственных задач, с применением XSLT вряд ли дозволено отнести к категории типичной деятельности, топик размещен в соответствующий раздел. В то-же время, я верю, что эта статья будет пригодна, в качестве учебного материала.

Xalan vs Saxon

Невзирая на довольно огромное число существующих реализаций XSLT, в случае если мы говорим о разработке на языке Java, выбор (на мой взор) сводиться к двум упомянутым в заголовке. Подлинно, применение реализации от Microsoft, затруднено тем, что она поставляется в виде нейтивной dll, а реализация от Oracle предуготовлена для применения непринужденно в базе данных. Другие реализации значительно менее вестимы (меня подлинно волнует данный вопрос и я буду рад добавочно разглядеть всякую из Java-совместимых реализаций XSLT, предложенную участниками Програ).

Saxon, на мой взор, является особенно развитым, на сегодняшний день, XSLT-процессором. Матрицапредоставляемых им вероятностей подлинно впечатляет. Правда особенно увлекательные из этих вероятностей поддерживаются только торговыми дистрибутивами, поставляемый по условиям Mozilla Public License version 1.0 Saxon HE также предоставляет полновесную поддержку XPath и XSLT как версии 1.0, так и версии 2.0. Для того, Дабы осознать, насколько помощь XSLT 2.0 может облегчить жизнь, довольно бегло ознакомиться с оглавлением знаменитого учебника XSLT Cookbook за авторством Sal Mangano.

Основным превосходством Xalan, в различии от Saxon, является применение менее ограничивающей Apache License Version 1.1. Эта реализация обеспечивает полновесную поддержку XSLT версии 1.0. Еще одним козырем, как Xalan так и Saxon, является заявленная ими полная помощь индустриального эталона TrAX. О том, что это такое и для чего оно необходимо, я расскажу в дальнейшем разделе.

Именем TrAX-а и JAXP-а его

TrAX — это API для выполнения XML-реформирований, разработанное рядом заинтересованных организаций с целью унификации взаимодействия с XSLT-процессорами. В части относящейся к Java API он был опубликован Sun как JAXP 6 февраля 2001 года. Для ознакомления с вероятностями применения JAXP я рекомендую прочитать следующие статьи.

Коротко говоря, JAXP разрешает трудиться с XML-документами в Java, применяя как DOM, так и SAX (в том числе, реализуя XSLT-реформирования), не привязывая код к применяемой реализации и версии обработчика. Для правильной работы довольно обеспечить наличие используемого jar-а в classpath и установить соответствующее System Property (последнее не непременно если нет разницы какой из обработчиков rFactory)tf; TransformerHandler h = stf.newTransformerHandler(); DocumentBuilderFactory df = DocumentBuilderFactory.newInstance(); Document doc = df.newDocumentBuilder().newDocument(); Result out = new DOMResult(doc); h.setResult(out); generateData(h, size); XPathFactory xpathFactory = XPathFactory.newInstance(); XPath xpath = xpathFactory.newXPath(); XPathExpression xpathExpression = xpath.compile(“/size”); System.out.println(xpathExpression.evaluate(doc)); } else { throw new Exception(“Can”t support SAXSource or DOMResult”); } }

Как мы видим, тут нет ничего трудного. Хочу лишь предостеречь от допустимой передачи в параметр uri вызовов startElement и endElement null-значений. Для Xalan это работает типично, но Saxon выбрасывает NullPointerException.

Для полноты картины, осталось добавить, что реформирования дозволено объединять в цепочки, образуя конвейер. На выходе, итог дозволено сберегать, скажем, в дисковый файл:

Конвейер

	private void test_solution(String size) throws Exception {
		TransformerFactory tf = TransformerFactory.newInstance();
	    if (tf.getFeature(SAXSource.FEATURE) && tf.getFeature(SAXResult.FEATURE)) {
	        SAXTransformerFactory stf = (SAXTransformerFactory)tf;	  
	        TransformerHandler solve  = stf.newTransformerHandler();
	        TransformerHandler filter = stf.newTransformerHandler();
	        TransformerHandler view   = stf.newTransformerHandler();
	        Result result = new StreamResult(new File("xml/result.xml"));

	        solve.setResult(new SAXResult(filter));
	        filter.setResult(new SAXResult(view));
	        view.setResult(result);
			generateData(solve, size);
	    } else {
	    	throw new Exception("Can''t support SAXSource or SAXResult");
	    }
	}

Пока, мы видим тут три пустых обработчика, исполняющих тождественное реформирование. В дальнейшем разделе мы начнем наполнять их XSLT-кодом.

1-й подход к снаряду

Выходит, нам нужно расставить ферзей на шахматной доске таким образом, Дабы они не били друг-друга. Для начала нам требуется сгенерировать список позиций, удовлетворяющих условию задачи. Определимся с кодированием позиций. От того что, по условиям задачи, фигуры не могут располагаться на одной вертикали, мы можем применять строку десятичных цифр для кодирования правильных позиций.

Позиция цифры будет обозначать номер вертикали, а само значение — номер горизонтали, на которой расположена фигура. От того что мы используем десятичные цифры, начиная с единицы, мы сумеем решать задачу для квадратной доски размером от 1×1 до 9×9 клеток. Дабы расчеты выполнялись стремительней, рекомендую вначале установить размер меньший 8-ми (5×5 клеток будет в самый раз). Код на XSLT (невзирая на свою излишнюю многословность) абсолютно внятный:

solution.xsl

<?xml version="1.0"?> 

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">

  <xsl:template match="size">
    <result>
      <xsl:call-template name="queens">
        <xsl:with-param name="r"/>
        <xsl:with-param name="n" select="."/>
        <xsl:with-param name="s" select="."/>
      </xsl:call-template>
    </result>
  </xsl:template>

  <xsl:template name="queens">
    <xsl:param name="r"/>
    <xsl:param name="n"/>
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="$n = 0">
        <position>
          <xsl:copy-of select="$r"/>
        </position>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="step">
          <xsl:with-param name="r" select="$r"/>
          <xsl:with-param name="n" select="$n"/>
          <xsl:with-param name="v" select="$s"/>
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="step">
    <xsl:param name="r"/>
    <xsl:param name="n"/>
    <xsl:param name="v"/>
    <xsl:param name="s"/>
    <xsl:if test="$v != 0">
      <xsl:variable name="c">
        <xsl:call-template name="check">
          <xsl:with-param name="r" select="$r"/>
<xsl:with-param name="v" select="$v"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:if test="$c != 0">
        <xsl:variable name="l">
          <xsl:value-of select="concat($v,$r)"/> 
        </xsl:variable>
        <xsl:call-template name="queens">
          <xsl:with-param name="r" select="$l"/>
          <xsl:with-param name="n" select="$n - 1"/>
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:if>
      <xsl:call-template name="step">
        <xsl:with-param name="r" select="$r"/>
        <xsl:with-param name="n" select="$n"/>
        <xsl:with-param name="v" select="$v - 1"/>
        <xsl:with-param name="s" select="$s"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="check">
    <xsl:param name="r"/>
    <xsl:param name="v"/>
    <xsl:if test="contains($r,$v)">0</xsl:if>
  </xsl:template>

</xsl:stylesheet>

Тут мы используем упрощенную проверку на взаимный бой фигур, не исполняя проверку боя по диагонали. Запустив следующую программу на выполнение:

8 ладей

	private void test_solution(String size) throws Exception {
		TransformerFactory tf = TransformerFactory.newInstance();
	    if (tf.getFeature(SAXSource.FEATURE) && tf.getFeature(SAXResult.FEATURE)) {
	        SAXTransformerFactory stf = (SAXTransformerFactory)tf;	  
	        TransformerHandler solve  = stf.newTransformerHandler(new StreamSource("xsl/solution.xsl"));
	        TransformerHandler filter = stf.newTransformerHandler();
	        TransformerHandler view   = stf.newTransformerHandler();
	        Result result = new StreamResult(new File("xml/result.html"));

	        solve.setResult(new SAXResult(filter));
	        filter.setResult(new SAXResult(view));
	        view.setResult(result);
			generateData(solve, size);
	    } else {
	    	throw new Exception("Can''t support SAXSource or SAXResult");
	    }
	}

… дозволено получить список допустимых решений задачи «8 ладей».

Дабы исключить допустимые обвинения в подмене задачи, усложним проверку взаимного боя фигур. Для облегчения повторного применения кода, XSLT предлагает применять вероятность импорта. Ей мы и воспользуемся:

queens.xsl

<?xml version="1.0"?> 

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">

  <xsl:import href="solution.xsl"/>

  <xsl:template name="check">
    <xsl:param name="r"/>
    <xsl:param name="v"/>
    <xsl:choose>
      <xsl:when test="contains($r,$v)">0</xsl:when>
      <xsl:otherwise>
        <xsl:variable name="y">
          <xsl:call-template name="additional_check">
            <xsl:with-param name="r" select="$r"/>
            <xsl:with-param name="v" select="$v"/>
            <xsl:with-param name="d" select="1"/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="$y"/> 
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="additional_check">
    <xsl:param name="r"/>
    <xsl:param name="v"/>
    <xsl:param name="d"/>
    <xsl:if test="$d &lt;= string-length($r)">
      <xsl:variable name="u" select="substring($r,$d,1)"/>
      <xsl:variable name="b">
        <xsl:call-template name="abs">
          <xsl:with-param name="x" select="$v - $u"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="$b = $d">0</xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="additional_check">
            <xsl:with-param name="r" select="$r"/>
            <xsl:with-param name="v" select="$v"/>
            <xsl:with-param name="d" select="$d   1"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
  </xsl:template>

  <xsl:template name="abs">
    <xsl:param name="x"/>
    <xsl:choose>
      <xsl:when test="$x &lt; 0">
        <xsl:value-of select="$x * -1"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$x"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Подмечу, что тут нужно применять именно инструкцию import, а не инструкцию include, Дабы обеспечить больше высокий приоритет образцов в импортирующем образце по сопоставлению с импортируемым (это дюже схоже на наследование).

Дабы каждый данный импорт заработал, нужно внести еще одно малое метаморфоза в Java-код. Определим URIResolver, тот, что будет вызываться при запросе URI в процессе разбора XSLT:

Resolver.java

import java.io.File;

import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamSource;

public class Resolver implements URIResolver {

	public Source resolve(String href, String base) throws TransformerException {
		return new StreamSource(new File("xsl/"   href));
	}
}

… и передадим его фабрике:

8 ферзей

	private void test_queens(String size) throws Exception {
		TransformerFactory tf = TransformerFactory.newInstance();
 		tf.setURIResolver(new Resolver());
	    if (tf.getFeature(SAXSource.FEATURE) && tf.getFeature(SAXResult.FEATURE)) {
	        SAXTransformerFactory stf = (SAXTransformerFactory)tf;	  
	        TransformerHandler solve  = stf.newTransformerHandler(new StreamSource("xsl/queens.xsl"));
	        TransformerHandler filter = stf.newTransformerHandler();
	        TransformerHandler view   = stf.newTransformerHandler();
	        Result result = new StreamResult(new File("xml/result.html"));

	        solve.setResult(new SAXResult(filter));
	        filter.setResult(new SAXResult(view));
	        view.setResult(result);
			generateData(solve, size);
	    } else {
	    	throw new Exception("Can''t support SAXSource or SAXResult");
	    }
	}

Безусловно, в нашем случае, когда все xsl-файлы загружаются из одного дискового каталога, XSLT-процессор и сам восхитительно разберется в том откуда подгрузить файл, но представьте себе, скажем, что XSLT-код загружается из LOB-поля в базе данных!

Запустив программу на выполнение, мы получим список решений задачи.

Что нам с ним делать?

Список решений в том виде, в котором мы его составили, не дюже комфортен для человека. Он суперкомпактен, но не дает наглядного представления о позициях (без некоторого мысленного усилия). Считать число решений вручную, применяя его, также не слишком комфортно. К счастью, обработка таких данных — это именно то, для чего предуготовлен XSLT. Добавив в конец цепочки трансформаций вызов еще одного обработчика, мы сумеем легко подсчитать число решений:

count.xsl

<?xml version="1.0"?> 

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">

  <xsl:template match="result">
    <result>
      <xsl:value-of select="count(position)"/> 
    </result>
  </xsl:template>

</xsl:stylesheet>

… либо, показать их в наглядной форме:

boards.xsl

<?xml version="1.0"?> 

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:redirect="http://xml.apache.org/xalan/redirect"
  extension-element-prefixes="redirect"
  version="1.0">

<xsl:output method="html"/>

  <xsl:template match="/result/position">
    <a href="{concat(. , '.html')}">
      <xsl:value-of select="."/>
    </a><br/>
    <redirect:write select="concat('xml/', . , '.html')">
      <style>
      table {
       display:block;
       margin:10px;
       border:0;
       border-collapse: collapse;
      }
      table tr {
       border:0;
      }
      table tr td {
       border:1px solid #999;
       width:15px;
       height:15px;
       padding: 0;
      }
      .active {
       background: #898989;
      }
      </style>
      <table border="1" style="border-collapse:collapse">
        <xsl:call-template name="line">
          <xsl:with-param name="r" select="."/>
          <xsl:with-param name="s" select="string-length(.)"/>
        </xsl:call-template>
      </table>
    </redirect:write>
  </xsl:template>

  <xsl:template name="line">
    <xsl:param name="r"/>
    <xsl:param name="s"/>
    <xsl:if test="string-length($r) != 0">
      <xsl:variable name="x" select="substring($r,1,1)"/>
      <tr>
        <xsl:call-template name="col">
          <xsl:with-param name="x" select="$x"/>
          <xsl:with-param name="i" select="$s"/>
        </xsl:call-template>
      </tr>
      <xsl:call-template name="line">
        <xsl:with-param name="r" select="substring($r,2)"/>
        <xsl:with-param name="s" select="$s"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="col">
    <xsl:param name="x"/>
    <xsl:param name="i"/>
    <xsl:if test="$i != 0">
      <xsl:choose>
        <xsl:when test="$x = $i"><td/></xsl:when>
        <xsl:otherwise><td/></xsl:otherwise>
      </xsl:choose>
      <xsl:call-template name="col">
        <xsl:with-param name="x" select="$x"/>
        <xsl:with-param name="i" select="$i - 1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

скажем такой:

image

В этом примере следует обратить внимание на нестандартное растяжение Xalan redirect:write, разрешающее перенаправить итог в иной файл (в XSLT 2.0, для этих целей, добавлена стандартная инструкция). К сожалению, мне не удалось перенаправить итог такого redirect-а в произвольный SAX-поток, что, на мой взор, несколько снижает его ценность.

Магия отражений

Мы получили решения, но их как-то слишком много. Это потому, что мы не отсеиваем повторы с учетом допустимых поворотов и отражений доски. Давайте получим список уникальных решений?

Если немножко подумать, становиться ясно, что всевозможных поворотов и отражений доски каждого 8 (рассматривая изначальный вариант). Реализуем вспомогательные образцы для отражения позиции (в нашем внутреннем представлении) по вертикали (flip), горизонтали (reverse) и поворота доски на 90 градусов (rotate):

utils.xsl

<?xml version="1.0"?> 

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">

  <xsl:template match="result">
    <result>
      <xsl:apply-templates/>
    </result>
  </xsl:template>

  <xsl:template match="position">
    <position>
      <xsl:value-of select="."/>
    </position>
    <flip>
      <xsl:call-template name="flip">
        <xsl:with-param name="x" select="."/>
      </xsl:call-template>
    </flip>
    <reverse>
      <xsl:call-template name="reverse">
        <xsl:with-param name="x" select="."/>
      </xsl:call-template>
    </reverse>
    <rotate>
      <xsl:call-template name="rotate">
        <xsl:with-param name="x" select="."/>
      </xsl:call-template>
    </rotate>
  </xsl:template>

  <xsl:template name="flip">
    <xsl:param name="x"/>
    <xsl:call-template name="flip_internal">
      <xsl:with-param name="x" select="$x"/>
      <xsl:with-param name="s" select="string-length($x)   1"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="flip_internal">
    <xsl:param name="x"/>
    <xsl:param name="s"/>
    <xsl:if test="string-length($x) != 0">
      <xsl:value-of select="$s - substring($x,1,1)"/>
      <xsl:call-template name="flip_internal">
        <xsl:with-param name="x" select="substring($x,2)"/>
        <xsl:with-param name="s" select="$s"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <!-- XSLT Cookbook By Sal Mangano http://shop.oreilly.com/product/9780596003722.do -->
  <xsl:template name="reverse">
    <xsl:param name="x"/>
    <xsl:variable name="len" select="string-length($x)"/>
    <xsl:choose>
      <xsl:when test="$len &lt; 2">
        <xsl:value-of select="$x"/>
      </xsl:when>
      <xsl:when test="$len = 2">
        <xsl:value-of select="substring($x,2,1)"/>
        <xsl:value-of select="substring($x,1,1)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="mid" select="floor($len div 2)"/>
        <xsl:call-template name="reverse">
          <xsl:with-param name="x" select="substring($x,$mid 1,$mid 1)"/>
        </xsl:call-template>
        <xsl:call-template name="reverse">
          <xsl:with-param name="x" select="substring($x,1,$mid)"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="rotate">
    <xsl:param name="x"/>
    <xsl:call-template name="rotate_internal">
      <xsl:with-param name="x" select="$x"/>
      <xsl:with-param name="i" select="1"/>
      <xsl:with-param name="r"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="rotate_internal">
    <xsl:param name="x"/>
    <xsl:param name="i"/>
    <xsl:param name="r"/>
    <xsl:variable name="p">
      <xsl:call-template name="index-of">
        <xsl:with-param name="input" select="$x"/>
        <xsl:with-param name="substr" select="$i"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$p = 0">
        <xsl:value-of select="$r"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="rotate_internal">
          <xsl:with-param name="x" select="$x"/>
          <xsl:with-param name="i" select="$i   1"/>
          <xsl:with-param name="r" select="concat($p,$r)"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- XSLT Cookbook By Sal Mangano http://shop.oreilly.com/product/9780596003722.do -->
  <xsl:template name="index-of">
    <xsl:param name="input"/>
    <xsl:param name="substr"/>
    <xsl:choose>
      <xsl:when test="contains($input,$substr)">
        <xsl:value-of select="string-length(substring-before($input,$substr)) 1"/>
      </xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Тут использованы реализации функций reverse и index-of из восхитительной книги Сэл Мангано «XSLT Альманах рецептов». Сама фильтрация уникальных значений — классическая задача на применение оси preceding-sibling:

distinct.xsl

<?xml version="1.0"?> 

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">

  <xsl:import href="utils.xsl"/>

  <xsl:template match="result">
    <result>
      <xsl:apply-templates/>
    </result>
  </xsl:template>

  <xsl:template match="position">
    <xsl:variable name="l" select="preceding-sibling::*"/>
    <xsl:variable name="a" select="."/>
    <xsl:variable name="b">
      <xsl:call-template name="flip">
        <xsl:with-param name="x" select="$a"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="c">
      <xsl:call-template name="reverse">
        <xsl:with-param name="x" select="$b"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="d">
      <xsl:call-template name="flip">
        <xsl:with-param name="x" select="$c"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="e">
      <xsl:call-template name="rotate">
        <xsl:with-param name="x" select="$a"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="f">
      <xsl:call-template name="flip">
        <xsl:with-param name="x" select="$e"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="g">
      <xsl:call-template name="reverse">
        <xsl:with-param name="x" select="$f"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="h">
      <xsl:call-template name="flip">
        <xsl:with-param name="x" select="$g"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$b = $l"></xsl:when>
      <xsl:when test="$c = $l"></xsl:when>
      <xsl:when test="$d = $l"></xsl:when>
      <xsl:when test="$e = $l"></xsl:when>
      <xsl:when test="$f = $l"></xsl:when>
      <xsl:when test="$g = $l"></xsl:when>
      <xsl:when test="$h = $l"></xsl:when>
      <xsl:otherwise>
        <position>
          <xsl:value-of select="$a"/>
        </position>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

К сожалению, в XSLT 1.0, мы не можем решить эту задачу одним XPath выражением, но в XSLT 2.0 добавлена вероятность «обертывания» образцов в пользовательские функции.

На этом все! Мы решили задачу.

Осталось померять…

Кто стремительней?

Измерения будем проводить при помощи дальнейшего кода:

Меряем продуктивность

	private final static String JAVAX_TRANSFORM_FACTORY = "javax.xml.transform.TransformerFactory";
	private final static String SAXON_TRANSFORM_FACTORY = "net.sf.saxon.TransformerFactoryImpl";
	private final static String XALAN_TRANSFORM_FACTORY = "org.apache.xalan.processor.TransformerFactoryImpl";

	private void test_full(String size) throws Exception {
		System.setProperty(JAVAX_TRANSFORM_FACTORY, SAXON_TRANSFORM_FACTORY);
		TransformerFactory tf = TransformerFactory.newInstance();
		tf.setURIResolver(new Resolver());
	    if (tf.getFeature(SAXSource.FEATURE) && tf.getFeature(SAXResult.FEATURE)) {
	        SAXTransformerFactory stf = (SAXTransformerFactory)tf;	  
	        TransformerHandler solve  = stf.newTransformerHandler(new StreamSource("xsl/queens.xsl"));
	        TransformerHandler filter = stf.newTransformerHandler(new StreamSource("xsl/distinct.xsl"));
	        TransformerHandler view   = stf.newTransformerHandler(new StreamSource("xsl/count.xsl"));
	        Result result = new StreamResult(new File("xml/result.xml"));

	        solve.setResult(new SAXResult(filter));
	        filter.setResult(new SAXResult(view));
	        view.setResult(result);

	        Long timestamp = System.currentTimeMillis();
			generateData(solve, size);
			System.out.println("Elapsed Time: "   Long.toString(System.currentTimeMillis() - timestamp));
	    } else {
	    	throw new Exception("Can''t support SAXSource or SAXResult");
	    }
	}

Заменяя константу SAXON_TRANSFORM_FACTORY на XALAN_TRANSFORM_FACTORY дозволено переключаться с одного XSLT-процессора на иной.

К сожалению (по малопонятной мне причине) мне не удалось принудить типично трудиться ни одну из версий ветки Saxon-HE. Код работает, но всякий вызов отрабатывает немыслимо медлительно. Скажем вызов TransformerFactory.newInstance() отрабатывал несколько минут! При этом один из CPU утилизировался всецело, а код (судя по отладчику) огромную часть времени находился где-то в районе реализации SHA-2.

К счастью, больше ранняя версия из соседней ветки работает типично. Вот итоговые картинки:

image

image

Дозволено подметить, что, в этой задаче, оба XSLT-процессора работают примерно с идентичной скоростью. Таким образом, применение Saxon может быть оправдано только при применении функциональности XSLT 2.0 либо XSLT 3.0.

Все начальные тексты, как традиционно, выложены на GitHub.

Напоследок, хочу поблагодарить jonic за оказанную им поддержка при подготовке этой статьи.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB