2012-05-14 11 views
6

Tôi đang cố chuyển đổi ResultSet thành tệp XML. Lần đầu tiên tôi sử dụng ví dụ này cho việc tuần tự hóa.Đặt không gian tên và tiền tố trong tài liệu Java DOM

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

Sau khi tôi thực hiện công việc này, tôi đã thử xác thực tệp XML của mình, có một vài cảnh báo. Một về việc không có loại tài liệu. Vì vậy, tôi đã thử một cách khác để thực hiện điều này. Tôi đã đi qua lớp Transformer. Lớp này cho phép tôi đặt mã hóa, loại tài liệu, v.v.

Triển khai trước đó hỗ trợ sửa lỗi không gian tên tự động. Sau đây không.

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

Trong khi tôi đang thử nghiệm triển khai trước đó, tôi nhận được một ngoại lệ TransformationException: Không gian tên cho tiền tố 'xsi' chưa được khai báo. Như bạn thấy, tôi đã cố gắng thêm một không gian tên với tiền tố xsi vào phần tử gốc của tài liệu của tôi. Sau khi thử nghiệm điều này tôi vẫn có ngoại lệ. Cách chính xác để đặt không gian tên và tiền tố của chúng là gì?

Chỉnh sửa: Một vấn đề khác mà tôi có với triển khai đầu tiên là phần tử cuối cùng trong tài liệu XML không có ba thẻ đóng cuối cùng.

Trả lời

4

Bạn chưa thêm khai báo không gian tên trong nút gốc; bạn vừa khai báo nút gốc trong không gian tên, hai thứ hoàn toàn khác nhau. Khi xây dựng một DOM, bạn cần tham chiếu không gian tên trên mọi Nút liên quan. Nói cách khác, khi bạn thêm thuộc tính của mình, bạn cần phải xác định không gian tên của nó (ví dụ: setAttributeNS).

Lưu ý phụ: Mặc dù các không gian tên XML giống như các URL nhưng chúng thực sự không phải. Không cần sử dụng lớp URL ở đây.

+1

Xin cảm ơn, nó hiện đang hoạt động. Học một cái gì đó mới ngày hôm nay, giống như mỗi ngày. – TrashCan

27

Cách đúng để thiết lập một nút trên một tài liệu namespaceAware là bằng cách sử dụng:

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

Vì vậy, bạn có thể thay thế "PREFIX" với tiền tố tùy chỉnh của riêng bạn và thay thế "aNodeName" với tên của nút của bạn. Để tránh việc mỗi nút có khai gian tên riêng của mình, bạn có thể xác định không gian tên như là thuộc tính trên nút gốc của bạn như vậy:

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

Hãy chắc chắn để thiết lập:

documentBuilderFactory.setNamespaceAware(true) 

Nếu bạn không có namespaceAwareness.

+0

+1, mặc dù tôi không cần phải gọi 'setNamespaceAware'. Tài liệu cho hàm đó cho thấy nó liên quan đến phân tích cú pháp. –

+1

Lưu ý rằng có một phương thức 'setPrefix (prefix);' cho phép tự động đặt tiền tố. –

5

Xin lưu ý rằng việc đặt tiền tố xmlns với setAttribute là sai. Nếu bạn muốn ký tên vào DOM của mình, bạn phải sử dụng setAttributeNS: element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

+0

Bất kỳ ví dụ cụ thể nào mà bạn nhận thấy sự khác biệt? Khi tôi chuyển đổi một DOM thành một tệp, sử dụng setAttribute hoặc setAttributeNS cho cùng một đầu ra. Bạn có nhận thấy một số khác biệt trong DOM thời gian chạy mà biến đổi sửa chữa không? – JBert