SitePoint Sponsor

User Tag List

Results 1 to 6 of 6
  1. #1
    Resident Java Hater
    Join Date
    Jul 2004
    Location
    Gerodieville Central, UK
    Posts
    446
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    DOM / XML Design Issue

    I'm doing stuff with the DOM, and at the moment I am extending DOM classes inorder to add functionallity to it, for instance...

    class HTMLInputTag extends DOMElement {
    //.... Stuff here
    }

    However ...

    This has lead into a few hidden problems. The first thing I found out is I can't do $some_node->appendChild(new HTMLInputTag(...)). When I extract the node out via the $some_node->childNodes NodeList object I find that the object gets recast back to a DOMElement node unless I do ...

    $node = new HTMLInputTag(...);
    $some_node->appendChild($node);

    and make sure that PHP has some variable always referencing $new_node to ensure that the object is not recast.

    However if I want to do import the node into another document, I also get the same issue and there is no work about. If I try to use $new_node = clone $node; I need to reset the pointers to parentNode and the childNodes list which can not be done explictly in PHP...

    Look at my nasty PHP code. I've been lazy here as I'm not using the factories like DOMDocument::createElement(), but I can't be bothered to extend the DOMDocument for now, and this makes no difference it seems

    PHP Code:
    <?php

    class Bar extends DOMElement {
        public 
    $foo 'FooBar happens';
    }

    /* Load of nonsense XML */
    $xml '<root><foo><bar><foo2 /><foo2 />Foo bar Foo bar Foo bar<foo2 /></bar><bar2 /></foo></root>';
    // Yea I know i should use the DOMimplementation factory method here.
    $doc = new DOMDocument();
    $doc->loadXML($xml);
    $root $doc->documentElement;

    /* Append new FooBar into main document */
    $BarObj = new Bar('EatMoreFoo');
    $root->appendChild($BarObj);
    /* Assign FooBar */
    $BarObj->foo 'FooBar Happens to change';
    $BarObj->setAttribute('id''dfdf');

    /* make another document */
    $doc2 = new DOMDocument();
    /* import our other document's root. Note here the upcasting to DOMelement happens */
    $root2 $doc2->importNode($roottrue);
    $doc2->appendChild($root2);

    /* PooPoo happens here. 
     * Node is copied and thus no PHP reference to the node, 
     * hence upcasting of object occur */ 
    $x_path_crap = new DOMXPath($doc2);
    $list_of_crap $x_path_crap->query('//EatMoreFoo');
    print_R($list_of_crap->item(0)); // Should echo FooBar Object()

    ?>
    Can anyone suggest a way round copying nodes without loosing the object type? Or even better could some one suggest another way of using DOM without extending the classes directly, thus avoiding this loss of type during cloning etc.

  2. #2
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I had exactly the same problem as you've now found out There is a solution depending on what version of PHP 5 you have? If you have the latest via CVS you need to use a Document Fragment, prior to appending the node.

    If on the other hand, like me you're using something like version 5.0.2 you have a more difficult time of things

    Fortunately I found a solution which has helped me out a few times. It works but does involve some extra work for you, here is what I found below

    PHP Code:
    //! temp function php version 5.0.2
     //! append a document fragment to a dom document tree
     
    function appendNode$phptag$dom_document$xml_string ) {
      
    $tag $dom_document -> getElementsByTagName$phptag );
      
    $tag $tag -> item(0);
      
      
    $tmp = new domdocument();
      
    $tmp -> load$xml_string );
      
    $node $tag -> ownerDocument -> importNode$tmp -> documentElementtrue );
      
    $child $node -> firstChild;
      
      while( 
    $child ) {
       
    $nextChild $child -> nextSibling;
       
    $tag -> appendChild$child );
       
    $child $nextChild;
      }
      unset( 
    $tmp );
      return 
    $tag
     } 
    And an example to use it

    PHP Code:
    public function executehttp_request $request ) {
       
    $this -> page = new DomDocument;
       
    $this -> page -> load'templates/home/template.tpl' );
       
       
    $entries announcements_gateway::loadannouncements_finder::find_all_by_limit$this -> db) );
       
       
    appendNode'phptag-announcements'$this -> page'sample.xml' );
      } 
    Hope this helps you, as it helped me a lot

  3. #3
    Resident Java Hater
    Join Date
    Jul 2004
    Location
    Gerodieville Central, UK
    Posts
    446
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, I saw something on Christian's Blog about that. I'll look into that as I can compile the PHP on the main hosting + office servers. However I use windows at home and I hate compiling under windows as it's a real *****.

    Thinking about it in retrospect, I think I will go for a simulated DOM system instead of the native DOM as I certainly don't need some features of the DOM. If it wasn't for the silly design querks in PHP it wouldn't be a problem :S

  4. #4
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is a case in which extends may be particularly "evil", since you couple your code tightly to something you have to control over. I wouldn't hesitate to use a Decorator instead.

    I haven't studied this particular problem so I'm not sure it would solve this one, but it typically helps when you have problems with objects belonging to the wrong class.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  5. #5
    Resident Java Hater
    Join Date
    Jul 2004
    Location
    Gerodieville Central, UK
    Posts
    446
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I was thinking about decorators here however things like DOMNode::childNodes, DOMNode:arentNode, etc are public readonly attributes. using a decorator round here kinda breaks things as they'd need to be in getter methods.

    I think this is more of a case of moving away from the DOM library because it doesn't suit the design due to the querks with the DOM memory management issues

  6. #6
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Never thought (in my case) of moving away from the DOM though in a sense still use a simular DOM like API

    I have a library that'd just do the job though for me I would need XPATH support as well which is not supported


Bookmarks

Posting Permissions

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