romesub
romesub

Reputation: 233

Java OO design for handling large XML

We are designing a system for processing XML messages.

The processing Java class needs to split out various attributes and values from a largish XML and pass these as parameters to individual handler classes for varied operations.

We have thought of following options:

A)

Pass the entire XML to each handler and let it extract the relevant bits - but feel this might be inefficient to pass the XML around each time

B)

Convert the XML into a DTO or set of smaller DTOs and pass each DTO to relevant handler

C)

Cut the XML into snippets and pass these to each handler method

We're not happy with each of these, so any suggestions which way to go?

Example XML

 <IdAction>supplied</IdAction>
    <RegId>true</RegId>
    <DeRegId>false</DeRegId>
    <SaveMessage>false</SaveMessage>
    <ServiceName>abcRequest</ServiceName>
    <timeToPerform>3600</timeToPerform>
    <timeToReceipt/>
    <SendToBES>true</SendToBES>
    <BESQueueName>com.abc.gateway.JMSQueue.forAddRequest</BESQueueName>
    <BESTransform/>
    <BESJMSProperties>
        <property>
            <propName>stateCode</propName>
            <propValue>OK</propValue>
        </property>
    <property>
            <propName>stateResponse</propName>
            <propValue>OK</propValue>
        </property>
    </BESJMSProperties>

This contains 4 blocks processed by 4 handlers one does

 <IdAction>supplied</IdAction>
    <RegId>true</RegId>
    <DeRegId>false</DeRegId>

another does

<timeToPerform>3600</timeToPerform>
    <timeToReceipt/>

next does

<SendToBES>true</SendToBES>
    <BESQueueName>com.abc.gateway.JMSQueue.forAddRequest</BESQueueName>
    <BESTransform/>
    <BESJMSProperties>
        <property>
            <propName>stateCode</propName>
            <propValue>OK</propValue>
        </property>
    <property>
            <propName>stateResponse</propName>
            <propValue>OK</propValue>
        </property>
    </BESJMSProperties>

and so on

Upvotes: 8

Views: 303

Answers (4)

netbrain
netbrain

Reputation: 9304

Tried? http://simple.sourceforge.net/

Personally i would create a datamodel for the xml and pass the datamodel around. Take a look at the tutorials. With a custom datamodel you can map only the data you want into the model and for the handler classes you can pass along child nodes or a subset of the xml data model instead of the entire thing.

If you have an xml with the following structure

<book>
  <title>XML</title>
  <author>
     <firstname>John</firstname>
     <lastname>Doe</lastname>
  </author>
  <isbn>123541356eas</isbn>
</book>

Then you would have a datamodel something like this:

[    Book     ]         [      Author    ]
---------------         ------------------
|String title |         |String firstname|
|String isbn  |         |String lastname |
|Author author| ------->|----------------|
---------------        

Where Book has a reference to Author. And then you could pass along the Author object to your handler method.

Upvotes: 3

ilcavero
ilcavero

Reputation: 3082

I don't think you need any special design considerations in terms of memory usage or performance so I would go with the solution that involved the least amount of coding and that would be to use a JAXB marshaller to parse your xml into DTOs and then going with your plan B. Perhaps it is harder to set up than StAX but it saves you from writing any XML parsing.

http://jaxb.java.net/

if you are using Spring is very easy to set up a bean for org.springframework.oxm.jaxb.Jaxb2Marshaller http://static.springsource.org/spring-ws/site/reference/html/oxm.html (8.5.2)

Upvotes: 3

bdoughan
bdoughan

Reputation: 149037

You could use StAX for this use case. Each processBlock operation will act on the XMLStreamReader advancing its state, then subsequent processBlock operations can do their bit:

package forum7011558;

import java.io.FileReader;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

public class Demo {

    public static void main(String[] args) throws Exception {
        Demo demo = new Demo();

        FileReader xml = new FileReader("src/forum7011558/input.xml");
        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);

        demo.processBlock1(xsr);
        demo.processBlock2(xsr);
        demo.processBlock3(xsr);
        demo.processBlock4(xsr);
    }

    private void processBlock1(XMLStreamReader xsr) {
        // PROCESS BLOCK 1
    }

    private void processBlock2(XMLStreamReader xsr) {
        // PROCESS BLOCK 2
    }

    private void processBlock3(XMLStreamReader xsr) {
        // PROCESS BLOCK 3
    }

    private void processBlock4(XMLStreamReader xsr) {
        // PROCESS BLOCK 4
    }

}

Upvotes: 2

Brian
Brian

Reputation: 6450

B sounds like the best option to me. A is most inefficient, and C would presumably need one pass to parse it and pick out the fragments, then a 2nd pass to properly handle them?

Use SAX to parse out minimal DTO sets for transmission to dedicated handler classes.

Good question, btw. Good to think about these things in advance, and get 2nd, 3rd, 4th opinions :-)

Upvotes: 6

Related Questions