0

I would like to insert a new node into a existent xml file, but The code below inserts all the nodes again.

I do a test if the file exists. If not, I create a new xml file and write the tags. If exists, it also creates the nodes, but the wrong way.

//create a new file called "new.xml" in the SD card
File newxmlfile = new File(Environment.getExternalStorageDirectory() + "/download/teste/audit.xml");

if (newxmlfile.exists()){

    try{
        fileos = new FileOutputStream(newxmlfile, true);
    }catch(FileNotFoundException e){
        Log.e("FileNotFoundException", "can't create FileOutputStream");
    }


} else {                    

    try{
        newxmlfile.createNewFile();
    }catch(IOException e){
        Log.e("IOException", "exception in createNewFile() method");
    }

    try{
        fileos = new FileOutputStream(newxmlfile);
    }catch(FileNotFoundException e){
        Log.e("FileNotFoundException", "can't create FileOutputStream");
    }
}

//we create a XmlSerializer in order to write xml data
XmlSerializer serializer = Xml.newSerializer();
try {
    serializer.setOutput(fileos, "UTF-8");
    serializer.startDocument(null, Boolean.valueOf(true));
    serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

    serializer.startTag(null, "root");
        serializer.startTag(null, "child1");
        serializer.endTag(null, "child1");

        serializer.startTag(null, "child2");
        serializer.attribute(null, "attribute", "value");
        serializer.endTag(null, "child2");

            serializer.startTag(null, "child3");
        serializer.text("some text inside child3");
        serializer.endTag(null, "child3");                           
    serializer.endTag(null, "root");
    serializer.endDocument();
    serializer.flush();
    fileos.close();

    Context context = getApplicationContext();
    CharSequence text = "Save!";
    int duration = Toast.LENGTH_SHORT;
    Toast toast = Toast.makeText(context, text, duration);
    toast.show();

} catch (Exception e) {
    Log.e("Exception","error occurred while creating xml file");
}

The result is this:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<root>
  <child1 />
  <child2 attribute="value" />
  <child3>some text inside child3</child3>
</root><?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<root>
  <child1 />
  <child2 attribute="value" />
  <child3>some text inside child3</child3>
</root>

But I want the result like this:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<root>
  <child1 />
  <child2 attribute="value" />
  <child3>some text inside child3</child3>
  <child1 />
  <child2 attribute="value" />
  <child3>some text inside child3</child3>
</root>

Thanks!

Wesley
  • 92
  • 1
  • 3
  • 9
  • So the issue is - another root get created instead of using existing one (in case if file already contains child1-3), right? BTW in the code there's no insertion of child4-6. – sandrstar May 18 '13 at 06:52
  • Correct. I want this: If the document does not exist, it creates the default structure, and then inserts the node. And if the document exists, insert the new node inside root node , and not repeating the structure ` "` – Wesley May 18 '13 at 07:16
  • 1
    @Wesley: Can u please help me with my similar problem? http://stackoverflow.com/questions/21318966/adding-a-node-to-same-xml-file-on-sd-card-under-its-root-tag-in-android – D'yer Mak'er Jan 24 '14 at 06:41
  • Iam facing same Problem.Have you got solution for @D'yerMak'er – Narender Reddy Oct 31 '16 at 11:44

1 Answers1

1

Looks like there's not such API in Android. However, You still have the following options to fix the issue:

  • Look for some open-source library which provides such ability;
  • Do some manual string operations still using XmlSerializer, like provided below:

    private void testXMLFiles() {
        //create a new file called "new.xml" in the SD card
        final File newXmlFile = new File(Environment.getExternalStorageDirectory() + "/download/teste/audit.xml");
        RandomAccessFile randomAccessFile = null;
        final boolean fileExists = newXmlFile.exists();
        String lastLine = null;
    
        if (fileExists) {
            try {
                randomAccessFile = new RandomAccessFile(newXmlFile, "rw");
                randomAccessFile.seek(0);
    
                if (null != randomAccessFile) {
                    final Scanner scanner = new Scanner(newXmlFile);
                    int lastLineOffset = 0;
                    int lastLineLength = 0;
    
                    while (scanner.hasNextLine()) {
                        // +1 is for end line symbol
                        lastLine = scanner.nextLine();
                        lastLineLength = lastLine.length() + 2;
                        lastLineOffset += lastLineLength;
                    }
    
                    // don't need last </root> line offset
                    lastLineOffset -= lastLineLength;
    
                    // got to string before last
                    randomAccessFile.seek(lastLineOffset);
                }
            } catch(FileNotFoundException e) {
                Log.e("FileNotFoundException", "can't create FileOutputStream");
            } catch (IOException e) {
                Log.e("IOException", "Failed to find last line");
            }
        } else {
            try {
                newXmlFile.createNewFile();
            } catch(IOException e) {
                Log.e("IOException", "exception in createNewFile() method");
            }
    
            try {
                randomAccessFile = new RandomAccessFile(newXmlFile, "rw");
            } catch(FileNotFoundException e) {
                Log.e("FileNotFoundException", "can't create FileOutputStream");
            }
        }
    
        //we create a XmlSerializer in order to write xml data
        XmlSerializer serializer = Xml.newSerializer();
    
        if (randomAccessFile == null) {
            return;
        }
    
        try {
            final StringWriter writer = new StringWriter();
    
            serializer.setOutput(writer);
    
            if (!fileExists) {
                serializer.startDocument(null, true);
                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
                serializer.startTag(null, "root");
            } else {
                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
            }
    
            serializer.startTag(null, "child1");
            serializer.endTag(null, "child1");
    
            serializer.startTag(null, "child2");
            serializer.attribute(null, "attribute", "value");
            serializer.endTag(null, "child2");
    
            serializer.startTag(null, "child3");
            serializer.text("some text inside child3");
            serializer.endTag(null, "child3");
    
            if (!fileExists) {
                serializer.endTag(null, "root");
            }
    
            serializer.flush();
    
            if (lastLine != null) {
                serializer.endDocument();
                writer.append(lastLine);
            }
    
            // Add \n just for better output in console
            randomAccessFile.writeBytes(writer.toString() + "\n");
            randomAccessFile.close();
    
            Toast.makeText(getApplicationContext(), "Save!", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            Log.e("Exception","error occurred while creating xml file");
            e.printStackTrace();
        }
    }
    

Its output after second run is the following (quite similar to what You expect):

<?xml version='1.0' standalone='yes' ?>
<root>
  <child1 />
  <child2 attribute="value" />
  <child3>some text inside child3</child3>

<child1 />
<child2 attribute="value" />
<child3>some text inside child3</child3></root>
  • Store all tags from initial xml (e.g. using SAXParser you can read tags, write to new file the same time and apppend new ones at the end using XMLSerializer);
sandrstar
  • 12,503
  • 8
  • 58
  • 65
  • Until the 2º creation, the json file is generated correctly. From the 3º, he inserts the tag after last nodes and and before the end node root. `1º node          some text... child3> 2º 3º onwards some text...some te... some ...` But you gave me the way. Now it only adjust the script to generate correctly. Thanks – Wesley May 20 '13 at 05:04
  • Right, seems new line should be added to have on new line. – sandrstar May 20 '13 at 05:50
  • @sandrstar: I have a similar problem like the question above. Could you please help me with my this question? http://stackoverflow.com/questions/21318966/adding-a-node-to-same-xml-file-on-sd-card-under-its-root-tag-in-android I would greatly appreciate it. – D'yer Mak'er Jan 24 '14 at 06:40
  • 1
    @D'yerMak'er will check it. – sandrstar Jan 24 '14 at 08:51
  • Thank you @sandrstar for your reply. Please look into it. – D'yer Mak'er Jan 24 '14 at 09:13
  • Ya damn good. In this way i am able to append data to xml file but when i retriving data i can read data at first time after appending data iam unable to read data. – Narender Reddy Nov 03 '16 at 11:59
  • XmlPullParser myparser = xmlFactoryObject.newPullParser(); myparser.setInput(new FileInputStream(tempfile), null); while (event != XmlPullParser.END_DOCUMENT) { String name = myparser.getName(); switch (event) { case XmlPullParser.START_TAG: if (name.equals("MyTag")) { temp3 = myparser.getAttributeValue(null, "Attribute1");temp2 = myparser.getAttributeValue(null, "Attribute2"); temp1 = myparser.getAttributeValue(null, "Attribute3"); list1.add(datetemp);list2.add(titletemp);list3.add(datatemp); } break; – Narender Reddy Nov 03 '16 at 12:07
  • sry for unable to show proper way.. i am getting null value at String name = myparser.getName(); – Narender Reddy Nov 03 '16 at 12:08
  • I opend the xml file in storage i found that the xml file is like this: – Narender Reddy Nov 03 '16 at 12:32