web-dev-qa-db-fra.com

Définition des espaces de noms et des préfixes dans un document DOM Java DOM

J'essaie de convertir un ResultSet en un fichier XML. J'ai d'abord utilisé cet exemple pour la sérialisation.

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

Après avoir fait ce travail, j'ai essayé de valider mon fichier XML, il y a eu quelques avertissements. Une sur le fait de ne pas avoir de doctype. J'ai donc essayé une autre façon de mettre cela en œuvre. Je suis tombé sur la classe Transformer. Cette classe me permet de définir l'encodage, le doctype, etc.

L'implémentation précédente prend en charge la correction automatique de l'espace de noms. Ce qui suit ne fonctionne pas.

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

Pendant que je testais l'implémentation précédente, j'ai eu une TransformationException: l'espace de noms pour le préfixe 'xsi' n'a pas été déclaré. Comme vous pouvez le voir, j'ai essayé d'ajouter un espace de noms avec le préfixe xsi à l'élément racine de mon document. Après avoir testé cela, j'ai toujours eu l'exception. Quelle est la bonne façon de définir des espaces de noms et leurs préfixes?

Edit: Un autre problème que j'ai avec la première implémentation est que le dernier élément du document XML n'a pas les trois dernières balises de fermeture.

12
TrashCan

Vous n'avez pas ajouté la déclaration d'espace de noms dans le nœud racine; vous venez de déclarer le nœud racine dans l'espace de noms, deux choses entièrement différentes. Lors de la construction d'un DOM, vous devez référencer l'espace de noms sur chaque nœud pertinent. En d'autres termes, lorsque vous ajoutez votre attribut, vous devez définir son espace de noms (par exemple, setAttributeNS).

Remarque: Bien que les espaces de noms XML ressemblent à des URL, ils ne le sont vraiment pas. Il n'est pas nécessaire d'utiliser la classe URL ici.

7
jtahlborn

La façon correcte de définir un nœud sur un document namespaceAware est d'utiliser:

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

Vous pouvez donc remplacer "PREFIX" par votre propre préfixe personnalisé et remplacer "aNodeName" par le nom de votre nœud. Pour éviter que chaque nœud ait sa propre déclaration d'espace de noms, vous pouvez définir les espaces de noms en tant qu'attributs sur votre nœud racine comme suit:

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

Assurez-vous de définir:

documentBuilderFactory.setNamespaceAware(true)

Sinon, vous n'avez pas namespaceAwareness.

32
Hans

Veuillez noter que la définition d'un préfixe xmlns avec setAttribute est incorrecte. Si vous voulez par exemple signer votre DOM, vous devez utiliser setAttributeNS: element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

9
jokster