SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Member linde002's Avatar
    Join Date
    Jun 2007
    Location
    Hoorn, The Netherlands
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Wrapping DOM in objects - what kind of approach?

    I am struggling to come up with a clear, readable, usable and OO-friendly approach to parse and manipulate a custom xml format using objects which represent the xml elements. To illustrate here is a basic xml file using this format:
    Code:
    <?xml version='1.0' encoding='UTF-8'?>
    <form id='form001' code='form001' version='1' description='form001_desc'>
       <dimensions>
          <dimension id='dim_01'>
             <levels>
                <level id='dim_01_l01' depth='1'>
                   <members>
                      <member id='dim_01_l02_m01
                   </members>
                </level>
             </levels>
          </dimension>
       </dimensions>
       <cubes>
          <cube id='c01'>
             <axiss>
                <axis id='rows'>
                   <dimensionlist>
                      <dimensionref dimensionid='dim_01'/>
                   </dimensionlist>
                   <tupels>
                      <tupel id='r_1'>
                         <memberref memberid='dim_01_l02_m01'/>
                      </tupel>
                   </tupels>
                </axis>
             </axiss>
          </cube>   
       </cubes>
    </form>
    As you can see the reocurring pattern is a 'container' element like 'dimensions' which hold the 'real' elements, in this case 'dimension'.

    The complete xml format has many more elements (not every container element has only one type of child element) but I choose not to show them here as they would only waste space. The overal concept is the same as showed above.

    The approach I've narrowed in on is that of a builder class, say FormEditor, which works with Object representations of the 'real' elements.
    In this example those objects would be
    • form
    • dimension
    • level
    • member
    • cube
    • (...)


    the Form object would have the following attributes and methods
    • sID
    • sCode
    • sVersion
    • sDescription
    • aDimensions
    • aCubes
    • setAttribute()
    • getAttribute()
    • addCube()
    • getCube()
    • delCube()
    • addDimension()
    • getDimension()
    • delDimension()
    • getXML()


    The other Objects would all use this kind of approach. The function of the getXML() method creates a DOMElement object with the tagname of the element the object is representing, that would be <form> in this example.
    Then it would set all the attributes, after this it would loop over the aDimensions and aCubes array and then call the getXML() method on these objects.

    getXML finally returns the DOMElement object.

    My problem now is: (yes finally ) How would I retrieve a specific Member Object from the top-level Form Element because the Member object is waaaay down in the object hierarchy:
    Code:
       Form
         Dimension
            Level
              Member
    Does anyone who's been able to decypher this riddle have any insights how I should go about creating this? Am I way wrong or just a nudge in the good direction away from my answer?

    P.S. I apologize if some of my concepts are badly explained. English not my mother tongue.
    Last edited by linde002; Jun 6, 2007 at 13:00. Reason: Uncompleted sentence

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by linde002 View Post
    How would I retrieve a specific Member Object from the top-level Form Element because the Member object is waaaay down in the object hierarchy:
    Code:
       Form
         Dimension
            Level
              Member
    The obvious solution is to use recursion. I suspect, that you know this already, and that you're weary of using that approach, because you fear the performance overhead? If you're going to maintain a large object graph, and do a lot of query-by-id, the overhead may be substantial. However, before worrying about this, you have to ask yourself the same question as always, when it comes to performance problems: Is it a real problem or an imagined one? I would suggest, that you implement using recursion, and then later measure if you have a bottleneck or not. If you do, a solution could be to use a hashmap of id => object. This could easily be applied at that point, so no need to spend time on it yet.

  3. #3
    SitePoint Member linde002's Avatar
    Join Date
    Jun 2007
    Location
    Hoorn, The Netherlands
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    The obvious solution is to use recursion. I suspect, that you know this already, and that you're weary of using that approach, because you fear the performance overhead? If you're going to maintain a large object graph, and do a lot of query-by-id, the overhead may be substantial. However, before worrying about this, you have to ask yourself the same question as always, when it comes to performance problems: Is it a real problem or an imagined one? I would suggest, that you implement using recursion, and then later measure if you have a bottleneck or not. If you do, a solution could be to use a hashmap of id => object. This could easily be applied at that point, so no need to spend time on it yet.
    Well the number of objects won't be too big I imagine, a safe guess would be under 4-500 so that shouldn't be too huge (I think)

    I am just pondering how the function would work in the FormEditor class

    say I wanted to retrieve a member object and set it's id attribute
    Code:
         // pseudocode
        function updateMember($sDimensionID, $sLevelID, $sMemberID, $sNewID)
        {
           $oDimension = $this->oForm->getDimension($sDimensionID);
           $oLevel = $oDimension->getLevel($sLevelID);
           $oMember = $oLevel->getMember($sMemberID);
           $oMember->setAttribute('id', $sNewID);
        }
    Is this approach right or is there another way I completely missed?

  4. #4
    SitePoint Evangelist
    Join Date
    Aug 2004
    Posts
    428
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    umm

    I assume you can already create the object hierarchy.
    meaning FormEditor contains the large composite already.

    How would I retrieve a specific Member Object from the top-level Form Element
    because the Member object is waaaay down in the object hierarchy
    $FormEditor->FindControlByID('idofcontrol');
    //return type is object; cast it to the proper control
    //example: ((Cube)$FormEditor->FindControlByID('c01'))->getNumberOfAxis();

    go down every branch until you find the node with this id.





    since you really don't have a deep hierarchy.

    I only see
    PHP Code:
                formeditor
                    
    |
         ----------- ------- ... 
    n
        
    |           |       |
    dimension      cube     n 

    maintaining a composite isn't necessary.. a simple id=>object as kyberfabrikken
    would work fine. if you were keeping track of depth you you need a level dimension not a simple id to object array $node[level][id] => object.

  5. #5
    SitePoint Member linde002's Avatar
    Join Date
    Jun 2007
    Location
    Hoorn, The Netherlands
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by leblanc View Post
    I assume you can already create the object hierarchy.
    meaning FormEditor contains the large composite already.



    $FormEditor->FindControlByID('idofcontrol');
    //return type is object; cast it to the proper control
    //example: ((Cube)$FormEditor->FindControlByID('c01'))->getNumberOfAxis();

    go down every branch until you find the node with this id.





    since you really don't have a deep hierarchy.

    I only see
    PHP Code:
                formeditor
                    
    |
         ----------- ------- ... 
    n
        
    |           |       |
    dimension      cube     n 

    maintaining a composite isn't necessary.. a simple id=>object as kyberfabrikken
    would work fine. if you were keeping track of depth you you need a level dimension not a simple id to object array $node[level][id] => object.

    Yes the number of levels in the composite is 4
    PHP Code:
       Form
          
    |-dimension
          
    |     |-level
          
    |          |-member
          
    |-cube
               
    |-axis
                    
    |-tupel 
    with FormEditor being the builder class. Form class is just another OO representation of an xml element.

    The problem with the FindControlByID() function is a design flaw in the xml format. The axis object's id attribute can only be rows or columns. Seeing that every cube has 2 axis and there are a unlimited number of cubes in a form it's apparent that the id attribute of an axis object is never unique.

  6. #6
    SitePoint Evangelist
    Join Date
    Aug 2004
    Posts
    428
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    let me show u what i've done in the past

    I still only see 1 level. the other levels are simply assigning properties or adding smaller composites.. but your main objects are cube and dimension...all child nodes to formeditor.

    therefore
    //example: ((Cube)$FormEditor->FindControlByID('c01'))->getNumberOfAxis();
    is still valid.


    I normally have one entry point that converts xml to object and vice versa.

    Example load your xml file and begin creating objects like these:
    PHP Code:
                XmlNode shiftpoints systemsetup.NextSibling// shiftpoints
                
    this._ShiftPointsClass = new ShiftPointsClass(
                        
    shiftpoints.FirstChild//composite 1
                        
    shiftpoints.FirstChild.NextSibling//composite 2
                        
    shiftpoints.FirstChild.NextSibling.NextSibling //composite 3
                
    ); 
    noticed i'm sending references to the child xml nodes in the argument... this object is responsible in building itself after that......

    if xml nodes are missing it throws argumentexception error since it wasn't able to construct itself from the xmlnode passed in.

  7. #7
    SitePoint Member linde002's Avatar
    Join Date
    Jun 2007
    Location
    Hoorn, The Netherlands
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't really understand what you are doing with the shiftpoints but I grasp the concept of 3 main objects.

    Could you explain your code some more I am really interested in the workings.

    I'm going to conjure up some code to see how it'll all work

  8. #8
    SitePoint Enthusiast
    Join Date
    Oct 2005
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by linde002 View Post
    My problem now is: (yes finally ) How would I retrieve a specific Member Object from the top-level Form Element because the Member object is waaaay down in the object hierarchy:
    Code:
       Form
         Dimension
            Level
              Member
    Xpath ?

    Tac

  9. #9
    SitePoint Member linde002's Avatar
    Join Date
    Jun 2007
    Location
    Hoorn, The Netherlands
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by tacone View Post
    Xpath ?

    Tac
    Unfortunately this doesn't apply when you use Object representation of a XML structure. When it's exported as a DomDocument then Xpath is the logical choice.

  10. #10
    SitePoint Enthusiast
    Join Date
    Oct 2005
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by linde002 View Post
    Unfortunately this doesn't apply when you use Object representation of a XML structure. When it's exported as a DomDocument then Xpath is the logical choice.
    I though you were extending dom objects, sorry.
    If you're objects have a method able to return their xml rappresentation Xpath can apply too. (even if it would be slower).

    Another route is writing yourself something like xpath. Rewriting xpath from scratch is out of discussion, obviously, but you could start implementing basic rules, and add what you need only when you need it, using the xpath docs as a api reference.

    I mean it shouldn't be so hard to write a simple function like this:

    $form->find( 'dimensions/dimension/levels/level/members' );

    Then you could start implementing something like:

    $form->find( 'dimensions/dimension/levels/level[2]/members' );

    And so on.

    Tac


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
  •