2

To help with an application that manipulates and works from an XML structure to produce other information, I've created a class structure that closely follows the XML structure.

So, the XML is:

<document>
  <group attr1="thing">
    <title>Some group of things</title>

    <information>
      <content />
    </information>

    <detail attr2="flame">
      <title>Some detail</title>

      <content />
    </detail>

    <subgroup attr1="invisible">
      <title>A subgroup</title>

      <information>
        <content />
      </information>

      <detail attr2="mister">
        <content />
      </detail>
    </subgroup>

    ...
  </group>

  <group>
    <title>...</title>

    <information>
        <content />
    </information>

    <reference ref="elsewhere" />

    ...
  </group>

  ...
</document>

The <reference> element is a special case that pulls in from a matching <detail> in a different group/subgroup.

I've pretty much identified a standard interface for the nodes:

interface iNode {
    getTitle();
    getAttr();
    getInformation();
    getNodes();
}

And then I've implemented in the following four classes, and use a factory to determine which class to use to represent a particular XML DOM Node as I parse through the document:

class NodeGroup implements iNode {
    getTitle()        : return <title>
    getAttr()         : return @attr1
    getInformation()  : return <information>
    getNodes() : return <detail> | <subgroup> | <reference>    
}

class NodeSubGroup implements iNode {
    getTitle()        : return <title>
    getAttr()         : return @attr1
    getInformation()  : return <information>
    getNodes() : return <detail> | <subgroup> | <reference>    
}

class NodeDetail implements iNode {
    getTitle()        : return <title>
    getAttr()         : return @attr2
    getInformation()  : return child::*[not <title>]
    getNodes() : return none
}

class NodeReference implements iNode {
    getTitle()        : return (NodeDetail:getTitle())
    getAttr()         : return (NodeDetail:getAttr())
    getInformation()  : return (NodeDetail:getInformation())
    getNodes() : return none
}

Now, it's pretty clear that the NodeGroup and NodeSubGroup have the same implementation - so I figured I could just create a superclass with the common implementation. Even NodeDetail can extend that superclass since it implements getTitle() in the same way (and override the other three methods).

Having done that, I now have 5 classes and 3 implementations (since NodeGroup and NodeSubGroup are just thin subclasses now that don't override anything).

My question is - do I cut this to 3 classes and have the factory instantiate the superclass for <group> and <subgroup>, or keep all 5 classes, make the superclass abstract, so that there is an explicit one-to-one relationship between classes and XML node types?


Sorry - in an attempt not to get bogged down in the implementation side of things, I probably oversimplified the class examples here. I'm trying to focus whether I should have 5 classes for 5 node types or not - especially when two node types present the same behaviour as far as anything that would need to use them. Using the word Interaction (while meaningful in the context of my applications) was also a poor choice.

Each of these classes instruct an XML parser how to get the relevant information I want from the document for the node that the object represents. Some of those classes also manipulate the information that the parser retrieves.

  • If you had an XML attribute that told you what kind of top-level interaction it was, you'd only need one class. There are many ways to skin this cat. In the JSON world, I can create DTO's for an entire hierarchy. Or (in C#), I can simply ask Newtonsoft to deserialize to a dynamic, and I don't require any DTO classes at all, as long as I'm willing to accept late binding. – Robert Harvey Mar 2 '16 at 6:49
  • well, i don't need even need the XML attribute - one class, store the node name, and then have if statements... i'm guess i'm just wondering if, now i'm in for penny (some subclasses) I should just go in for a pound and have it one-to-one – HorusKol Mar 2 '16 at 12:29
  • 1
    ...explicit .. relationship between classes and XML node types?. No. The XML is simply a data store - an implementation detail. Express the problem domain in code, not the database design. If there is a natural mapping in places, fine. But don't compromise your design. – radarbob Mar 3 '16 at 1:43
  • Do these classes do anything? If they do stuff and the properties are the same perhaps the stuff they do is the same things, just different implementation? Now that sounds like an abstract class. ... iInteraction interface seems pointless. So abstract as to be meaningless. So these classes are "interactable"? Given the XML element names it seems "interaction" is inherent in what they are. What is any OO class for if not interaction? So make classes to give them an identity w/in your business domain. Expressing the problem domain trumps class count. – radarbob Mar 3 '16 at 1:49
  • @radarbob - hmm... maybe i oversimplified my pseudocode - those interface methods are very meaningful in our problem domain, and yes, those classes do the work of extracting information for processing by several different consumers and it made more sense to provide standardised interfaces rather than have the consumers set up all the xpath queries. – HorusKol Mar 3 '16 at 1:52
2

It looks to me like you can use the Composite Pattern for your classes. enter image description here

In the diagram above, CompositeNode is a synonym for Group. It can also be used where you see Subgroups in the XML content.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.