3

How do I control the order that the XML attributes are listed within the output file?

It seems by default they are getting alphabetized, which the program I'm sending this XML to apparently isn't handling.

e.g. I want zzzz to show first, then bbbbb in the following code.

DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element root = doc.createElement("requests");
doc.appendChild(root);
root.appendChild(request);
root.setAttribute("zzzzzz", "My z value");
root.setAttribute("bbbbbbb", "My b value");

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(file));
transformer.transform(source, result);
Marcs
  • 3,768
  • 5
  • 33
  • 42
Doug
  • 6,446
  • 9
  • 74
  • 107
  • 2
    Related http://stackoverflow.com/q/726395/862441 and http://stackoverflow.com/q/3184598/862441 – srkavin Nov 10 '11 at 23:18
  • If you use JAXB and annotated Objects to represent your XML you can control order with propOrder in the @XmlType-annotation. Related to that: https://stackoverflow.com/questions/5435138/jaxb-and-property-ordering – trappski Oct 05 '18 at 09:16

4 Answers4

3

The order of attributes is defined to be insignificant in XML: no conformant XML application should produce results that depend on the order in which attributes appear. Therefore, serializers (code that produces lexical XML as output) will usually give you no control over the order.

Now, it would sometimes be nice to have that control for cosmetic reasons, because XML is designed to be human-readable. So there's a valid reason for wanting the feature. But the fact is, I know of no serializer that offers it.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • 1
    True. But not only for cosmetic reasons. I am generating 2 xml files and I need to compare them manually and visually see the differences. – Andrés Oviedo May 05 '20 at 11:58
  • 1
    The answer is out of date. These days Saxon offers (a) saxon:attribute-order as a way to control attribute order on serialization, and (b) the option to serialize according to the canonical XML specification, which enables you to compare documents in their lexical form. – Michael Kay May 05 '20 at 12:08
  • Incidentally, we have found that the Edge browser doesn't retain attribute order, and this caused a significant number of W3C tests to fail until we fixed the tests. – Michael Kay May 05 '20 at 12:10
  • I want to warn developers who read this answer and will decide to try Saxon: current free version Saxon-HE:10.3 doesn't allow to use nor SAXON_ATTRIBUTE_ORDER (although keeps the order without specifying this attribute) nor SAXON_INDENT_SPACES (default is 3 unlike java code convention where 1 tab are 4 spaces). – TachikomaGT Jan 26 '21 at 13:24
  • Yes, that's correct. In general, all Saxon language features provided as extensions to the W3C specification require Saxon-PE or higher, which is a commercial product. – Michael Kay Jan 26 '21 at 13:36
2

I had the same issue when I used XML DOM API for writing file. To resolve the problem I had to use XMLStreamWriter. Attributes appear in a xml file in the order you write it using XMLStreamWriter.

Alexandr
  • 9,213
  • 12
  • 62
  • 102
  • 1
    next time it would be much more useful if you could provide at least one small example, not just statement... – qraqatit Jan 31 '20 at 10:28
0

XML Canonicalisation results in a consistent attribute ordering, primarily to allow one to check a signature over some or all of the XML, though there are other potential uses. This may suit your purposes.

John Jerik
  • 39
  • 2
0

If you don't want to use another framework just for a custom attribute order you can simply add an order identifier to the attributes.

<someElement a__price="32" b__amount="3"/>

After the XML serializer is done post process the raw XML like so:

public static String removeAttributeOrderIdentifiers(String xml) {
    return xml.replaceAll(
        " [a-z]__(.+?=\")", 
        "$1"
    );
}

And you will get:

<someElement amount="3" price="32"/>
trallnag
  • 2,041
  • 1
  • 17
  • 33