Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/233.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 在DomDocument中,重用DOMXpath,是否稳定?_Php_Xpath - Fatal编程技术网

Php 在DomDocument中,重用DOMXpath,是否稳定?

Php 在DomDocument中,重用DOMXpath,是否稳定?,php,xpath,Php,Xpath,我正在使用下面的功能,但不确定它是否始终稳定/安全是吗? 何时以及谁能够稳定/安全地“重用部分DOMPath准备过程”? 为了简化使用,我们可以采用一个函数,用静态变量记忆最后的调用 函数DOMXpath\u重用器($file){ 静态$doc=NULL; 静态$docName=''; 静态$xp=NULL; 如果(!$doc) $doc=新的DOMDocument(); 如果($file!=$docName){ $doc->loadHTMLFile($file); $xp=NULL; } 如果

我正在使用下面的功能,但不确定它是否始终稳定/安全是吗?

何时以及谁能够稳定/安全地“重用部分DOMPath准备过程”?

为了简化使用,我们可以采用一个函数,用静态变量记忆最后的调用

函数DOMXpath\u重用器($file){ 静态$doc=NULL; 静态$docName=''; 静态$xp=NULL; 如果(!$doc) $doc=新的DOMDocument(); 如果($file!=$docName){ $doc->loadHTMLFile($file); $xp=NULL; } 如果(!$xp) $xp=新的DOMXpath($doc); 返回$xp;//?返回值始终稳定?? }
目前的问题类似于关于XSLTProcessor重用的问题。 在这两个问题中,这个问题可以推广到使用LibXML2作为DomDocument实现的任何语言或框架

还有一个相关问题:


说明 重用非常常见(示例):

但是,如果您执行类似于
removeChild
replaceChild
等操作(示例)

可能会发生额外的事情,并且查询无法按预期工作

  • 何时(哪些DOMDocument方法影响XPath?)
  • 为什么我们不能使用类似“刷新DOM”(存在?)的东西
  • 只有“新的DOMXpath($doc);”是安全的吗?还需要重新加载$doc吗

    • DOMXpath受DOMDocument上的load*()方法的影响。加载新的xml或html后,您需要重新创建DOMXpath实例:

      $xml = '<xml/>';    
      $dom = new DOMDocument();
      $dom->loadXml($xml);
      $xpath = new DOMXpath($dom);
      
      var_dump($xpath->document === $dom); // bool(true)
      
      $dom->loadXml($xml);
      
      var_dump($xpath->document === $dom); // bool(false)
      
      $xml='';
      $dom=新的DOMDocument();
      $dom->loadXml($xml);
      $xpath=newdomxpath($dom);
      var_dump($xpath->document==$dom);//布尔(真)
      $dom->loadXml($xml);
      var_dump($xpath->document==$dom);//布尔(假)
      
      在DOMXpath_reuser()中,存储一个静态变量,并根据文件名重新创建xpath。如果要重用Xpath对象,建议扩展DOMDocument。这样,您只需要传递$dom变量。它可以处理存储的xml文件以及xml字符串或您正在创建的文档

      下面的类使用xpath()方法扩展了DOMDocument,该方法始终为DOMDocument返回有效的DOMDxpath实例。它还存储和注册名称空间:

      class MyDOMDocument
        extends DOMDocument {
      
        private $_xpath = NULL;
        private $_namespaces = array();
      
        public function xpath() {
          // if the xpath instance is missing or not attached to the document
          if (is_null($this->_xpath) || $this->_xpath->document != $this) {
            // create a new one
            $this->_xpath = new DOMXpath($this);
            // and register the namespaces for it
            foreach ($this->_namespaces as $prefix => $namespace) {
              $this->_xpath->registerNamespace($prefix, $namespace);
            }
          }
          return $this->_xpath;
        }
      
        public function registerNamespaces(array $namespaces) {
          $this->_namespaces = array_merge($this->_namespaces, $namespaces);
          if (isset($this->_xpath)) {
            foreach ($namespaces as $prefix => $namespace) {
              $this->_xpath->registerNamespace($prefix, $namespace);
            }
          }
        }
      }
      
      $xml = <<<'ATOM'
        <feed xmlns="http://www.w3.org/2005/Atom">
          <title>Test</title>
        </feed>
      ATOM;
      
      
      $dom = new MyDOMDocument();
      $dom->registerNamespaces(
        array(
          'atom' => 'http://www.w3.org/2005/Atom'
        )
      );
      $dom->loadXml($xml);
      // created, first access
      var_dump($dom->xpath()->evaluate('string(/atom:feed/atom:title)', NULL, FALSE));
      $dom->loadXml($xml);
      // recreated, connection was lost
      var_dump($dom->xpath()->evaluate('string(/atom:feed/atom:title)', NULL, FALSE));
      
      类MyDOMDocument
      扩展DOMDocument{
      私有$_xpath=NULL;
      私有$_名称空间=数组();
      公共函数xpath(){
      //如果xpath实例丢失或未附加到文档
      如果(为空($this->uxpath)|$$this->\uxpath->document!=$this){
      //创建一个新的
      $this->xpath=newdomxpath($this);
      //并为其注册名称空间
      foreach($this->\名称空间为$prefix=>$namespace){
      $this->_xpath->registerNamespace($prefix,$namespace);
      }
      }
      返回$this->\u xpath;
      }
      公共函数注册表命名空间(数组$namespace){
      $this->\u namespaces=array\u merge($this->\u namespaces,$namespaces);
      if(isset($this->\uxpath)){
      foreach($prefix=>$namespace的名称空间){
      $this->_xpath->registerNamespace($prefix,$namespace);
      }
      }
      }
      }
      $xml=loadXml($xml);
      //创建,第一次访问
      var_dump($dom->xpath()->evaluate('string(/atom:feed/atom:title'),NULL,FALSE));
      $dom->loadXml($xml);
      //已重新创建,连接已丢失
      var_dump($dom->xpath()->evaluate('string(/atom:feed/atom:title'),NULL,FALSE));
      
      (这不是真正的答案,而是此处发布的评论和答案以及相关问题的综合)


      这个新版本的问题的
      DOMXpath\u reuse
      函数包含@ThomasWeinert建议(通过外部重新加载
      避免DOM更改)和一个选项
      $enforceRefresh
      ,以解决不稳定性问题(相关问题表明程序员必须在何时检测)

      函数DOMXpath\u reuser\u v2($file,$enforceRefresh=0){//在此处更改
      静态$doc=NULL;
      静态$docName='';
      静态$xp=NULL;
      如果(!$doc)
      $doc=新的DOMDocument();
      如果($file!=$docName | |($xp&&$doc!==$xp->document)){//在此处更改
      $doc->load($file);
      $xp=NULL;
      }elseif($enforceRefresh==2){//添加此新的刷新模式
      $doc->loadXML($doc->saveXML());
      $xp=NULL;
      }
      如果(!$xp | |$enforceRefresh==1)//在此处更改
      $xp=新的DOMXpath($doc);
      返回$xp;
      }
      
      何时必须使用$enforceRefresh=1? 。。。也许是一个公开的问题,只有一些小提示和线索

      • 当DOM提交给setAttribute、removeChild、replaceChild等时
      • 。。。?更多的案例
      何时必须使用$enforceRefresh=2? 。。。也许是一个公开的问题,只有一些小提示和线索

      • 当DOM受到索引不一致等影响时,请参阅
      • 。。。?更多的案例

        • 类(而不是中的XSLTProcessor)使用对构造函数中给定的
          DOMDocument
          对象的引用
          DOMXpath
          基于给定的
          DOMDocument
          创建
          libxml
          上下文对象,并将其保存到内部类数据中。除了
          libxml
          context之外,它还
          s保存对构造函数参数中给定的原始
          DOMDocument`的引用

          这意味着什么:

          答案中的部分样本:

          加载后给出false,因为加载前,
          $dom
          已持有指向新
          libxml
          数据的指针,但
          DOMXpath
          持有
          libxml
          上下文,加载后持有指向真实文档的指针

          现在关于
          查询
          工作

          如果它应该返回
          XPATH\u NODESET
          (与您的情况相同),那么它将创建一个节点副本-逐节点迭代抛出检测到的节点集(
          \ext)
          
          $xml = '<xml/>';    
          $dom = new DOMDocument();
          $dom->loadXml($xml);
          $xpath = new DOMXpath($dom);
          
          var_dump($xpath->document === $dom); // bool(true)
          
          $dom->loadXml($xml);
          
          var_dump($xpath->document === $dom); // bool(false)
          
          class MyDOMDocument
            extends DOMDocument {
          
            private $_xpath = NULL;
            private $_namespaces = array();
          
            public function xpath() {
              // if the xpath instance is missing or not attached to the document
              if (is_null($this->_xpath) || $this->_xpath->document != $this) {
                // create a new one
                $this->_xpath = new DOMXpath($this);
                // and register the namespaces for it
                foreach ($this->_namespaces as $prefix => $namespace) {
                  $this->_xpath->registerNamespace($prefix, $namespace);
                }
              }
              return $this->_xpath;
            }
          
            public function registerNamespaces(array $namespaces) {
              $this->_namespaces = array_merge($this->_namespaces, $namespaces);
              if (isset($this->_xpath)) {
                foreach ($namespaces as $prefix => $namespace) {
                  $this->_xpath->registerNamespace($prefix, $namespace);
                }
              }
            }
          }
          
          $xml = <<<'ATOM'
            <feed xmlns="http://www.w3.org/2005/Atom">
              <title>Test</title>
            </feed>
          ATOM;
          
          
          $dom = new MyDOMDocument();
          $dom->registerNamespaces(
            array(
              'atom' => 'http://www.w3.org/2005/Atom'
            )
          );
          $dom->loadXml($xml);
          // created, first access
          var_dump($dom->xpath()->evaluate('string(/atom:feed/atom:title)', NULL, FALSE));
          $dom->loadXml($xml);
          // recreated, connection was lost
          var_dump($dom->xpath()->evaluate('string(/atom:feed/atom:title)', NULL, FALSE));
          
          var_dump($xpath->document === $dom); // bool(true)  
          $dom->loadXml($xml);    
          var_dump($xpath->document === $dom); // bool(false)