Comment charger un org.w3c.dom.Document à partir de XML dans une chaîne?

103

J'ai un document XML complet dans une chaîne et je voudrais un Documentobjet. Google révèle toutes sortes de déchets. Quelle est la solution la plus simple? (Dans Java 1.5)

Solution Grâce à Matt McMinn , j'ai choisi cette implémentation. Il a le bon niveau de flexibilité d'entrée et de granularité d'exception pour moi. (Il est bon de savoir si l'erreur provient d'un XML malformé SAXException- ou simplement d'une mauvaise IO - IOException.)

public static org.w3c.dom.Document loadXMLFrom(String xml)
    throws org.xml.sax.SAXException, java.io.IOException {
    return loadXMLFrom(new java.io.ByteArrayInputStream(xml.getBytes()));
}

public static org.w3c.dom.Document loadXMLFrom(java.io.InputStream is) 
    throws org.xml.sax.SAXException, java.io.IOException {
    javax.xml.parsers.DocumentBuilderFactory factory =
        javax.xml.parsers.DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    javax.xml.parsers.DocumentBuilder builder = null;
    try {
        builder = factory.newDocumentBuilder();
    }
    catch (javax.xml.parsers.ParserConfigurationException ex) {
    }  
    org.w3c.dom.Document doc = builder.parse(is);
    is.close();
    return doc;
}
Frank Krueger
la source
Ce serait bien si vous pouviez corriger la solution. L'utilisation de String.getByptes et InputStream pose des problèmes i18n. Un de mes amis a reçu le code d'ici tel quel, ce qui est faux. Heureusement que findbugs a détecté le problème. La bonne solution fournie par erickson est d'utiliser InputSource.
Kenneth Xu

Réponses:

80

Cela fonctionne pour moi dans Java 1.5 - j'ai supprimé des exceptions spécifiques pour la lisibilité.

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import java.io.ByteArrayInputStream;

public Document loadXMLFromString(String xml) throws Exception
{
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    factory.setNamespaceAware(true);
    DocumentBuilder builder = factory.newDocumentBuilder();

    return builder.parse(new ByteArrayInputStream(xml.getBytes()));
}
Matt McMinn
la source
28
Comme indiqué dans la réponse de sylvarking, ce code utilise getBytes()sans considération pour l'encodage.
McDowell
2
voulez-vous dire la réponse d'Erickson? ou peut-être qu'il a renommé son profil?
rogerdpack
1
ne devrait-il pas y avoir de casting return (Document) builder.parse(new ByteArrayInputStream(xml.getBytes()));??
InfantPro'Aravind '16
150

Whoa là!

Il y a un problème potentiellement sérieux avec ce code, car il ignore le codage de caractères spécifié dans le String(qui est UTF-8 par défaut). Lorsque vous appelez String.getBytes()le codage par défaut de la plateforme est utilisé pour coder les caractères Unicode en octets. Ainsi, l'analyseur peut penser qu'il obtient des données UTF-8 alors qu'en fait il obtient EBCDIC ou quelque chose de ce genre ...

Au lieu de cela, utilisez la méthode d'analyse qui prend un InputSource, qui peut être construit avec un Reader, comme ceci:

import java.io.StringReader;
import org.xml.sax.InputSource;

        return builder.parse(new InputSource(new StringReader(xml)));

Cela peut ne pas sembler un gros problème, mais l'ignorance des problèmes de codage des caractères conduit à une pourriture insidieuse du code semblable à y2k.

Erickson
la source
3
Une solution si simple mais si insaisissable sur Google. Merci +1
pat8719
6
Je réalise maintenant que je ne devrais pas simplement copier-coller la réponse acceptée, mais plutôt lire.
Vitaly Sazanovich
1
Impressionnant! Nous avons sauvé la vie sur JDK8 avec le fichier d'installation suivant.encoding = ISO-8859_1, javax.servlet.request.encoding = UTF-8 PS la réponse étiquetée comme correcte
n'a
9

J'ai juste eu un problème similaire, sauf que j'avais besoin d'une NodeList et non d'un document, voici ce que j'ai trouvé. C'est essentiellement la même solution qu'avant, augmentée pour obtenir l'élément racine en tant que NodeList et en utilisant la suggestion d'erickson d'utiliser une InputSource à la place pour les problèmes d'encodage de caractères.

private String DOC_ROOT="root";
String xml=getXmlString();
Document xmlDoc=loadXMLFrom(xml);
Element template=xmlDoc.getDocumentElement();
NodeList nodes=xmlDoc.getElementsByTagName(DOC_ROOT);

public static Document loadXMLFrom(String xml) throws Exception {
        InputSource is= new InputSource(new StringReader(xml));
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = null;
        builder = factory.newDocumentBuilder();
        Document doc = builder.parse(is);
        return doc;
    }
shsteimer
la source
1

Pour manipuler XML en Java, j'ai toujours tendance à utiliser l'API Transformer:

import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;

public static Document loadXMLFrom(String xml) throws TransformerException {
    Source source = new StreamSource(new StringReader(xml));
    DOMResult result = new DOMResult();
    TransformerFactory.newInstance().newTransformer().transform(source , result);
    return (Document) result.getNode();
}   
Xavier Dury
la source