1

I am using the function below, but not sure about it is always secure... Is it? No DOM-memory or "residual XSLT" at there?

   function XSLproc_reuse($domXsl) {
      static $XSLproc=NULL;
      if (!$XSLproc)
           $XSLproc = new XSLTProcessor();
      return $XSLproc->importStylesheet($domXsl); // STABLE?
   }

There are no future "surprise side effects" on it?

PS: I have some strange bugs with my XSLT processing... So, posting one (of many other) hypothesis here, to check if ok or must be avoid. This is more evident with XPath, see this other related question.


Another way, to REUSE MORE processing sheet (that I was using on my library), is to reuse also the imported 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);
      }
   }
4

2 回答 2

1

使用静态定义全局状态,即定义为“不稳定”。它可以从程序中的任何位置进行更改。使用对象可以获得本地状态(在对象实例内)。我也建议使用数组。因此它可以为不同的文件存储多个处理器。

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 也是如此。

于 2013-11-21T21:58:56.090 回答
1

要理解这个问题,了解 XSLTProcessor 如何在内部存储数据以及调用XSLTProcessor::importStylesheet. 实现该类的代码位于\ext\xsl\xsltprocessor.cfrom php 源代码中。

解释将不得不简化一点 - 是用纯 php 'c' 编写的。php 对象中有什么 - 仅就с函数而言,它在全局上下文中运行。

Web 需要了解导入数据的方式和情况:

  1. XSLTProcessor::importStylesheet 接受DOMDocumentor的对象SimpleXMLElement
  2. 导入时发生的第一件事(来自 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); 
    
  3. importStylesheet你可以用你的 $stylesheet 对象做任何你想做的事情之后——它不会影响工作,XSLTProcessor因为它使用了 $stylesheet 的副本。但是您无法在不importStylesheet再次调用的情况下刷新或更新您的 $stylesheet。

关于XSLTProcessor::transformToDocphp_xsl_apply_stylesheet- 来自同一来源的 477 行)和其他transform方法。它们中的每一个都分配它们的输出类型(在 的情况下为 DOMDocument XSLTProcessor::transformToDoc)并使用内部sheetp对象(在 中创建importStylesheet)来转换数据。

评论后编辑

  1. 一些关于“何时”和/或“为什么”重用条件的词语是无效的。重复使用是有效的,建议您每次需要transformTo多做一次时重复使用。如果 stylesheep在大样式表上使用xsl:key ,则应该重用,因为额外的 XML 节点遍历。
  2. 仅缓存 XSLTProcessor 对象没有任何意义 - 该对象的构造函数不分配任何内容。并且XSLproc_reuse2有意义,应该使用。您在xsl:key用法中缓存 $stylesheet 复制和遍历的过程。不是指针,而是所有对象及其内部。

s some more words about how thetransformToDoc` 工作:

  1. 分配新DOMDocument对象。
  2. 如果 $stylesheet 有xsl:key它会复制您的 $doc 参数。
  3. xsltNewTransformContext使用和xsltApplyStylesheetUser从制作电车形式libxslt
  4. 返回DOMDocument

哪里没有任何惩罚代码或XSLTProcessor重用错误。在 0.7.2 之前,我尝试使用该项目并将其调整为与外部站点一起使用。有我的经验。那时我们使用 XSLT 作为带有大型 XSLT 模板的模板引擎(大约 3-5mb 的缩小代码)。在这种情况下,缓存具有很大的性能提升。但是没有任何机会缓存结果 - 每次调用它时都会对内存中的两个准备好的对象进行 dom 操作,并为您提供新的对象作为结果。libxsltXSLTProcessorxslcacheimportStylesheettransformToDoclibxslt

于 2013-11-20T09:25:37.467 回答