Я использую функцию ниже, но не уверен, что она всегда безопасна … Разве? Нет DOM-памяти или «остаточного XSLT»?
function XSLproc_reuse($domXsl) { static $XSLproc=NULL; if (!$XSLproc) $XSLproc = new XSLTProcessor(); return $XSLproc->importStylesheet($domXsl); // STABLE? }
На нем нет будущих «неожиданных побочных эффектов»?
PS: У меня есть некоторые странные ошибки с моей обработкой XSLT … Итак, отправляя одну (из многих других) гипотез здесь, чтобы проверить, нормально ли или ее следует избегать. Это более очевидно с XPath, см. Этот другой родственный вопрос .
Еще один способ, чтобы ПОЛУЧИТЬ БОЛЬШЕ листа обработки (который я использовал в своей библиотеке), заключается в повторном использовании импортированного XSLT:
function XSLproc_reuse2($nameOrDomXsl='', $domXsl=NULL) { static $XSLproc=NULL; static $name=''; if (!$XSLproc) $XSLproc = new XSLTProcessor(); // else reune of the already initialized $XSLproc. if (is_object($nameOrDomXsl)) return $XSLproc->importStylesheet($nameOrDomXsl); // STABLE? elseif ($nameOrDomXsl==$name); return $XSLproc; // imported in the last call, STABLE? else { // recording for future reuse: $name = $nameOrDomXsl; return $XSLproc->importStylesheet($domXsl); } }
Чтобы понять проблему, важно понять, как XSLTProcessor хранит данные внутри и что происходит после вызова XSLTProcessor::importStylesheet
. Код, реализующий этот класс, находится в \ext\xsl\xsltprocessor.c
из исходного кода php.
Объяснение будет немного упрощено – написано в чистом php 'c'. То, что находится в объекте php – с точки зрения с
просто функций, работает в глобальном контексте.
Веб должен понимать, как и что происходит с импортированными данными:
DOMDocument
или SimpleXMLElement
. Firts, что происходит с импортом (из 409 строк источников, docp
– параметр importStylesheet
)
//php_libxml_import_node is (in the \ext\libxml\libxml.c) just get //the real `xmlNodePtr` XMLlib2 object pointer by php object pointer. nodep = php_libxml_import_node(docp TSRMLS_CC); if (nodep) { doc = nodep->doc; } if (doc == NULL) { php_error(E_WARNING, "Invalid Document"); RETURN_FALSE; } //Next lines is an original comments and call of `xmlCopyDoc` which makes copy // of your stylesheet. The main lines in my answer. /* libxslt uses _private, so we must copy the imported stylesheet document otherwise the node proxies will be a mess */ newdoc = xmlCopyDoc(doc, 1); .... //Here we create internal stylesheet object with libxslt function.
sheetp = xsltParseStylesheetDoc (newdoc);
…
//And some lines later store them to internal variables for this //XSLTProcessor class instance. php_xsl_set_object(id, sheetp TSRMLS_CC);
После importStylesheet
вы можете делать все, что хотите, с помощью объекта $ stylesheet – это не влияет на работу XSLTProcessor
потому что он использует копию таблицы стилей $. Но вы не можете обновить или обновить таблицу $ importStylesheet
без вызова importStylesheet
снова.
Что XSLTProcessor::transformToDoc
( php_xsl_apply_stylesheet
– из строки 477 того же источника) и другие методы transform
. Каждый из них выделяет их тип вывода (DOMDocument в случае XSLTProcessor::transformToDoc
) и использует внутренний объект sheetp
(созданный в importStylesheet
) для преобразования данных.
Отредактировано после комментариев
transformTo
более одного раза. Если повторное использование, если stylesheep использует xsl: key в больших таблицах стилей из-за дополнительного обхода XML-узла. XSLproc_reuse2
имеет смысл и должен использоваться. Вы выполняете кеширование порядка $ stylesheet и трассировки в использовании xsl: key . Не указатель, а весь объект и его внутренние элементы. Пусть s some more words about how the
работает transformToDoc`:
DOMDocument
новый объект DOMDocument
. xsltNewTransformContext
и xsltApplyStylesheetUser
из libxslt
. DOMDocument
Где нет никакого кода штрафа в XSLTProcessor
или libxslt
который неправильно использует XSLTProcessor
использование XSLTProcessor
. Перед 0.7.2 xslcache
я пытаюсь работать с этим проектом и настраивать его для работы с xslcache
сайтом. Есть мой опыт. В то время мы используем XSLT в качестве механизма шаблона с большими XSLT-шаблонами (в раунде ~ 3-5 МБ сокращенного кода). В таких случаях кеширование importStylesheet
имеет большой прирост производительности. Но нет никакой возможности кэшировать результаты transformToDoc
– каждый раз, когда вы вызываете его, libxslt
делает dom манипуляции с двумя подготовленными объектами в памяти и дает вам новый объект в качестве результата.
Использование static определяет глобальное состояние, которое по определению является «неустойчивым». Его можно изменить из любой точки программы. Используя объект, вы получаете локальное состояние (внутри экземпляра объекта). Я также предлагаю использовать массив. Таким образом, он может хранить несколько процессоров для разных файлов.
class XsltFactory { private $_processors = array(); public function get($file) { if (!isset($this->_processors[$file])) { $xslDom = new DOMDocument(); $xslDom->load($file); $xslProc = new XSLTProcessor(); $xslProc->importStylesheet($xslDom); return $this->_processors[$file] = $xslProc; } return $this->_processors[$file]; } } $xsltFactory = new XsltFactory(); var_dump( htmlspecialchars( $xsltFactory->get($template)->transformToDoc($xmlDom)->saveXml() ) );
Лучшим решением для повышения производительности будет xslcache . Он кэширует результат $xslt->importStyleSheet($filename)
внутри процесса. Если процесс повторно используется, то и скомпилированный xsl.