Search code examples
javaandroidkmlexiffilewriter

Java: Create a KML File and insert elements in existing file


I`m developing an app that reads the GPS-Exif Information of Photos and writes the Tags (Lat/Lon,...) in an KML or CSV File. Creating the Files if they dont exist, especially the csv, is not the problem, but in this case i want to add a new KML- placemark to an existing KML-file.

so far i have created a method that checks if the file already exists - if not (if-statement) it creates a new one. and if the file exists it should add the information (else).

public void createKMLFile(){


        String kmlstart = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                        "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n";

        String kmlelement ="\t<Placemark>\n" +
                            "\t<name>Simple placemark</name>\n" +
                            "\t<description>"+name+"</description>\n" +
                            "\t<Point>\n" +
                            "\t\t<coordinates>"+latlon[1]+","+latlon[0]+","+z+ "</coordinates>\n" +
                            "\t</Point>\n" +
                            "\t</Placemark>\n";

        String kmlend = "</kml>";

        ArrayList<String> content = new ArrayList<String>();
        //content.add(0,kmlstart);
        //content.add(1,kmlelement);
        //content.add(2,kmlend);

        String kmltest;


        //Zum Einsetzen eines Substrings (weitere Placemark)
        //String test = "</kml>";
        //int index = kml.lastIndexOf(test);

        File test = new File(datapath+"/"+name+".kml");
        Writer fwriter;

        if(test.exists() == false){
            try {
                content.add(0,kmlstart);
                content.add(1,kmlelement);
                content.add(2,kmlend);
                kmltest = content.get(0) + content.get(1) + content.get(2);

                fwriter = new FileWriter(datapath+"/"+name+".kml");
                fwriter.write(kmltest);
                //fwriter.append("HalloHallo", index, kml.length());
                fwriter.flush();
                fwriter.close();
            }catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }   
        }
        else{
            kmltest = content.get(0) + content.get(1) + content.get(2);
            StringTokenizer tokenize = new StringTokenizer(kmltest, ">");
            ArrayList<String> append = new ArrayList<String>();
            while(tokenize.hasMoreTokens()){

            append.add(tokenize.nextToken());
            append.add(1, kmlelement);

            String rewrite = append.toString();
            try {
                fwriter = new FileWriter(datapath+"/"+name+".kml");
                fwriter.write(rewrite);
                fwriter.flush();
                fwriter.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


            }

        }



    }

I dont get any Logs in the LogCat but the App stops working if i try to update the existing file... any suggestions? thanks in advance

EDIT: Ok i see that content.add(0, kml...) has to be outside the try block... but thats not the main problem it seems


Solution

  • When modifying XML files it is best accomplished using a library of some sort. I maintain the XML-manipulation library called JDOM which is designed to make this sort of manipulation as easy as it can. Other options are using the DOM library (which is already built in to the Java runtime which makes it much easier to integrate in to your program), and SAX (which, in this case, I would not recommend, even though it may be faster). Other external libraries (like JDOM) exist which would also help, like XOM, dom4j, etc. This stackoverflow answer seems relevant: Best XML parser for Java

    In JDOM, your code would look something like:

        Document doc = null;
        Namespace kmlns = new Namespace("http://www.opengis.net/kml/2.2");
        Element position = new Element("Position", kmlns);
        position.addContent(new Element("name", kmlns).setText(positionName));
        position.addContent(new Element("desc", kmlns).setText(description));
        position.addContent(.....   all the XML content needed for the Position ....);
    
        // create the XML Document in memory if the file does not exist
        // otherwise read the file from the disk
        if(!test.exists()){
                doc = new Document();
                Element root = new Element("kml", kmlns);
        } else {
                SAXBuilder sb = new SAXBuilder();
                doc = sb.build(test);
        }
    
        Element root = doc.getRootElement();
        // modify the XML as you need
        // add Position Element
        root.addContent(position);
    
        try {
            fwriter = new FileWriter(datapath+"/"+name+".kml");
            XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
            xout.output(doc, writer);
            fwriter.flush();
            fwriter.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    

    EDIT: you ask what's wrong with your actual code.... There are a few things that are contributing to your problems, but you don't show an actual error, or other indication of how the program 'stops working'.

    1. there are bugs in your code which should throw serious exceptions: kmltest = content.get(0) + content.get(1) + content.get(2); should throw IndexOutOfBoundsException because the content ArrayList is empty (the lines adding values to the ArrayList are commented out....) - but let's assume that they are not....
    2. You never read the file you are changing, so how can you be changing it?
    3. The StringTokenizer delimeter is ">", which is never a good way to parse XML.
    4. You loop through the String tokenizer on evert '>' delimeter, but you never add the token back in to the output (i.e. your output is milling a lot of '>' characters).
    5. You add the kmlelement Position content in the place of every '>' caracter in the document, not just the one that is important.
    6. The FileWriter logic should be ** outside** the loop.... you do not want to modify the file for every token you modify.