在Java DOM文档中设置名称空间和前缀

我正在尝试将ResultSet转换为XML文件。 我首先使用这个例子进行序列化。

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); 

在我完成这项工作后,我尝试validation我的XML文件,有几个警告。 一个关于没有doctype的人。 所以我尝试了另一种方法来实现它。 我遇到了Transformer课程。 这个类让我设置编码,doctype等。

以前的实现支持自动命名空间修复。 以下不是。

 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; } 

当我测试之前的实现时,我得到了TransformationException:前缀’xsi’的命名空间尚未声明。 正如您所看到的,我已经尝试将带有xsi前缀的命名空间添加到我的文档的根元素中。 经过测试,我仍然得到了例外。 设置命名空间及其前缀的正确方法是什么?

编辑:我对第一个实现的另一个问题是XML文档中的最后一个元素没有最后三个结束标记。

您尚未在根节点中添加名称空间声明; 你刚刚在命名空间中声明了根节点,两个完全不同的东西。 构建DOM时,需要在每个相关节点上引用命名空间。 换句话说,当您添加属性时,您需要定义其命名空间(例如,setAttributeNS)。

旁注:尽管XML命名空间看起来像URL,但实际上并非如此。 这里不需要使用URL类。

在namespaceAware文档上设置节点的正确方法是使用:

 rootNode.createElementNS("http://example/namespace", "PREFIX:aNodeName"); 

因此,您可以将“PREFIX”替换为您自己的自定义前缀,并将“aNodeName”替换为您的节点名称。 为避免每个节点都有自己的名称空间声明,您可以将名称空间定义为根节点上的属性,如下所示:

 rootNode.setAttribute("xmlns:PREFIX", "http://example/namespace"); 

请务必设置:

 documentBuilderFactory.setNamespaceAware(true) 

否则你没有namespaceAwareness。

请注意,使用setAttribute设置xmlns前缀是错误的。 如果您想要例如签署您的DOM,您必须使用setAttributeNS: element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");