2012-05-14 3 views
6

Я пытаюсь преобразовать ResultSet в файл XML. Я впервые использовал этот пример для сериализации.Установка пространств имен и префиксов в документе DOM Java

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

После того как я сделал эту работу, я попытался проверить мой 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 не содержит последних трех закрывающих тегов.

ответ

4

Вы не добавили декларацию пространства имен в корневой узел; вы просто объявили корневой узел в пространстве имен, две совершенно разные вещи. При создании DOM вам нужно ссылаться на пространство имен на каждом соответствующем узле. Другими словами, когда вы добавляете свой атрибут, вам нужно определить его пространство имен (например, setAttributeNS).

Замечание: Хотя пространства имен XML выглядят как URL-адреса, они на самом деле не являются. Здесь нет необходимости использовать класс URL.

+1

Спасибо, сейчас работает. Сегодня узнал что-то новое, как и каждый день. – TrashCan

27

Правильный способ установить узел в документе namespaceAware является использование:

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

Таким образом, вы можете заменить «приставкой» с собственным пользовательским префиксом и заменить «aNodeName» с именем вашего узла. Для того, чтобы избежать того, чтобы каждый узел имеет свою собственную декларацию пространства имен можно определить пространство имен в качестве атрибутов на корневой узел так:

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

Пожалуйста, убедитесь, что установили:

documentBuilderFactory.setNamespaceAware(true) 

В противном случае у вас нет namespaceAwareness.

+0

+1, хотя мне не нужно было вызывать 'setNamespaceAware'. Документация для этой функции предполагает, что она связана с разбором. –

+1

Обратите внимание, что существует метод setPrefix (prefix); ', который позволяет динамически устанавливать префикс. –

5

Обратите внимание, что установка префикса xmlns с помощью setAttribute неверна. Если вы когда-либо захотите, например, подписать свой DOM, вы должны использовать setAttributeNS: element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

+0

Любой конкретный пример, в котором вы заметили разницу? Когда я преобразовываю DOM в файл, использование setAttribute или setAttributeNS дает тот же результат. Вы заметили некоторую разницу во времени выполнения DOM, которое исправлено? – JBert

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