Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 13 of 13
  1. #1
    New Coder
    Join Date
    Aug 2007
    Posts
    58
    Thanks
    2
    Thanked 6 Times in 6 Posts

    Extending DOMDocument and setting doctype

    My boss and I are sick of dealing with smarty for our templating system, so we have embarked on a journey to create our own way of doing things. We chose to use DOMDocument. An example DOMDocument I'd like to use:
    PHP Code:
            $doctype DOMImplementation::createDocumentType('html',
                              
    '-//W3C//DTD XHTML 1.0 Transitional//EN',
                              
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd');

            
    $document DOMImplementation::createDocument('http://www.w3.org/1999/xhtml',
                               
    'html',
                               
    $doctype); 
    The trouble is, we don't want to simply use another class, we want to extend it. I'm having trouble creating a constructor to give me what the above code gives. Consider:
    PHP Code:
        public function __constuct() {
            
    parent::__construct('1.0''utf-8');
        } 
    That creates a normal XML doctype declaration. How do I add the XHTML transitional (or any other) doctype? I tried overriding the DOMDocument with the following, but I get the 'Cannot redefine $this' error when I call extendDoctype():
    PHP Code:
    class MyTemplate extends DOMDocument {
        public function 
    __constuct() {
            
    parent::__construct('1.0''utf-8');
        }
        public function 
    extendDoctype() {
            
    $doctype DOMImplementation::createDocumentType('html',
                              
    '-//W3C//DTD XHTML 1.0 Transitional//EN',
                              
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd');

            
    $this DOMImplementation::createDocument('http://www.w3.org/1999/xhtml',
                               
    'html',
                               
    $doctype);
        }


  • #2
    Regular Coder
    Join Date
    May 2008
    Posts
    446
    Thanks
    23
    Thanked 5 Times in 5 Posts
    This probably wont be able to help your error, but I see you are using the DOMDocument for creating objects. W3 officially stated that the best means to use the DOM interface is through the DOMImplementation.

    So instead of this:

    Code:
    class MyTemplate extends DOMDocument {
        public function __constuct() {
            parent::__construct('1.0', 'utf-8');
        }
    use this:

    Code:
    class MyTemplate extends DOMImplementation {
        public function __constuct() {
            parent::__construct('1.0', 'utf-8');
        }
    Source:
    http://us3.php.net/manual/en/class.d...ementation.php


    As for your $this error I would suggest looking at what $this is calling:
    Code:
        public function extendDoctype() {
            $doctype = DOMImplementation::createDocumentType('html',
                              '-//W3C//DTD XHTML 1.0 Transitional//EN',
                              'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd');
    
            $this = DOMImplementation::createDocument('http://www.w3.org/1999/xhtml',
                               'html',
                               $doctype);
        }
    I could be wrong but I would think you are accessing $doctype with the $this, then you have $doctype inside the function which is being saved to $this... May cause a redundancy problem which would explain the key word 'redefine' in the error. Just a thought, I have never worked with a 'redefine' error before, so shooting from the hip there.

  • #3
    Senior Coder Dormilich's Avatar
    Join Date
    Jan 2010
    Location
    Behind the Wall
    Posts
    3,251
    Thanks
    12
    Thanked 340 Times in 336 Posts
    Quote Originally Posted by surreal5335 View Post
    I could be wrong but I would think you are accessing $doctype with the $this, then you have $doctype inside the function which is being saved to $this... May cause a redundancy problem which would explain the key word 'redefine' in the error. Just a thought, I have never worked with a 'redefine' error before, so shooting from the hip there.
    if I remember you can’t redefine $this at all. objects are usually created through a constructor and not by defining $this.
    The computer is always right. The computer is always right. The computer is always right. Take it from someone who has programmed for over ten years: not once has the computational mechanism of the machine malfunctioned.
    André Behrens, NY Times Software Developer

  • #4
    New Coder
    Join Date
    Aug 2007
    Posts
    58
    Thanks
    2
    Thanked 6 Times in 6 Posts
    Quote Originally Posted by surreal5335 View Post
    This probably wont be able to help your error, but I see you are using the DOMDocument for creating objects. W3 officially stated that the best means to use the DOM interface is through the DOMImplementation.

    So instead of this:

    PHP Code:
    class MyTemplate extends DOMDocument {
        public function 
    __constuct() {
            
    parent::__construct('1.0''utf-8');
        } 
    use this:

    PHP Code:
    class MyTemplate extends DOMImplementation {
        public function 
    __constuct() {
            
    parent::__construct('1.0''utf-8');
        } 
    Source:
    http://us3.php.net/manual/en/class.d...ementation.php


    As for your $this error I would suggest looking at what $this is calling:
    PHP Code:
    public function extendDoctype() {
           
    $doctype DOMImplementation::createDocumentType('html',
                              
    '-//W3C//DTD XHTML 1.0 Transitional//EN',
                              
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd');

           
    $this DOMImplementation::createDocument('http://www.w3.org/1999/xhtml',
                               
    'html',
                               
    $doctype);
        } 
    I could be wrong but I would think you are accessing $doctype with the $this, then you have $doctype inside the function which is being saved to $this... May cause a redundancy problem which would explain the key word 'redefine' in the error. Just a thought, I have never worked with a 'redefine' error before, so shooting from the hip there.
    Extending DOMImplemenation doesn't help, because you have to create a new DOMDocument using it. That means I'd have a DOMDocument inside my class instead of extending my class. That's exactly what I don't want. Typing $myclassname->DOMDocument->Method is just really annoying, especially when all I want is to add a few simple things to the class itself. I like verbose naming schemes because often I see legacy code and, honestly, verbose names are the best documentation for things. So I'd really be typing something that long. Ouch. I'd like to cut out $myclassname->

    I'm familiar with the redefine error. There's no conflict in the way it is set up in terms of $doctype and $this, the trouble is that you have to use the __construct (as Dormilich mentioned). I just threw in that information in case anyone tried suggesting it and to prove I actually think for myself before I post
    Last edited by Blue_Jeans; 12-15-2010 at 02:06 AM. Reason: Formatted the CODE tags in the quote to be PHP tags.

  • #5
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    Come again? I'm a little confused here sorry. For starters, you can't exactly extend the DOMImplementation to do what you are wanting. The DOMImplementation doesn't include a parameterized constructor. DOMImplementation::createDocument and createDocumentType are not actually static methods either, so they should not be treated as static. PHP is far too lenient in this regard though.

    Why not simply create a wrapper class with a static creator? You won't be able to do this with the constructor itself.
    PHP Code:
    class MyDOM extends DOMDocument
    {
        public function 
    __construct($a null$b null)
        {
            throw new 
    Exception('Cannot construct ' get_class($this)
                . 
    ', use ' get_class($this) . '::createInstance instead.');
        }

        public static function 
    createInstance($ns null$qn null)
        {
            
    $di = new DOMImplementation();
            
    $dt $di->createDocumentType('html',
                
    '-//W3C//DTD XHTML 1.0 Strict//EN',
                
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
            return 
    $di->createDocument($ns$qn$dt);
        }
    }


    $mydom MyDOM::createInstance();
    print 
    $mydom->saveXML(); 
    There are other alternatives as well, which include passing in the DOMImplementation and DOMDocumentType and constructing from there. I don't like this though as the DOMImplementation will choke if you try to give it more than one creation. On the other hand, pulling out the type for reuse would be aok.
    And any special methods or properties and away you go.

    Also, been a long long while here, but I believe that $this was previously re-definable. I recall it was a stink when they actually stopped that (which doesn't make any sense to have in the first place). I think it was 5.1 when the plug was pulled on that. I can understand why it was liked though; singleton objects could be created with a call against new, and PHP lacks the scoping ability to demote the constructor from an extended class object. This was also an issue since pre-PHP5.3 there was not late static binding in the classes which caused great havok when trying to create extended classes through a singleton from a parent (why bother rewriting the same code over and over for child classes?).
    All of these little problems have been taken care of, and it appears that on Zend's plate is to add a scope demotion for the constructors as well, so that will make it easier too.
    You can always trick a class to do what you want though :P
    Last edited by Fou-Lu; 12-15-2010 at 05:48 AM.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #6
    New Coder
    Join Date
    Aug 2007
    Posts
    58
    Thanks
    2
    Thanked 6 Times in 6 Posts
    Quote Originally Posted by Fou-Lu View Post
    Come again? I'm a little confused here sorry. For starters, you can't exactly extend the DOMImplementation to do what you are wanting. The DOMImplementation doesn't include a parameterized constructor. DOMImplementation::createDocument and createDocumentType are not actually static methods either, so they should not be treated as static. PHP is far too lenient in this regard though.

    Why not simply create a wrapper class with a static creator? You won't be able to do this with the constructor itself.
    PHP Code:
    class MyDOM extends DOMDocument
    {
        public function 
    __construct($a null$b null)
        {
            throw new 
    Exception('Cannot construct ' get_class($this)
                . 
    ', use ' get_class($this) . '::createInstance instead.');
        }

        public static function 
    createInstance($ns null$qn null)
        {
            
    $di = new DOMImplementation();
            
    $dt $di->createDocumentType('html',
                
    '-//W3C//DTD XHTML 1.0 Strict//EN',
                
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
            return 
    $di->createDocument($ns$qn$dt);
        }
    }


    $mydom MyDOM::createInstance();
    print 
    $mydom->saveXML(); 
    There are other alternatives as well, which include passing in the DOMImplementation and DOMDocumentType and constructing from there. I don't like this though as the DOMImplementation will choke if you try to give it more than one creation. On the other hand, pulling out the type for reuse would be aok.
    And any special methods or properties and away you go.

    Also, been a long long while here, but I believe that $this was previously re-definable. I recall it was a stink when they actually stopped that (which doesn't make any sense to have in the first place). I think it was 5.1 when the plug was pulled on that. I can understand why it was liked though; singleton objects could be created with a call against new, and PHP lacks the scoping ability to demote the constructor from an extended class object. This was also an issue since pre-PHP5.3 there was not late static binding in the classes which caused great havok when trying to create extended classes through a singleton from a parent (why bother rewriting the same code over and over for child classes?).
    All of these little problems have been taken care of, and it appears that on Zend's plate is to add a scope demotion for the constructors as well, so that will make it easier too.
    You can always trick a class to do what you want though :P
    Hmm... I'm not sure I understand. We're just all confused. I don't want to extend DOMImplementation, I want to extend a DOMDocument like that you get from using DOMImplementation::createDocumentType(). The code you gave me doesn't achieve this end (though I thank you for it anyway). For example:
    PHP Code:
    class MyDOM extends DOMDocument
    {
        public 
    $title;

        public function 
    __construct($a null$b null)
        {
            throw new 
    Exception('Cannot construct ' get_class($this)
                . 
    ', use ' get_class($this) . '::createInstance instead.');
        }

        public static function 
    createInstance($ns null$qn null)
        {
            
    $di = new DOMImplementation();
            
    $dt $di->createDocumentType('html',
                
    '-//W3C//DTD XHTML 1.0 Strict//EN',
                
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
            return 
    $di->createDocument($ns$qn$dt);
        }
        public function 
    buildTemplate() {
            
    $html $this->createElementNS('http://www.w3.org/1999/xhtml''html');
            
    $head $this->createElement('head');
            
    $title $this->createElement('title'$this->title);

            
    $head->appendChild($title);
            
    $html->appendChild($head);
            
    $this->appendChild($html);
        }
    }


    $mydom MyDOM::createInstance();
    $mydom->title 'Hello, World!';

    $mydom->buildTemplate();

    print 
    $mydom->saveXML(); 
    That throws an error:
    Fatal error: Call to undefined method DOMDocument::buildTemplate()
    I find it odd though, that setting $mydom->title doesn't throw an error. Is there already a variable in DOMDocument of that name? This all seems crazily complicated for no apparent reason.
    Last edited by Blue_Jeans; 12-15-2010 at 06:21 PM. Reason: Added $this-> to $title in buildTemplate()

  • #7
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    Oh yes yes yes, I see now what you want. And what was I thinking, the implementation has no reference to what it should create.
    I'll need to look into this a little further. The problem is the current setup with the final variables within the dom itself.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #8
    New Coder
    Join Date
    Aug 2007
    Posts
    58
    Thanks
    2
    Thanked 6 Times in 6 Posts
    Anyone have any luck? I'm still not getting anywhere on this. It seems like they've deliberately made it impossible to extend DOMDocument and use a custom DOCTYPE.

  • #9
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    I'm in the same boat here as well, I've only tried a couple of things but the API doesn't leave much for movement.
    The last idea I had was to essentially create two DOM's, one that is an actual DOMDocument, and one that is a custom extension, and import the entire dom into it (technically that should work since the DOMDocument is a node). Sadly it did not.
    And since the DOMImplementation does not include a way of using a custom class, I can't actually see a standard way to implement this.
    I'm afraid that you may not be able to implement what you are looking to do.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #10
    New to the CF scene
    Join Date
    Jan 2011
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts
    PHP Code:
    class MyTemplate extends DOMDocument {
        private 
    $itsHtmlElement;

        public function 
    __constuct($version "1.0"$encoding "utf-8") { 
            
    parent::__construct($version$encoding);

            
    $this->appendChild(DOMImplementation::createDocumentType("html""-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"));
            
    $this->itsHtmlElement $this->appendChild($this->createElement("html"));
            
    $this->itsHtmlElement->setAttribute("xmlns""http://www.w3.org/1999/xhtml");
        }

    Works for me!

  • #11
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    Quote Originally Posted by MECHT4NK View Post
    PHP Code:
    class MyTemplate extends DOMDocument {
        private 
    $itsHtmlElement;

        public function 
    __constuct($version "1.0"$encoding "utf-8") { 
           
    // parent::__construct($version, $encoding);

            
    $this->appendChild(DOMImplementation::createDocumentType("html""-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"));
            
    $this->itsHtmlElement $this->appendChild($this->createElement("html"));
            
    $this->itsHtmlElement->setAttribute("xmlns""http://www.w3.org/1999/xhtml");
        }

    Works for me!
    Not for me. The Document type is still a plain XML when dumped with the saveXML method. Since these are declared as final properties that cannot be accessed even during construction, they cannot be overridden.
    ItsHTMLElement is also null on my test, indicating that the createDocument has failed to append.
    I thought I previously indicated that I couldn't merge together a domdocument into another domdocument...
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #12
    New to the CF scene
    Join Date
    Jan 2011
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by Fou-Lu View Post
    Not for me. The Document type is still a plain XML when dumped with the saveXML method. Since these are declared as final properties that cannot be accessed even during construction, they cannot be overridden.
    ItsHTMLElement is also null on my test, indicating that the createDocument has failed to append.
    I thought I previously indicated that I couldn't merge together a domdocument into another domdocument...
    Sorry, I missed an r in __construct. This should work:

    PHP Code:
    class MyTemplate extends DOMDocument {
        private 
    $itsHtmlElement;
        
        public function 
    __construct($version "1.0"$encoding "utf-8") {
            
    parent::__construct($version$encoding);
            
            
    $this->appendChild(DOMImplementation::createDocumentType("html""-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"));
            
    $this->itsHtmlElement $this->appendChild($this->createElement("html"));
            
    $this->itsHtmlElement->setAttribute("xmlns""http://www.w3.org/1999/xhtml");
        }

    To get rid of '<?xml version="1.0" encoding="utf-8"?>' you could replace saveXML with this:

    PHP Code:
    public function saveXML() {
        
    $output = array();
        
        foreach (
    $this->childNodes as $node
            
    $output[] = parent::saveXML($node);
        
        return 
    implode($output);


  • #13
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    I missed the missing r myself!
    I'll have to give this a shot when I get home, I realized as well that I tried to merge the documents, but I haven't tried to append a domdocument into an domdocument.

    I'm still not convinced just by looking at it that the proper doctype and implementation are passed into the root base of the class (we're not trying to strip out the xml tags, just add the proper doctype's to it). I have a feeling as soon as you call that parent::__construct, that it will cause the domdocument to populate the domimplementation within itself which is not cannot be overridden; however, that saveXML idea may work for what is desired as well. If the domimplementation cannot be overridden, than we should be able to simulate it by overriding the saveXML() and pushing the proper doctype onto the string. It would be a hacky approach, but I'd expect that would probably work.

    Edit:
    Alright, so I have no idea why the appending allows you to override the DOMImplementation and DOCType, but this appears to work correctly.
    One thing to note is that this does require you to use the documentElement or a known accessible root element for the DOMDocument as appending directly onto the template class will not properly wrap it up. IMO I wouldn't go without accessing documentElement anyway unless its a completely empty tree, so that is kinda a moot point.
    Good job Mechtank!
    Last edited by Fou-Lu; 01-06-2011 at 12:02 AM.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •