之前在stackoverflow中已经问过这个问题:
真的不可能吗?
使用insertBefore我想为元素排序属性序列。具体来说,在下面的示例中,如何更改属性的顺序?从节点中使用setAttribute会更容易吗?在任何一种情况下,订单似乎都是自动发生的,尽管insertBefore肯定意味着可以指定订单。
代码:
package xml;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class Main {
private static final Logger logger = Logger.getLogger(Main.class.getName());
/**
* catches errors
*/
public Main() {
try {
createDoc();
} catch (ParserConfigurationException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerConfigurationException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void createDoc()
throws ParserConfigurationException, TransformerConfigurationException, TransformerException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setIgnoringComments(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
doc.setXmlStandalone(true);
Comment comment = doc.createComment(" nodes ");
doc.appendChild(comment);
Element root = doc.createElement("foo");
root.setAttribute("Version", "1.0");
doc.appendChild(root);
Element bar = doc.createElement("bar");
Element baz = doc.createElement("baz");
Element child1 = doc.createElementNS("foo", "bar");
child1.setPrefix("prefix1");
Attr attr1 = doc.createAttribute("attr1");
attr1.setValue("val1");
Element child2 = doc.createElementNS("foo", "bar");
child2.setPrefix("prefix2");
Attr attr2 = doc.createAttribute("attr2");
attr2.setValue("val2");
baz.setAttributeNode(attr2);
baz.setAttributeNode(attr1);
root.appendChild(bar);
bar.appendChild(baz);
writeToFile(doc);
}
private void writeToFile(Document doc)
throws TransformerConfigurationException, TransformerException, IOException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setAttribute("indent-number", new Integer(2));
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
logger.log(Level.INFO, "\n{0}", sw.toString());
result = new StreamResult(new FileWriter("test.xml"));
transformer.transform(source, result);
}
public static void main(String args[]) {
Main main = new Main();
}
}
答案 0 :(得分:4)
XML元素属性的排序不是XML information set的一部分,因此实现(包括DOM,解析器和解析器)没有义务保留它。
实际上,这意味着它是特定于实现的,是否可以通过DOM API控制属性的顺序(例如,使用insertBefore),并且它是否是实现特定的,是否将在转换之间保留排序。
我的建议是更改您的应用程序,使其不依赖于XML属性排序。
答案 1 :(得分:2)
底层XML不支持它。也许您可以利用库的特定实现来获得您想要的订单,但是不能保证它将永远以这种方式工作。
以这种方式思考,属性是元素的描述性项目。如果你又瘦又瘦,那么你的属性真的没有自然的顺序。它不像高个子必须在瘦之前来,或者在瘦之前瘦。同样地,一辆热的,快速的,红色的汽车与其他汽车的区别在于热,快,红而不是快速,红色和热。
在实践方面,您可以期望的最好的方法是从节点中删除所有属性,并找出底层代码的工作原理。按照正确的顺序添加所有属性可能会获得您在特定情况下的特定库版本所需的订单。不理想,但如果它对你来说很重要,任何解决方案都比没有好。