0

Do method chaining with PHP is easy. But I need something like this,

$xml = $dom->transformToThis('file1.xsl')->transformToThis('file2.xsl')->saveXML();

or

$books = $dom->
    transformToThis('file1.xsl')->
    transformToThis('file2.xsl')->
    getElementsByTagName('book');

It is possible with PHP's DOMDocument or DOMNode?


  class DOMxx extends DOMDocument {

     public function __construct() {
          parent::__construct("1.0", "UTF-8");
     }

     function trasformToThis($xslfile) {
        $xsldom = new DOMDocument('1.0', 'UTF-8');
        $xsldom->load($xslfile);

        $xproc = new XSLTProcessor();
        $xproc->importStylesheet($xsldom);

        $this = $xproc->transformToDoc($this);  // ERROR!
        return $this; 
      }
  } // class

The $this = X is a invalid construct in PHP, and I not understand the workaround explained here. I can use something like $this->loadXML( $xproc->transformToDoc($this)->saveXML() ); but it is a big overload, and the question is about how to do the correct thing.

Another (wrong) way to try to implement,

     function trasformToThis($xslfile) {
        ... same ...
        return  $xproc->transformToDoc($this);  // lost trasformToThis() method
      }

so, in this case the question is "How to cast to DOMxx?".

Community
  • 1
  • 1
Peter Krauss
  • 13,174
  • 24
  • 167
  • 304

2 Answers2

2

How about something like this:

class DOMxx {
  function __construct($version = '1.0', $encoding = 'UTF-8') {
    $this->document = new DOMDocument($version, $encoding);
  }                                                 

  function __call($name, $args) {
    $callback = array($this->document, $name);
    return call_user_func_array($callback, $args);
  }

  function transformToThis($xslfile) {
    $xsldom = new DOMDocument('1.0', 'UTF-8');
    $xsldom->load($xslfile);

    $xproc = new XSLTProcessor();
    $xproc->importStylesheet($xsldom);

    $this->document = $xproc->transformToDoc($this->document);
    return $this; 
  }
}

Instead of extending from DOMDocument, you keep an internal reference to a DOMDocument object inside your DOMxx class. The majority of methods are just forwarded to this internal object via the __call method. And the transformToThis method just updates the reference with the new document returned from the transformToDoc call.

James Holderness
  • 22,721
  • 2
  • 40
  • 52
  • YES, it works with method chaining, thanks a lot! I will do more tests and wait some other answer, but I think your is the best answer. – Peter Krauss Jul 20 '13 at 21:59
0

Do you have a definite requirement that transformToThis() has to modify the original object? I'd think it would be cleaner to do something like this:

function trasform($xslfile) {
    $xsldom = new DOMDocument('1.0', 'UTF-8');
    $xsldom->load($xslfile);

    $xproc = new XSLTProcessor();
    $xproc->importStylesheet($xsldom);

    $xml = $xproc->transformToXML($this);
    $newDom = new DOMxx();
    $newDom.loadXML($xml);
    return $newDom; 
  }

If you really want to modify the original object, I imagine this would work also (for that last part of the method):

    $xml = $xproc->transformToXML($this);
    $this.loadXML($xml);
    return $this; 
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Hum... Thanks the clues, but no one can be used... About your question, YES, the original DOM is discarded, I need only the transformed. About codes. The first code, I think you can simplify with `return $xproc->transformToDoc($this);`, so, it is what all people do. About the second, sorry, I edited my question with "I can use `$this>loadXML( $xproc->transformToDoc($this)->saveXML() );` but it is a big overload". – Peter Krauss Jul 18 '13 at 10:56
  • Could you please explain why "no one can be used"? It doesn't seem that you gave a reason. No, my first example is not equivalent to `return $xproc->transformToDoc($this);`, because in my example, the returned object will actually have the `transform()` method and the chaining will work. And as for the second snippet, there's no point in creating a DOM, getting its XML, and then loading it into another DOM. Just get the XML and load it into a DOM. – JLRishe Jul 18 '13 at 11:13
  • Explaining. I am reading this page with my mind with "context sensitive" enabled: **1**. "no one can be used" = "no of your clues can be used in as solution to my problem, posted as a question". **2**. Sorry, I try to `return $xproc->transformToDoc($this);` and it not works... It works for you?! Later I can try again (!). **3**. "DOM = Load(SaveXML)" is an overhead, "DOM1 = DOM2" or "DOM1 = clone DOM2" is not. – Peter Krauss Jul 18 '13 at 11:17
  • 2. No, `return $xproc->transformToDoc($this);` will **not work** but that's different from what I'm doing in my first example. 3. There may be a tiny amount of overhead, but probably too small to matter and that's better than making some overwrought wrapper class, which would be the other alternative. Incidentally `DOM1 = clone DOM2` would certainly have overhead. – JLRishe Jul 18 '13 at 11:49