Для создания документа JDOM JDOM требует использования реализации DOM с поддержкой пространства имен.
Я поставил вместе следующий код, чтобы проиллюстрировать этот момент:
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jdom2.Document;
import org.jdom2.input.DOMBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
public class DOMvsJDOM {
private static org.w3c.dom.Document buildDOM(String xml) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml);
InputSource is = new InputSource(sr);
return db.parse(is);
}
public static void printDocument(org.w3c.dom.Document doc, OutputStream out) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
}
private static void parseUsingJDOM(org.w3c.dom.Document doc) throws Exception {
// Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("testxml.xml"), "UTF8"));
DOMBuilder builder = new DOMBuilder();
Document jdoc = builder.build(doc);
XMLOutputter fmt = new XMLOutputter();
fmt.setFormat(Format.getPrettyFormat());
fmt.output(jdoc, System.out);
}
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
org.w3c.dom.Document doc = dbFactory.newDocumentBuilder().newDocument();
doc.setXmlVersion("1.0");
Element root = doc.createElement("Document");
root.setAttribute("xmlns", "urn:iso:foo");
root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd");
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
doc.appendChild(root);
printDocument(doc, System.out);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
printDocument(doc, baos);
System.out.println("JDOM Using captured");
parseUsingJDOM(doc);
String xml = new String(baos.toByteArray());
doc = buildDOM(xml);
System.out.println("JDOM Using parsed");
parseUsingJDOM(doc);
}
}
Обратите внимание, что -тиено- код делает, это построить DOM вручную, вывести его, строить JDOM из DOM, вывод, что, то выведите DOM в виде строки, повторно проанализируйте String как DOM, а затем создайте JDOM из повторно обработанного XML.
Это выход (я поставил новую строку на выходе вручную, чтобы фактическая строка DOM имеет декларацию XML на своей собственной линии):
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:foo bar.xsd"/>
JDOM Using captured
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="urn:iso:foo bar.xsd" />
JDOM Using parsed
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:foo bar.xsd" />
Суть в том, что DOM, отображающий его выход не является технически «пространством имен» и, следовательно, не удовлетворяет ожиданиям JDOM 2.0.
Теперь, используйте следующий код, чтобы установить атрибуты:
root.setAttribute("xmlns", "urn:iso:foo");
root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd");
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
Если вы использовали пространство имен-зависимые версии вместо:
root.setAttribute("xmlns", "urn:iso:foo");
root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
root.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", "urn:iso:foo bar.xsd");
doc.appendChild(root);
тогда JDOM получит это право ,
Именно поэтому JDOM работает в версии с синтаксическим строком выше, потому что анализ выполняется в стиле имен.
Итак, у JDOM есть требование, чтобы при обработке содержимого DOM содержимое DOM находилось в формате XML, поддерживающем пространство имен. Вот почему мои тесты все работают, потому что мой контент DOM - это все пространство имен.
К сожалению, это не решит проблему, которая у вас есть ... она просто объясняет это.
JDOM2 должен быть совместимым с JDOM 1.x в этом случае, и проблема несовместимости является проблемой. JDOM2 делает «правильную» вещь, но она также должна, вероятно, делать и «неправильную» вещь, и настаивать на поиске пространства имен для тех атрибутов, которые определены в DOM, которые также не объявлены должным образом.
Я создал вопрос 138, чтобы отслеживать это: https://github.com/hunterhacker/jdom/issues/138
Вы неудобное сочетание DOM и JDOM содержания здесь .... Обратите внимание, что 'root' является DOM, а не элемент JDOM, и JDOM не будет позволяют устанавливать атрибуты с этими незаконными именами. Почему вы так поступаете, а не просто создаете документ как документ JDOM напрямую? – rolfl
Никакой особой причины я не думаю. Просто куча устаревшего кода. Согласно некоторым комментариям в коде, похоже, что JDOM используется только для форматирования XML несколькими способами. С JDOM 1.0 он даже работал хорошо. Спасибо за подсказку! – Roland
Я смотрю на ваш случай использования, возможно, вы обнаружили ошибку в DOMBuilder, не занимающую пространство имен атрибутов. Скорее всего, мне придется дождаться, когда я закончу работу сегодня, прежде чем проверять это дальше. У вас есть несколько необычных вещей. Просто говорю. – rolfl