Bagaimana cara memuat org.w3c.dom.Document dari XML dalam sebuah string?

103

Saya memiliki dokumen XML lengkap dalam sebuah string dan menginginkan sebuah Documentobjek. Google menemukan semua jenis sampah. Apa solusi paling sederhana? (Di Java 1.5)

Solusi Terima kasih kepada Matt McMinn , saya telah menetapkan penerapan ini. Ini memiliki tingkat fleksibilitas masukan dan perincian pengecualian yang tepat untuk saya. (Senang mengetahui apakah kesalahan tersebut berasal dari format XML yang salah - SAXException- atau hanya IO yang buruk - 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
sumber
Alangkah baiknya jika Anda bisa memperbaiki solusinya. Menggunakan String.getByptes dan InputStream menimbulkan masalah i18n. Salah satu teman saya mendapat kode dari sini seperti apa yang salah. Beruntung findbugs mendeteksi masalah ini. Solusi yang benar disediakan oleh erickson adalah dengan menggunakan InputSource.
Kenneth Xu

Jawaban:

80

Ini berfungsi untuk saya di Java 1.5 - Saya menghapus pengecualian khusus untuk keterbacaan.

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
sumber
28
Seperti dicatat dalam jawaban sylvarking, kode ini digunakan getBytes()tanpa pertimbangan untuk pengkodean.
McDowell
2
maksudmu jawaban erickson? atau mungkin dia mengganti nama profilnya?
rogerdpack
1
Bukankah seharusnya ada casting return (Document) builder.parse(new ByteArrayInputStream(xml.getBytes()));??
InfantPro'Aravind '
150

Siapa disana!

Ada masalah yang berpotensi serius dengan kode ini, karena kode ini mengabaikan pengkodean karakter yang ditentukan dalam String(yang merupakan UTF-8 secara default). Saat Anda memanggil String.getBytes()platform, pengkodean default digunakan untuk mengenkode karakter Unicode menjadi byte. Jadi, pengurai mungkin berpikir itu mendapatkan data UTF-8 padahal sebenarnya itu mendapatkan EBCDIC atau sesuatu… tidak bagus!

Sebagai gantinya, gunakan metode parse yang menggunakan InputSource, yang dapat dibuat dengan Reader, seperti ini:

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

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

Ini mungkin tidak tampak seperti masalah besar, tetapi ketidaktahuan tentang masalah pengkodean karakter menyebabkan pembusukan kode berbahaya seperti y2k.

erickson
sumber
3
Sangat sederhana tetapi solusi yang sangat sulit dipahami di Google. Terima kasih +1
pat8719
6
Saya sekarang menyadari bahwa saya seharusnya tidak hanya menyalin-dan-menempel jawaban yang diterima tetapi membaca secara menyeluruh.
Vitaly Sazanovich
1
Hebat! Menyelamatkan hidup kita di JDK8 dengan file setup berikut.encoding = ISO-8859_1, javax.servlet.request.encoding = UTF-8 PS jawaban yang diberi label benar tidak berhasil untuk kita
kosta5
9

Baru saja mengalami masalah serupa, kecuali saya membutuhkan NodeList dan bukan Dokumen, inilah yang saya dapatkan. Ini sebagian besar solusi yang sama seperti sebelumnya, ditambah untuk mendapatkan elemen root sebagai NodeList dan menggunakan saran erickson untuk menggunakan InputSource sebagai gantinya untuk masalah pengkodean karakter.

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.dll
sumber
1

Untuk memanipulasi XML di Java, saya selalu cenderung menggunakan Transformer API:

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
sumber