2008-08-28 11 views
94

J'ai un document XML complet dans une chaîne et j'aimerais un objet Document. Google affiche toutes sortes de déchets. Quelle est la solution la plus simple? (En Java 1.5)Comment charger un fichier org.w3c.dom.Document à partir de XML dans une chaîne?

Solution Grâce à , je me suis installé sur cette implémentation. Il a le bon niveau de flexibilité d'entrée et la granularité d'exception pour moi. (Il est bon de savoir si l'erreur est venue de XML malformé - SAXException - ou tout simplement mauvais 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; 
} 
+0

Ce serait bien si vous pouvez corriger la solution. Utiliser String.getByptes et InputStream imposent des problèmes i18n. Un de mes amis a reçu le code d'ici, comme c'est faux. Heureusement que findbugs a détecté le problème. La solution correcte fournie par erickson est d'utiliser InputSource. –

Répondre

71

Cela fonctionne pour moi en Java 1.5 - Je retirai des exceptions spécifiques pour une meilleure 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())); 
} 
+27

Comme indiqué dans la réponse de sylvarking, ce code utilise 'getBytes()' sans tenir compte de l'encodage. – McDowell

+2

voulez-vous dire la réponse d'erickson? ou peut-être qu'il a renommé son profil? – rogerdpack

+1

ne doit pas être lancé 'return (Document) builder.parse (nouveau ByteArrayInputStream (xml.getBytes()))' '?? –

132

Whoa là-bas!

Il existe un problème potentiellement grave 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 et hellip; pas beau!

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

import java.io.StringReader; 
import org.xml.sax.InputSource; 
… 
     return builder.parse(new InputSource(new StringReader(xml))); 

Il peut ne pas sembler une grosse affaire, mais l'ignorance des questions de caractère d'encodage conduit à code insidieux pourri semblable à y2k.

+3

Si simple mais si insaisissable une solution sur Google. Merci +1 – pat8719

+5

Je me rends compte maintenant que je ne devrais pas simplement copier et coller la réponse acceptée, mais plutôt lire. –

+1

Génial! Sauvé nos vies sur JDK8 avec l'installation suivante file.encoding = ISO-8859_1, javax.servlet.request.encoding = UTF-8 PS la réponse étiqueté comme correct ne fonctionne pas pour nous – kosta5

9

Juste eu un problème similaire, sauf que j'avais besoin d'un NodeList et non d'un document, voici ce que j'ai trouvé. C'est la plupart du temps 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 un 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; 
    } 
1

Pour manipuler XML en Java, je tends toujours à 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(); 
}