How to stop XML Tag Attributes from sorting in Ascending Order after modifying the XML file using Java?

2.6k views Asked by At

I have written a program to find all XML files matching a particular pattern in a directory and modify it by adding a new tag.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<paths>
  <upgradepath startversion="1.4.0.0" moduleid="${moduleId}" endversion="1.4.0.1">
    <steps>
      <!-- Put scripts here to go from 1.4.0.0 to 1.4.0.1 -->
    </steps>
  </upgradepath>

  <upgradepath startversion="1.4.0.1" moduleid="${moduleId}" endversion="1.4.0.2">
    <steps>
      <!-- Put scripts here to go from 1.4.0.1 to 1.4.0.2 -->
    </steps>
  </upgradepath>
</paths>

After running my program the XML file gets modified as below :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<paths>
  <upgradepath endversion="1.4.0.1" moduleid="${moduleId}" startversion="1.4.0.0">
    <steps>
      <!-- Put scripts here to go from 1.4.0.0 to 1.4.0.1 -->
    </steps>
  </upgradepath>

  <upgradepath endversion="1.4.0.2" moduleid="${moduleId}" startversion="1.4.0.1">
 <steps>
   <!-- Put scripts here to go from 1.4.0.1 to 1.4.0.2 -->
 </steps>
  </upgradepath>

<upgradepath endversion="1.4.0.3" moduleid="${moduleId}" startversion="1.4.0.2">
<steps>
<!--Put scripts here to go from 1.4.0.2 to 1.4.0.3-->
</steps>
</upgradepath>
</paths>

If you see the attributes of all the tags you will see that they have all been rearranged in ascending order. The startversion attribute now appears last and the endversion attribute appears first. I want the original order of the attributes after modification of the XML file. I have tried almost everything and have lost all hope. Is there any way I can do this? Also is there a way to sort the attributes in descending order? It's not the right solution but it helps.

Here is a code snippet from the program I am using to modify the files :

private static void updateXMLFiles(String sStartVersion, String sEndVersion) {
  try {
    for (int c = 0; c < pathsList.size(); c++) {
      File xmlFile = new File(pathsList.get(c).toString());
      DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder dBuilder;
      dBuilder = dbFactory.newDocumentBuilder();
      Document doc = dBuilder.parse(xmlFile);
      doc.getDocumentElement().normalize();
                
      // Get the last <upgradepath> tag in the file.
      // Method Call to verify the version entered and update the XML Files.

      // Write the updated document to the file.
      doc.getDocumentElement().normalize();
      TransformerFactory transformerFactory = TransformerFactory.newInstance();
      Transformer transformer = transformerFactory.newTransformer();
      DOMSource source = new DOMSource(doc);
      StreamResult result = new StreamResult(new File(pathsList.get(c).toString()));
      transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
      transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
      transformer.transform(source, result);
  } 
  catch (SAXException e1) {
    e1.printStackTrace();
  } 
  catch (ParserConfigurationException e1) {
    e1.printStackTrace();
  } 
  catch (IOException e1) {
    e1.printStackTrace();
  } 
  catch (TransformerException e1) {
    e1.printStackTrace();
  }
}

private static void addNewVersion(Document doc, String sStartVersion, String sEndVersion) {
    Element element = doc.getDocumentElement();
    Element upgradePath = doc.createElement("upgradepath");
    upgradePath.setAttribute("startversion", sStartVersion);
    upgradePath.setAttribute("moduleid", "${moduleId}");
    upgradePath.setAttribute("endversion", sEndVersion);
    Element steps = doc.createElement("steps");
    Comment comment = doc.createComment("Put scripts here to go from " + sStartVersion + " to " + sEndVersion);
    steps.appendChild(comment);
    upgradePath.appendChild(steps);
    element.appendChild(upgradePath);
}

Is there any way I can keep the order of the attributes intact or in the worst case arrange it in descending order? A friend of mine suggested I try out JAXB but I couldn't find a way to achieve this. If someone thinks JAXB can solve this do mention how to format an existing XML file and not creating one. Another issue which is not a major concern is that although I have used the
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
the newly added tags are not indented correctly. Any way to fix this?

2

There are 2 answers

1
SuperRedNova On
@XmlType(propOrder = {"startversion", "moduleid", "endversion", "steps"})
public class XmlSubModel {

    private String startversion = "";
    private String moduleid = "";
    private String endversion = "";
    private String steps = "";

    @XmlAttribute
    public String getStartversion() {
        return startversion;
    }

    public void setStartversion(String startversion) {
        this.startversion = startversion;
    }

    @XmlAttribute
    public String getModuleid() {
        return moduleid;
    }

    public void setModuleid(String moduleid) {
        this.moduleid = moduleid;
    }

    @XmlAttribute
    public String getEndversion() {
        return endversion;
    }

    public void setEndversion(String endversion) {
        this.endversion = endversion;
    }

    public String getSteps() {
        return steps;
    }

    public void setSteps(String steps) {
        this.steps = steps;
    }


}
0
slow_learner On

You cannot control the order of attributes. If you are using DOM, then attributes will be sorted in alphabetical order. One approach is to set your element as string without parsing, this will maintain the order.

Example: element.setTextContent("<child_element attr=""></child_element>")

Later you can parse this while reading.

If you want to specify the order of attributes, it can be achieved by using JAXB. JAXB Example