2012-05-14 12 views
6

Ich versuche, ein ResultSet in eine XML-Datei zu konvertieren. Ich habe dieses Beispiel zuerst für die Serialisierung verwendet.Festlegen von Namespaces und Präfixen in einem Java-DOM-Dokument

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

Nachdem ich diese Arbeit gemacht, habe ich versucht, meine XML-Datei zu überprüfen, gibt es ein paar Warnungen waren. Eine über keinen Doctype. Also habe ich einen anderen Weg versucht, dies zu implementieren. Ich bin auf die Transformer-Klasse gestoßen. Mit dieser Klasse kann ich die Codierung, den Doctyp usw. festlegen.

Die vorherige Implementierung unterstützt die automatische Namensraumkorrektur. Das Folgende nicht.

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

Während ich die vorherige Implementierung ich eine TransformationException bekam Prüfung wurde: Namensraum für Vorsilbe ‚xsi‘ erklärt worden ist. Wie Sie sehen können, habe ich versucht, dem Wurzelelement meines Dokuments einen Namespace mit dem Präfix xsi hinzuzufügen. Nach dem Testen habe ich immer noch die Ausnahme. Wie werden Namespaces und ihre Präfixe richtig festgelegt?

Bearbeiten: Ein weiteres Problem, das ich mit der ersten Implementierung habe, ist, dass das letzte Element im XML-Dokument nicht die letzten drei schließenden Tags hat.

Antwort

4

Sie haben die Namespace-Deklaration nicht im Stammknoten hinzugefügt. Sie haben gerade den Wurzelknoten im Namespace deklariert, zwei völlig verschiedene Dinge. Wenn Sie ein DOM erstellen, müssen Sie den Namespace auf jedem relevanten Knoten referenzieren. Mit anderen Worten, wenn Sie Ihr Attribut hinzufügen, müssen Sie seinen Namespace definieren (z. B. setAttributeNS).

Seitliche Anmerkung: Obwohl XML-Namespaces wie URLs aussehen, sind sie es wirklich nicht. Sie müssen die URL-Klasse hier nicht verwenden.

+1

Danke, es funktioniert jetzt. Heute, wie jeden Tag, etwas Neues gelernt. – TrashCan

27

Der richtige Weg, um einen Knoten auf einem namespaceAware Dokument zu setzen, ist durch die Verwendung:

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

So können Sie „PREFIX“ mit Ihrem eigenen Präfix ersetzen und „aNodeName“ mit dem Namen Ihres Knotens ersetzen. Um zu vermeiden, jeder Knoten mit einem eigenen Namensraum-Deklaration aufweisen, können Sie die Namespaces als Attribute auf dem Wurzelknoten definieren wie folgt:

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

Bitte achten Sie darauf, ein:

documentBuilderFactory.setNamespaceAware(true) 

Ansonsten haben Sie nicht NamespaceAwareness.

+0

+1, obwohl ich 'setNamespaceAware' nicht aufrufen musste. Die Dokumentation für diese Funktion weist darauf hin, dass es sich um das Parsen handelt. –

+1

Beachten Sie, dass es eine 'setPrefix (Präfix);' -Methode gibt, mit der das Präfix dynamisch gesetzt werden kann. –

5

Bitte beachten Sie, dass das Setzen eines xmlns-Präfixes mit setAttribute falsch ist. Wenn Sie zB Ihr DOM signieren möchten, müssen Sie setAttributeNS verwenden: element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

+0

Jedes spezifische Beispiel, in dem Sie einen Unterschied bemerkt haben? Wenn ich ein DOM in eine Datei transformiere, gibt die Verwendung von setAttribute oder setAttributeNS dieselbe Ausgabe. Haben Sie einen Unterschied im Laufzeit-DOM bemerkt, das die Transformation behebt? – JBert