I'm trying to convert a ResultSet to an XML file. I've first used this example for the serialization.
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.Document;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
...
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS impl =
(DOMImplementationLS)registry.getDOMImplementation("LS");
...
LSSerializer writer = impl.createLSSerializer();
String str = writer.writeToString(document);
After I made this work, I tried to validate my XML file, there were a couple of warnings. One about not having a doctype. So I tried another way to implement this. I came across the Transformer class. This class lets me set the encoding, doctype, etc.
The previous implementation supports automatic namespace fix-up. The following does not.
private static Document toDocument(ResultSet rs) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
URL namespaceURL = new URL("http://www.w3.org/2001/XMLSchema-instance");
String namespace = "xmlns:xsi="+namespaceURL.toString();
Element messages = doc.createElementNS(namespace, "messages");
doc.appendChild(messages);
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
String attributeValue = "true";
String attribute = "xsi:nil";
rs.beforeFirst();
while(rs.next()) {
amountOfRecords = 0;
Element message = doc.createElement("message");
messages.appendChild(message);
for(int i = 1; i <= colCount; i++) {
Object value = rs.getObject(i);
String columnName = rsmd.getColumnName(i);
Element messageNode = doc.createElement(columnName);
if(value != null) {
messageNode.appendChild(doc.createTextNode(value.toString()));
} else {
messageNode.setAttribute(attribute, attributeValue);
}
message.appendChild(messageNode);
}
amountOfRecords++;
}
logger.info("Amount of records archived: " + amountOfRecords);
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tf.setOutputProperty(OutputKeys.INDENT, "yes");
BufferedWriter bf = createFile();
StreamResult sr = new StreamResult(bf);
DOMSource source = new DOMSource(doc);
tf.transform(source, sr);
return doc;
}
While I was testing the previous implementation I got an TransformationException: Namespace for prefix 'xsi' has not been declared. As you can see I've tried to add a namespace with the xsi prefix to the root element of my document. After testing this I still got the Exception. What is the correct way to set namespaces and their prefixes?
Edit: Another problem I have with the first implementation is that the last element in the XML document doesn't have the last three closing tags.
You haven't added the namespace declaration in the root node; you just declared the root node in the namespace, two entirely different things. When building a DOM, you need to reference the namespace on every relevant Node. In other words, when you add your attribute, you need to define its namespace (e.g., setAttributeNS).
Side note: Although XML namespaces look like URLs, they really aren't. There's no need to use the URL class here.
The correct way to set a node on a namespaceAware document is by using:
rootNode.createElementNS("http://example/namespace", "PREFIX:aNodeName");
So you can replace "PREFIX" with your own custom prefix and replace "aNodeName" with the name of your node. To avoid having each node having its own namespace declaration you can define the namespaces as attributes on your root node like so:
rootNode.setAttribute("xmlns:PREFIX", "http://example/namespace");
Please be sure to set:
documentBuilderFactory.setNamespaceAware(true)
Otherwise you don't have namespaceAwareness.
Please note that setting an xmlns-prefix with setAttribute is wrong.
If you ever want to eg sign your DOM, you have to use setAttributeNS:
element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");
来源:https://stackoverflow.com/questions/10584670/setting-namespaces-and-prefixes-in-a-java-dom-document