2014-11-04 1 views
1

Я пытался обновить JDOM 1.0 до JDOM2. В JDOM 1.0 этот код:Как предотвратить использование XMLOutputter в JDOM2 от сокращения имени атрибута (namespace-part)?

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

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

производит этот 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" /> 

Когда я использую JDOM2, атрибут xsi:schemaLocation изменяется на schemaLocation (и XML выглядит следующим образом):

<?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" /> 

Есть ли способ сохранить xsi: в JDOM2? Без него система, обрабатывающая сгенерированный XML, не может ее прочитать (не под моим контролем). Не уверен, соответствует ли тот вопрос this.

+1

Вы неудобное сочетание DOM и JDOM содержания здесь .... Обратите внимание, что 'root' является DOM, а не элемент JDOM, и JDOM не будет позволяют устанавливать атрибуты с этими незаконными именами. Почему вы так поступаете, а не просто создаете документ как документ JDOM напрямую? – rolfl

+0

Никакой особой причины я не думаю. Просто куча устаревшего кода. Согласно некоторым комментариям в коде, похоже, что JDOM используется только для форматирования XML несколькими способами. С JDOM 1.0 он даже работал хорошо. Спасибо за подсказку! – Roland

+0

Я смотрю на ваш случай использования, возможно, вы обнаружили ошибку в DOMBuilder, не занимающую пространство имен атрибутов. Скорее всего, мне придется дождаться, когда я закончу работу сегодня, прежде чем проверять это дальше. У вас есть несколько необычных вещей. Просто говорю. – rolfl

ответ

2

Для создания документа 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

0

Согласно намеком rolfl, один из способов не перепутать DOM и JDOM контента и использовать только DOM для создания и сохранения XML в виде файла:

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
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); 

TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
transformerFactory.setAttribute("indent-number", 2); 
Transformer transformer = transformerFactory.newTransformer(); 
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
DOMSource source = new DOMSource(doc); 
StreamResult xmlfile = new StreamResult(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("testxml.xml"), "UTF8"))); 
transformer.transform(source, xmlfile); 

Но это не является полностью действительным ответ, поскольку вопрос заключается в том, как использовать JDOM2 для выполнения задачи.

+0

Просто укажите, что проблема технически является непоследовательным использованием пространств имен в DOM, и что 'root.setAttribute (" xsi: schemaLocation "," urn: iso: foo bar.xsd ");' действительно должен быть 'root .setAttributeNS («http://www.w3.org/2001/XMLSchema-instance», «xsi: schemaLocation», «urn: iso: foo bar.xsd»); и т. д. – rolfl

Смежные вопросы