2

I have XML data fed through from an API

The data is similar to below

<item>
 <A>xxxxxxxxxxxxxxxxxx</A>
 <B>xxxxxxxxxxxxxxxxxxxx</B>
 <C>xxxxxxxxxxxxxxxxxxxx</C>
 <D>xxxxxxxxxxxxxxxxxxxxx</D>
 </item>
<item>
<item>
 <A>rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr</A>
 <B>rrrrrrrrrrrrrrrrrrrrrr</B>
 <C>rrrrrrrrrrrrrrrrrrrrrr</C>
 <D>rrrrrrrrrrrrrr</D>
 </item>
<item>
<item>
 <A>rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr</A>
 <B>rrrrrrrrrrrrrrrrrrrrrr</B>
 <C>rrrrrrrrrrrrrrrrrrrrrr</C>
 <D>rrrrrrrrrrrrrr</D>
 <E>rrrrrrrrrrrrrr</E>
 </item>
<item>

x and r represents data for each particular element.

Below is an extract of my code, I am adding each element of each node into an arraylist using the following bit of code, a,b,c,d are the arraylists:

for (int i = 0; i < list.getLength(); i++) {
Element element = (Element)list.item(i);
String nodeName = element.getNodeName();

switch (nodeName) {
case "A":
a.add(element.getChildNodes().item(0).getNodeValue()); 
break;
case "B":
b.add(element.getChildNodes().item(0).getNodeValue()); 
break;
case "C":
c.add(element.getChildNodes().item(0).getNodeValue()); 
break;
case "D":
d.add(element.getChildNodes().item(0).getNodeValue()); 
break;
case "E":
e.add(element.getChildNodes().item(0).getNodeValue()); 
break;

The problem is that the XML structure adds node E to the structure in this repeating list partway down the XML. This causes a problem because the lengths of my arraylists are now differing in length. When it comes to comparing arraylists or creating tables of the arraylists the data is not aligned because of the differing lengths. What can i do so that all the arraylists are the same length. I wish to do this as an arraylist.

4
  • use HashSet instead to avoid duplication Commented Aug 28, 2015 at 20:51
  • Recognize the case where no 'e' was seen before the end of the 'item', and add a null or dummy value to the corresponding araylist to occupy that space. Commented Aug 28, 2015 at 20:52
  • @ keshlam how would i do this? Commented Aug 28, 2015 at 22:36
  • Look at my post: Look at how each setter should be defined. Commented Sep 1, 2015 at 23:08

4 Answers 4

4
+50

Synchronizing lists does not seem a good practice. If you want all the lists have the same size, that means that, conceptually, you want just one list. So, redesign your code to match the right concept:

Instead of several lists of beans:

List<A> a;
List<B> b;
List<C> c;
...

... why don't replace it with a single list of a composite bean:

class MyComposite
{
    private A a;
    private B b;
    private C c;

    public A getA()
    {
        return this.a;
    }

    public void setA(A a)
    {
        this.a=a;
    }

    // ... rest of getters and setters...
}

List<MyComposite> list;

So, the population algorithm would be like this:

// Iterate over the "item" nodes of the document:
private List<MyComposite> populate(Document doc)
{
    NodeList items=doc.getElementsByTagName("item");
    List<MyComposite> list=new ArrayList<MyComposite>(items.getLength());
    for (int i = 0; i < items.getLength(); i++)
    {
        Element item = (Element)items.item(i);
        MyComposite myComposite=parseItem(item);
        list.add(myComposite);
    }
    return list;
}

// Create one MyComposite bean reading the child nodes of an input "item" node:
private MyComposite parseItem(Element item)
{
    MyComposite myComposite=new MyComposite();
    NodeList childNodes=item.getChildNodes();
    for (int i = 0; i < childNodes.getLength(); i++)
    {
        // Processing some element in the form: <name>value</name>
        Element element = (Element)childNodes.item(i);
        String nodeName = element.getNodeName();
        String nodeValue = element.getTextContent();

        // Decide where to store the node value (in myComposite) depending on the node name:
        switch (nodeName)
        {
            case "A":
                myComposite.setA(nodeValue); 
                break;
            case "B":
                myComposite.setB(nodeValue); 
                break;
            ...
            default: // An unknown node was found.
                System.err.println("Warning: Node '"+nodeName+"' not recognized and will be ignored");
        }
    }
    return myComposite;
}

In this way, you can have the XML loaded into a coherent data model with no chance of lists with different sizes.

Sign up to request clarification or add additional context in comments.

19 Comments

@ Little Santi, hi thanks for your response I will experiment with this, i am relatively new to Java so i will try get this to work but i may have to revert.
@ Little Santi a quick question why does A, B, and C appear underlined in red in its current form? class MyComposite { private A a; private B b; private C c; // ... getters and setters... } List<MyComposite> list;
Are private A a; private B b;private C c; strings?
I meant A, B and C to be any type you want, even if they have to be different types. Of corse, it is easier they being strings, so the can be got from node values immediately. Should they be other types, a conversion must be done after reading the node values.
Thanks for clarification, i shall try get this to work
|
0

Add dummy or null value in the respective list if node with that name is not found. This will keep all arraylist length equal.

2 Comments

@ Raman Shrivastava could you provide some code on how i would do that?
@ Raman Shrivastava and if i did place an if statement where would i put it because the nodename determines which case is used, if the nodename doesnt state E at what point would i say now fill in a dummy value?
0

Assuming that the endgame of your "action", as implied in "When it comes to comparing arraylists or creating tables of the arraylists the data is not aligned because of the differing lengths", is to store data into database the answer is simple.. Batched Prepared Statement.. these beauties are perfect for doing massive amount of work that is repetitive in nature.. Simply create 5 (n) prepared statement and add batch as you see fit, giving the name of the element, the value of the element and a father key (e.g. the "id" of the relevant item element) and add the "prepared" insert to the batch of the relevant prepared statement.. than execute the whole lot and there you have it, alignement taken care of for free as well ... A sample code of how i would envision this (long, but maybe it will give you some ideas..)... In the sample all prepared statement do the very same thing, but I'm giving four different "actor" method, so that you can basically customize the target query for each different "element" of the item type. Additionally you should plan a full rollback method, as with this "thing" you will commit each block (preparedstatement) when the cap of queryLimit (10000) is reached, so for rolling back you will need to do a manual method cleaning the relevant item (e.g. adding for example a "referral" id of the xml that originated the elements iteselves).

        public class ExternalQueryInputAnnex {

    private int queryLimit = 10000;

        //prep statement for elementA
        private PreparedStatement ps1;
        private int cnt1 = 0;
        //prep statement for elementB
        private PreparedStatement ps2;
        private int cnt2 = 0;
        //prep statement for elementC
        private PreparedStatement ps3;
        private int cnt3 = 0;
        //prep statement for elementD
        private PreparedStatement ps4;
        private int cnt4 = 0;
        //prep statement for elementE
        private PreparedStatement ps5;
        private int cnt5 = 0;


        private void theThingYouNeed(List<Object> itemList)
        {
        for (int i = 0; i < list.getLength(); i++) {
            Element element = (Element)list.item(i);
            String nodeName = element.getNodeName();

            switch (nodeName) {
                case "A":
                doPreparedStatementOne("element.getChildNodes().item(0).getNodeValue()", "A", "whatever");
                break;
                case "B":
                doPreparedStatementTwo("element.getChildNodes().item(0).getNodeValue()", "B", "whatever");
                break;
                case "C":
                doPreparedStatementThree("element.getChildNodes().item(0).getNodeValue()", "C", "whatever");
                break;
                case "D":
                doPreparedStatementFour("element.getChildNodes().item(0).getNodeValue()", "D", "whatever");
                break;
                case "E":
                //e.add(element.getChildNodes().item(0).getNodeValue()); 
                doPreparedStatementFive("element.getChildNodes().item(0).getNodeValue()", "E", "whatever");
                break;
                }
            }
        }

        private void doPreparedStatementFive(String attribute, String sonId, String fatherId) throws DatabaseException {

            int i = 0;

            String query = "INSERT INTO TRS_ORDER_PRICE_INT_DTL_TIMES "
                    + "(SON_VALUE,SON_ID,FATHER_ID) "
                    + "VALUES "
                    + "(?,?,?)";            
            try {
                if (ps5 == null)
                {
                    ps5 = connect.prepareStatement(query);
                }

                ps5.setString(1, attribute);
                ps5.setString(2, sonId);
                ps5.setString(3, fatherId);
                ps5.addBatch();
                cnt5++;
                if (cnt5 >= queryLimit)
                    {
                        ps5 = wrapperDoBulkQueryList(ps5, query);
                        cnt5 = 0;
                    }
                }

            } catch (SQLException e) {
                logger.error("Error insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
                throw new DatabaseException("Sql Exception during insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
            }
        }

        private void doPreparedStatementFour(String attribute, String sonId, String fatherId) throws DatabaseException {

            int i = 0;

            String query = "INSERT INTO TRS_ORDER_PRICE_INT_DTL_TIMES "
                    + "(SON_VALUE,SON_ID,FATHER_ID) "
                    + "VALUES "
                    + "(?,?,?)";            
            try {
                if (ps4 == null)
                {
                    ps4 = connect.prepareStatement(query);
                }

                ps4.setString(1, attribute);
                ps4.setString(2, sonId);
                ps4.setString(3, fatherId);
                ps4.addBatch();
                cnt4++;
                if (cnt4 >= queryLimit)
                    {
                        ps4 = wrapperDoBulkQueryList(ps4, query);
                        cnt4 = 0;
                    }
                }

            } catch (SQLException e) {
                logger.error("Error insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
                throw new DatabaseException("Sql Exception during insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
            }
        }

        private void doPreparedStatementThree(String attribute, String sonId, String fatherId) throws DatabaseException {

            int i = 0;

            String query = "INSERT INTO TRS_ORDER_PRICE_INT_DTL_TIMES "
                    + "(SON_VALUE,SON_ID,FATHER_ID) "
                    + "VALUES "
                    + "(?,?,?)";            
            try {
                if (ps3 == null)
                {
                    ps3 = connect.prepareStatement(query);
                }

                ps3.setString(1, attribute);
                ps3.setString(2, sonId);
                ps3.setString(3, fatherId);
                ps3.addBatch();
                cnt3++;
                if (cnt3 >= queryLimit)
                    {
                        ps3 = wrapperDoBulkQueryList(ps3, query);
                        cnt3 = 0;
                    }
                }

            } catch (SQLException e) {
                logger.error("Error insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
                throw new DatabaseException("Sql Exception during insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
            }
        }

        private void doPreparedStatementTwo(String attribute, String sonId, String fatherId) throws DatabaseException {

            int i = 0;

            String query = "INSERT INTO TRS_ORDER_PRICE_INT_DTL_TIMES "
                    + "(SON_VALUE,SON_ID,FATHER_ID) "
                    + "VALUES "
                    + "(?,?,?)";            
            try {
                if (ps2 == null)
                {
                    ps2 = connect.prepareStatement(query);
                }

                ps2.setString(1, attribute);
                ps2.setString(2, sonId);
                ps2.setString(3, fatherId);
                ps2.addBatch();
                cnt2++;
                if (cnt2 >= queryLimit)
                    {
                        ps2 = wrapperDoBulkQueryList(ps2, query);
                        cnt2 = 0;
                    }
                }

            } catch (SQLException e) {
                logger.error("Error insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
                throw new DatabaseException("Sql Exception during insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
            }
        }

        private void doPreparedStatementOne(String attribute, String sonId, String fatherId) throws DatabaseException {

            int i = 0;

            String query = "INSERT INTO TRS_ORDER_PRICE_INT_DTL_TIMES "
                    + "(SON_VALUE,SON_ID,FATHER_ID) "
                    + "VALUES "
                    + "(?,?,?)";            
            try {
                if (ps1 == null)
                {
                    ps1 = connect.prepareStatement(query);
                }

                ps1.setString(1, attribute);
                ps1.setString(2, sonId);
                ps1.setString(3, fatherId);
                ps1.addBatch();
                cnt1++;
                if (cnt1 >= queryLimit)
                    {
                        ps1 = wrapperDoBulkQueryList(ps1, query);
                        cnt1 = 0;
                    }
                }

            } catch (SQLException e) {
                logger.error("Error insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
                throw new DatabaseException("Sql Exception during insertOrderPriceIntDtlTimes: "+e.getLocalizedMessage());
            }
        }

        // do any sub-querylimit execution
        public void cleanUpExecution() throws DatabaseException
        {
            if (ps1 != null)
            {
                logger.debug("ps1");
                wrapperDoBulkQueryList(ps1, null);
            }
            if (ps2 != null)
            {
                logger.debug("ps2");
                wrapperDoBulkQueryList(ps2, null);
            }
            if (ps3 != null)
            {
                logger.debug("ps3");
                wrapperDoBulkQueryList(ps3, null);
            }
            if (ps4 != null)
            {
                logger.debug("ps4");
                wrapperDoBulkQueryList(ps4, null);
            }
            if (ps5 != null)
            {
                logger.debug("ps5");
                wrapperDoBulkQueryList(ps5, null);
            }
        }

        public PreparedStatement wrapperDoBulkQueryList(PreparedStatement queryBulk, String query) throws DatabaseException
        {

            queryBulk = wrapperDoBulkQueryListDirect(queryBulk, null, query);
            return queryBulk;
        }

        public PreparedStatement wrapperDoBulkQueryListDirect(PreparedStatement queryList, Long load_id, String query) throws DatabaseException
        {
            if (doBulkQueryList(queryList))
            {
                if (query != null)
                {
                    try
                    {
                        queryList = connect.prepareStatement(query);
                        return queryList;
                    }
                    catch (SQLException e)
                    {
                        throw new DatabaseException("Exception of sqlexception while regenerating statement:"+e.getLocalizedMessage());
                    }
                }
                else
                {
                    logger.debug("Query not passed, cleanup for preparedstatement");
                    //System.out.println("Query not passed, cleanup for preparedstatement");
                    return queryList;
                }
            }
            else
            {
                // do delete based on loadid
                // then throw exception
                throw new DatabaseException("Some failure");
            }
        }

        public boolean doBulkQueryList(PreparedStatement queryList) throws DatabaseException
        {
            // do bulk query execution
            try {
                connect.setAutoCommit(false);
                //System.out.println("query: "+singleQuery.toString());
                long startSetup = System.currentTimeMillis();
                int[] results = queryList.executeBatch();
                long finishSetup = (System.currentTimeMillis()-startSetup)/1000;
                if(finishSetup > 5){
                    logger.warn("Execution "+results.length+" insert in "+finishSetup+" seconds.");
                }


                for(int singleResult : results){
                    if (singleResult >= 0) {
                        // System.out.println("OK; updateCount");
                    }
                    else if (singleResult == Statement.SUCCESS_NO_INFO) {
                        // System.out.println("OK; insert=Statement.SUCCESS_NO_INFO");
                    }
                    else if (singleResult == Statement.EXECUTE_FAILED) {
                        System.out.println("Failure; updateCount=Statement.EXECUTE_FAILED");
                    }
                }

                insertedRows = insertedRows + results.length;
                //System.out.println("Query effettuata");
                connect.commit();
            } catch (SQLException e) {
                //e.printStackTrace();
                if (connect != null) {
                    try {
                        logger.error("Transaction is being rolled back: ",e);

                        connect.rollback();
                        return false;
                    } catch(SQLException excep) {

                        throw new DatabaseException("Error Transaction commit");
                    }

                }
            }
            finally{
                if (queryList != null) {
                    try {
                        queryList.close();
                    } catch (SQLException e) {

                        logger.error("Transaction is being rolled back: "+e.getLocalizedMessage());
                    }
                }
                try {
                    connect.setAutoCommit(true);
                } catch (SQLException e) {

                    logger.error("Set true auto commit: ",e);
                }
            }
            return true;
        }
    }

Comments

0

If your xml is proper with proper root tag, the easiest approach would be to use Jaxb. Since JDK 1.6 JaxB comes out of the box. The code would be short and simple like

File file = new File("Item.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
JAXBContext jaxbContext = JAXBContext.newInstance(Items.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Items items = (Items) jaxbUnmarshaller.unmarshal(dBuilder.parse(file));

A complete example. Say your xml is like

<items>
    <item>
        <A>xxxxxxxxxxxxxxxxxx</A>
        <B>xxxxxxxxxxxxxxxxxxxx</B>
        <C>xxxxxxxxxxxxxxxxxxxx</C>
        <D>xxxxxxxxxxxxxxxxxxxxx</D>
    </item>
    <item>
        <A>rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr</A>
        <B>rrrrrrrrrrrrrrrrrrrrrr</B>
        <C>rrrrrrrrrrrrrrrrrrrrrr</C>
        <D>rrrrrrrrrrrrrr</D>
    </item>
    <item>
        <A>rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr</A>
        <B>rrrrrrrrrrrrrrrrrrrrrr</B>
        <C>rrrrrrrrrrrrrrrrrrrrrr</C>
        <D>rrrrrrrrrrrrrr</D>
        <E>rrrrrrrrrrrrrr</E>
    </item>
</items>

Then you need to create 2 class one parent Items and child Item (or whatever name you like).

import java.io.File;
import java.io.Serializable;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

@XmlRootElement(name = "items")
class Items implements Serializable {
    List<Item> item;

    public List<Item> getItem() {
        return item;
    }

    @XmlElement(name = "item")
    public void setItem(List<Item> item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "Items [" + item + "]";
    }
}

class Item implements Serializable {
    private String a;
    private String b;
    private String c;
    private String d;
    private String e;

    public String getA() {
        return a;
    }

    @XmlElement(name = "A")
    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    @XmlElement(name = "B")
    public void setB(String b) {
        this.b = b;
    }

    public String getC() {
        return c;
    }

    @XmlElement(name = "C")
    public void setC(String c) {
        this.c = c;
    }

    public String getD() {
        return d;
    }

    @XmlElement(name = "D")
    public void setD(String d) {
        this.d = d;
    }

    public String getE() {
        return e;
    }

    @XmlElement(name = "E")
    public void setE(String e) {
        this.e = e;
    }

    @Override
    public String toString() {
        return "Item [a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + ", e="
                + e + "]";
    }
}

public class ItemParser {

    public static void main(String[] args) throws Exception {
        File file = new File("Item.xml"); // Give appropriate file path.
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        JAXBContext jaxbContext = JAXBContext.newInstance(Items.class);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        Items items = (Items) jaxbUnmarshaller.unmarshal(dBuilder.parse(file));
        System.out.println(items);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.