Обновление: Я исправил это, чтобы фактически работать; теперь это не ускорение!
Построение ответа @ Уилфреда ...
После манипулирования функцией EXSLT replace () я решил, что достаточно интересно опубликовать другой ответ, даже если он бесполезен для ОП. Это может быть полезно для других.
Это интересно из-за алгоритма: вместо основного алгоритма, работающего здесь (выполнение бинарного рекурсивного поиска, деление пополам при каждой рекурсии, обрезка, когда во 2-й подстроке нет специальных символов, и итерация по выбор специальных символов, когда строка длины = 1 содержит специальный символ), алгоритм EXSLT Джени Теннисон помещает итерацию в набор строк поиска во внешний цикл. Поэтому внутри цикла он ищет только одну строку за раз и может использовать substring-before () / substring-after () для разделения строки вместо слепого деления пополам.
[устарело: Полагаю, этого достаточно, чтобы значительно ускорить его. Мои тесты показывают ускорение на 2,94x по сравнению с самым последним из @ Dimitre (в среднем 230 мс против 676 мс). ] Я тестировал с использованием Saxon 6.5.5 в профилировщике Oxygen XML. В качестве входных данных я использовал XML-документ размером 7 МБ, который в основном представлял собой один текстовый узел, созданный из веб-страниц о javascript , повторение. Мне кажется, что это представитель задачи, которую ОП пытался оптимизировать. Мне было бы интересно узнать, какие результаты получают другие, с их данными испытаний и средами.
Зависимость
При этом используется реализация XSLT replace, которая использует exsl: node-set (). Похоже, xsltproc поддерживает эту функцию расширения (возможно, раннюю версию). Так что это может сработать для вас, @Frerich; и для других процессоров , как это было с Saxon.
Однако если мы хотим 100% чистоту XSLT 1.0, я думаю, что было бы не сложно изменить этот шаблон замены для работы без exsl: node-set (), если 2-й и 3-й параметры передаются как наборы узлов не RTF.
Вот код, который я использовал, который вызывает шаблон замены. Большая часть длины связана с подробным описанием созданных мной наборов узлов поиска / замены ... которые, возможно, могут быть сокращены. (Но вы не можете выполнить поиск или заменить узлы атрибутов , так как шаблон замены в настоящее время написан. Вы получите ошибку при попытке поместить атрибуты в элемент документа.)
<xsl:stylesheet version="1.0" xmlns:str="http://exslt.org/strings"
xmlns:foo="http://www.foo.net/something" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="lars.replace.template.xsl"/>
<foo:replacements>
<replacement>
<search>"</search>
<replace>"\""</replace>
</replacement>
<replacement>
<search>\</search>
<replace>"\\"</replace>
</replacement>
<replacement>
<search>@</search>
<replace>"["</replace>
</replacement>
<replacement>
<search>|</search>
<replace>"["</replace>
</replacement>
<replacement>
<search>#</search>
<replace>"["</replace>
</replacement>
<replacement>
<search>}</search>
<replace>"}"</replace>
</replacement>
<replacement>
<search>&</search>
<replace>"&"</replace>
</replacement>
<replacement>
<search>^</search>
<replace>"^"</replace>
</replacement>
<replacement>
<search>~</search>
<replace>"~"</replace>
</replacement>
<replacement>
<search>/</search>
<replace>"/"</replace>
</replacement>
<replacement>
<search>{</search>
<replace>"{"</replace>
</replacement>
</foo:replacements>
<xsl:template name="escape-text" match="text()" priority="2">
<xsl:call-template name="str:replace">
<xsl:with-param name="string" select="."/>
<xsl:with-param name="search"
select="document('')/*/foo:replacements/replacement/search/text()"/>
<xsl:with-param name="replace"
select="document('')/*/foo:replacements/replacement/replace/text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Изначально импортированная таблица стилей , .
Однако, как отметил @Frerich, это никогда не давало правильного вывода!
Это должно научить меня не публиковать показатели производительности без проверки на правильность!
Я вижу в отладчике, где что-то идет не так, но я не знаю, работал ли шаблон EXSLT или он просто не работал в Saxon 6.5.5 ... любой из этих вариантов был бы удивительным.
В любом случае str: replace () в EXSLT определено для того, чтобы делать больше, чем нам нужно, поэтому я изменил его так, чтобы
- требует, чтобы входные параметры уже были наборами узлов
- как следствие, не требует exsl: node-set ()
- не сортировать строки поиска по длине (в этом приложении все они - один символ)
- не вставлять строку замены между каждой парой символов, когда соответствующая строка поиска пуста
Вот модифицированный шаблон замены:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings">
<!-- By Lars Huttar
based on implementation of EXSL str:replace() by Jenni Tennison.
http://www.exslt.org/str/functions/replace/str.replace.template.xsl
Modified by Lars not to need exsl:node-set(), not to bother sorting
search strings by length (in our application, all the search strings are of
length 1), and not to put replacements between every other character
when a search string is length zero.
Search and replace parameters must both be nodesets.
-->
<xsl:template name="str:replace">
<xsl:param name="string" select="''" />
<xsl:param name="search" select="/.." />
<xsl:param name="replace" select="/.." />
<xsl:choose>
<xsl:when test="not($string)" />
<xsl:when test="not($search)">
<xsl:value-of select="$string" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="search1" select="$search[1]" />
<xsl:variable name="replace1" select="$replace[1]" />
<xsl:choose>
<xsl:when test="contains($string, $search1)">
<xsl:call-template name="str:replace">
<xsl:with-param name="string"
select="substring-before($string, $search1)" />
<xsl:with-param name="search"
select="$search[position() > 1]" />
<xsl:with-param name="replace"
select="$replace[position() > 1]" />
</xsl:call-template>
<xsl:value-of select="$replace1" />
<xsl:call-template name="str:replace">
<xsl:with-param name="string"
select="substring-after($string, $search)" />
<xsl:with-param name="search" select="$search" />
<xsl:with-param name="replace" select="$replace" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="str:replace">
<xsl:with-param name="string" select="$string" />
<xsl:with-param name="search"
select="$search[position() > 1]" />
<xsl:with-param name="replace"
select="$replace[position() > 1]" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Одним из побочных преимуществ этого более простого шаблона является то, что теперь вы можете использовать атрибуты для узлов вашего поиска и заменять параметры. Это сделало бы данные <foo:replacements>
более компактными и легкими для чтения IMO.
Производительность: С этим пересмотренным шаблоном работа будет выполнена примерно за 2,5 с, тогда как мои 0,68 с - для моих недавних испытаний ведущего конкурента, таблицы стилей XSLT 1.0 @ Dimitre. Так что это не ускорение. Но, опять же, у других были результаты тестирования, отличные от моих, поэтому я хотел бы услышать, что другие получают с этой таблицей стилей.