¿Cómo cargo un documento org.w3c.dom.Document desde XML en una cadena?

103

Tengo un documento XML completo en una cadena y me gustaría un Documentobjeto. Google muestra todo tipo de basura. Cual es la solucion mas simple? (En Java 1.5)

Solución Gracias a Matt McMinn , me he decidido por esta implementación. Tiene el nivel adecuado de flexibilidad de entrada y granularidad de excepciones para mí. (Es bueno saber si el error provino de un XML con formato incorrecto SAXException, o simplemente de una E / S incorrecta 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
fuente
Sería bueno si pudiera corregir la solución. El uso de String.getByptes y InputStream imponen problemas de i18n. Uno de mis amigos obtuvo el código de aquí, lo cual es incorrecto. Suerte que findbugs detectó el problema. La solución correcta proporcionada por erickson es utilizar InputSource.
Kenneth Xu

Respuestas:

80

Esto funciona para mí en Java 1.5: eliminé las excepciones específicas para mejorar la legibilidad.

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
fuente
28
Como se señaló en la respuesta de sylvarking, este código se usa getBytes()sin tener en cuenta la codificación.
McDowell
2
¿Te refieres a la respuesta de Erickson? ¿O tal vez cambió el nombre de su perfil?
rogerdpack
1
¿No debería haber casting return (Document) builder.parse(new ByteArrayInputStream(xml.getBytes()));?
InfantPro'Aravind '16 de
150

¡Vaya!

Hay un problema potencialmente serio con este código, porque ignora la codificación de caracteres especificada en String(que es UTF-8 por defecto). Cuando llama a String.getBytes()la plataforma, la codificación predeterminada se utiliza para codificar caracteres Unicode en bytes. Entonces, el analizador puede pensar que está obteniendo datos UTF-8 cuando en realidad está obteniendo EBCDIC o algo ... ¡no es bonito!

En su lugar, use el método de análisis que toma un InputSource, que se puede construir con un Reader, como este:

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

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

Puede que no parezca gran cosa, pero la ignorancia de los problemas de codificación de caracteres conduce a una corrupción de código insidiosa similar a y2k.

erickson
fuente
3
Una solución tan simple pero tan elusiva en Google. Gracias +1
pat8719
6
Ahora me doy cuenta de que no debería simplemente copiar y pegar la respuesta aceptada, sino leerla.
Vitaly Sazanovich
1
¡Increíble! Salvó nuestras vidas en JDK8 con el siguiente archivo de configuración.encoding = ISO-8859_1, javax.servlet.request.encoding = UTF-8 PD: la respuesta etiquetada como correcta no funcionó para nosotros
kosta5
9

Acabo de tener un problema similar, excepto que necesitaba una NodeList y no un Documento, esto es lo que se me ocurrió. Es principalmente la misma solución que antes, aumentada para obtener el elemento raíz como NodeList y usar la sugerencia de Erickson de usar InputSource en lugar de problemas de codificación de caracteres.

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
fuente
1

Para manipular XML en Java, siempre tiendo a usar la API de 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
fuente