1

I'm trying to parse an XML containing geographic nodes and ways connecting the nodes using SAX parser. I store the parsed nodes in an ArrayMap<Long, MapPos> and the ways in an ArrayList<ArrayList<MapPos>>. When parsing a way, I create an ArrayList<MapPos> of the referenced nodes and add this to the ArrayList of ways.

After debugging the application, I see that startElement() and endElement() successfully adds the ways to the ArrayList, but in the endDocument() method the ways ArrayList contains nothing but a bunch of empty ArrayList.

Here is the java class:

public class ParkingDataExtractor {
    private static List<ArrayList<MapPos>> roads = new ArrayList<ArrayList<MapPos>>();

    public static List<ArrayList<MapPos>> getWaysFromXML()
            throws ParserConfigurationException, SAXException, IOException{

        SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
        DefaultHandler handler = new DefaultHandler() {
            ArrayMap<Long, MapPos> nodes = new ArrayMap<Long, MapPos>();
            ArrayList<MapPos> nodeBuffer = new ArrayList<MapPos>();
            List<ArrayList<MapPos>> ways = new ArrayList<ArrayList<MapPos>>();
            // private int i; // for debug purposes

            @Override
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes)
                    throws SAXException {
                if (qName.equalsIgnoreCase("node")) {
                    Long id = Long.parseLong(attributes.getValue("id"));
                    Float lat = Float
                            .parseFloat(attributes.getValue("lat"));
                    Float lon = Float
                            .parseFloat(attributes.getValue("lon"));
                    nodes.put(id, new MapPos(lat, lon));
                } else if (qName.equalsIgnoreCase("nd")) {
                    Long ref = Long.parseLong(attributes.getValue("ref"));
                    nodeBuffer.add(nodes.get(ref));
                }
            }

            @Override
            public void endElement(String uri, String localName,
                    String qName) throws SAXException {
                if (qName.equalsIgnoreCase("way")) {
                    ways.add(nodeBuffer);
                    // i++;
                    // if(i==1590) // last element
                    //     ArrayList<MapPos> test = ways.get(i-1); // test = [MapPos [x=..., y=..., z=0.0], MapPos [x=..., y=..., z=0.0],...]
                    nodeBuffer.clear();
                }
            }

            @Override
            public void endDocument() throws SAXException {
                // ArrayList<MapPos> test = ways.get(i-1); // test = []
                roads = ways;
            }
        };

        saxParser.parse("file://" + Environment.getExternalStorageDirectory() 
                + "/roadmap.xml", handler);
        return roads;
    }
}
deakandris
  • 85
  • 2
  • 10

2 Answers2

2

When you call nodeBuffer.clear() you empty the list that you have just passed on to ways. You basically use the same nodeBuffer object over and over, and fill the ways list with a lot of references to the same object - which you empty each time.

The way you should do it is create a new ArrayList object using new and assign it to nodeBuffer every time. You will then have separate objects, each containing the list of nodes parsed in the latest round.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
0

Try this way,hope this will help you to solve your problem.

public class ParkingDataExtractor {
    private static List<ArrayList<MapPos>> roads = new ArrayList<ArrayList<MapPos>>();

    public static List<ArrayList<MapPos>> getWaysFromXML() throws ParserConfigurationException, SAXException, IOException{
        SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();

        DefaultHandler handler = new DefaultHandler() {
            ArrayMap<Long, MapPos> nodes = new ArrayMap<Long, MapPos>();
            ArrayList<MapPos> nodeBuffer;
            List<ArrayList<MapPos>> ways = new ArrayList<ArrayList<MapPos>>();

            @Override
            public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {
                if (qName.equalsIgnoreCase("node")) {
                    Long id = Long.parseLong(attributes.getValue("id"));
                    Float lat = Float.parseFloat(attributes.getValue("lat"));
                    Float lon = Float.parseFloat(attributes.getValue("lon"));
                    nodes.put(id, new MapPos(lat, lon));
                } else if (qName.equalsIgnoreCase("nd")) {
                    Long ref = Long.parseLong(attributes.getValue("ref"));
                    nodeBuffer = new ArrayList<MapPos>();
                    nodeBuffer.add(nodes.get(ref));
                }
            }

            @Override
            public void endElement(String uri, String localName,String qName) throws SAXException {
                if (qName.equalsIgnoreCase("way")) {
                    ways.add(nodeBuffer);
                }
            }

            @Override
            public void endDocument() throws SAXException {
                roads = ways;
            }
        };

        saxParser.parse("file://" + Environment.getExternalStorageDirectory() + "/roadmap.xml", handler);
        return roads;
    }
}
Haresh Chhelana
  • 24,720
  • 5
  • 57
  • 67
  • Did you only removed the line `nodeBuffer.clear();`? That object stores the nodes relevant to the actual way. I need to clear it before reusing it for a new way. – deakandris Oct 10 '14 at 08:47
  • you have initialize nodeBuffer at one time in your code and given value to ways then you try to clan nodeBuffer which reference given to way to so finally your ways list have no data that way i initialize nodeBuffer every time in startElement nd node occurrence and that way not clear in endElement. – Haresh Chhelana Oct 10 '14 at 08:52
  • I see now, but I need a new one only if I finished with a way so I initialized it in `endElement()` where I originally cleared it. Now it works like a charm, thank you. – deakandris Oct 10 '14 at 09:04
  • yes it another way to solve your problem but i given generalized way to solve your problem means initialize nodeBuffer in startElement() instead of endElement(). – Haresh Chhelana Oct 10 '14 at 09:17