2009-01-14 18 views
21

Tôi đang sử dụng JAXP để tạo và phân tích cú pháp một tài liệu XML mà từ đó một số trường được tải từ cơ sở dữ liệu.Sản xuất XML hợp lệ với mã hóa Java và UTF-8

Mã để serialize XML:

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
Document doc = builder.newDocument(); 
Element root = doc.createElement("test"); 
root.setAttribute("version", text); 
doc.appendChild(root); 

DOMSource domSource = new DOMSource(doc); 
TransformerFactory tFactory = TransformerFactory.newInstance(); 

FileWriter out = new FileWriter("test.xml"); 
Transformer transformer = tFactory.newTransformer(); 
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
transformer.transform(domSource, new StreamResult(out)); 

Mã để phân tích cú pháp XML:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
factory.setNamespaceAware(true); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document doc = builder.parse("test.xml"); 

Và tôi bắt gặp ngoại lệ sau đây:

[Fatal Error] test.xml:1:4: Invalid byte 1 of 1-byte UTF-8 sequence. 
Exception in thread "main" org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence. 
    at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) 
    at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source) 
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source) 
    at com.test.Test.xml(Test.java:27) 
    at com.test.Test.main(Test.java:55) 

Văn bản Chuỗi bao gồm u- umlaut và o-umlaut (mã ký tự 0xFC và 0xF6). Đây là những nhân vật gây ra lỗi. Khi tôi thoát khỏi chuỗi bản thân mình để sử dụng & #xFC; và & # xF6; thì vấn đề sẽ biến mất. Các thực thể khác được tự động mã hóa khi tôi viết ra XML.

Làm cách nào để đầu ra của tôi được viết/đọc đúng cách mà không tự thay thế các ký tự này?

(Tôi đã đọc các câu hỏi sau đây đã:

How to encode characters from Oracle to XML?

Repairing wrong encoding in XML files)

Trả lời

31

Sử dụng một FileOutputStream chứ không phải là một FileWriter.

Sau này áp dụng mã hóa riêng, gần như chắc chắn không phải là UTF-8 (tùy thuộc vào nền tảng của bạn, có thể là Windows-1252 hoặc IS-8859-1).

Chỉnh sửa (bây giờ mà tôi có một thời gian):

Một tài liệu XML mà không có một mở đầu được phép được mã hóa theo UTF-8 hoặc UTF-16. Với phần mở đầu, nó được phép chỉ định mã hóa của nó (phần mở đầu có thể chỉ chứa các ký tự US-ASCII, vì vậy phần mở đầu luôn có thể đọc được).

Trình đọc tương tác với các ký tự; nó sẽ giải mã luồng byte của InputStream bên dưới. Kết quả là, khi bạn chuyển một Reader vào trình phân tích cú pháp, bạn đang nói rằng bạn đã xử lý mã hóa, do đó trình phân tích cú pháp sẽ bỏ qua phần mở đầu. Khi bạn truyền một InputStream (đọc byte), nó không đưa ra giả định này, và sẽ xem xét phần mở đầu để xác định mã hóa - hoặc mặc định là UTF-8/UTF-16 nếu nó không có.

Tôi chưa bao giờ thử đọc tệp được mã hóa bằng UTF-16. Tôi nghi ngờ rằng trình phân tích cú pháp sẽ tìm kiếm một Byte Order Mark (BOM) là 2 byte đầu tiên của tệp.

+0

Đẹp và dễ dàng, tôi đã nghĩ đến việc thay đổi điều này nhưng đã loại bỏ ý tưởng vì tôi không thấy cách xác định mã hóa trong hàm tạo. Nó hoạt động tốt, cảm ơn. –

+0

Tôi tự bắn mình vào chân với FileWriter một lần .... +1 –

+0

Câu trả lời hay - Tôi sẽ luôn tìm kiếm Gotchas ẩn trong FileWriter từ bây giờ! –

5

Vâng, chắc chắn 0xFC0xF6 không hợp lệ UTF-8 ký tự. Những điều này cần phải được đưa vào chuỗi hai byte: 0x3CBC0x3CB6.

Rất có thể sự cố xảy ra với nguồn gốc của các ký tự được xác định là UTF-8 khi không.

+0

Thay đổi FileWriter thành một FileOutputStream đã thực sự dẫn đến các ký tự này được mã hóa với hai chuỗi byte: 0xC3BC và 0xC3B6. –

Các vấn đề liên quan