0

I am trying to convert a XML Node to String using the following code :

private String nodeToString(final Node node) {
    final StringWriter stringWriter = new StringWriter();
    try {
        final Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.transform(new DOMSource(node), new StreamResult(stringWriter));

    } catch (final TransformerException e) {
        JOptionPane.showMessageDialog(this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
    }
    return stringWriter.toString();
}

My problem is that it formats attributes of XML node in alphabetical orders. Is there any property I could apply to ignore formatting of Node attributes ?

Yuvi
  • 1,344
  • 4
  • 24
  • 46
  • @Yuvi i think u can't...because the order of attribute is not a matter in xml .. – Naren Feb 26 '14 at 12:12
  • @McDowell Agreed it is duplicated, but no one suggested how accomplish this in java, with or without using DOM. If you don't know answer, then don't mark it as duplicate. – Yuvi Feb 26 '14 at 12:14
  • @Naren its matter, if you need to verify XML signature. – Yuvi Feb 26 '14 at 12:15
  • @Yuvi ok try .. if u get any positive result let me know – Naren Feb 26 '14 at 12:16

2 Answers2

0

The DOM API does not preserve attribute order:

NamedNodeMaps are not maintained in any particular order

If you have a Node then you have already lost any attribute ordering. Consider this XML:

<?xml version="1.0" encoding="UTF-8"?>
<!-- attrs.xml -->
<attrs
  a="a"
  z="z"
  b="b"
  m="m" />

There are no guarantees about the ordering of the output of this application:

import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;

public class Attrs {
  public static void main(String[] args) throws Exception {
    NamedNodeMap attrs = DocumentBuilderFactory.newInstance()
        .newDocumentBuilder()
        .parse("attrs.xml")
        .getElementsByTagName("attrs")
        .item(0)
        .getAttributes();
    for (int i = 0; i < attrs.getLength(); i++) {
      Attr attribute = (Attr) attrs.item(i);
      System.out.println(attribute.getName() + "=" + attribute.getValue());
    }
  }
}

If they are alphabetical then that is only an implementation side-effect, not a requirement. If attribute order is significant to you then you are using the wrong tools.

McDowell
  • 107,573
  • 31
  • 204
  • 267
  • I am consuming xml at client side, so have to process according to xml created by server. – Yuvi Feb 26 '14 at 13:23
  • The server is not sending you a `org.w3c.dom.Document`. Which APIs you use to parse and transform the data are up to you. The standard Java XML APIs will not do what you want because attribute order generally does not matter. – McDowell Feb 26 '14 at 13:37
  • the order of attributes are significant to me because I'm writing tests and they must never change, even when I reconstitute a DOM into its source string for inspection. I apologize for writing tests. I know it's a bad habit, and I will try to stop – Phlip Jul 08 '23 at 15:20
0

I figure it out how to do this, I have read xml file, and read only specific node from that xml file as a string. And applied operations on string to match my conditions. By doing this obviously I cannot leverage the Parser API, but that fulfilled my requirements. Following is my code snippet:

/**
 * @param in InputStream of xml file
 */
private String getNodeString(InputStream in) throws IOException {

    String nodeString = "";
    InputStreamReader is = new InputStreamReader(in);
    StringBuilder sb = new StringBuilder();
    BufferedReader br = new BufferedReader(is);
    String read = br.readLine();

    String fileData;

    while (read != null) {
        //System.out.println(read);
        sb.append(read);
        read = br.readLine();
    }

    fileData = sb.toString().trim();

    // Start index of node
    int start = fileData.indexOf("<" + mSignedNode);
    // End index of node, next node name
    int end = fileData.indexOf("</Configuration>");

    nodeString = fileData.substring(start, end);
    return nodeString.trim();
}

The method is quite dirty, but you can pass parameters to find start index and end index. Hope this would help someone, rather just closing their question ;)

Yuvi
  • 1,344
  • 4
  • 24
  • 46