2011-12-12 32 views
5

Tôi tạo chuỗi XML ngay lập tức (KHÔNG đọc từ tệp). Sau đó, tôi sử dụng Cocoon 3 để chuyển đổi nó qua FOP sang PDF. Một nơi nào đó ở giữa Xerces chạy. Khi tôi sử dụng công cụ mã hóa mọi thứ hoạt động. Ngay sau khi tôi đặt một Umlaut Đức vào cơ sở dữ liệu và làm giàu xml của tôi với dữ liệu mà tôi nhận được:Tôi có UTF-8 - nhưng vẫn nhận được "byte không hợp lệ 1 của chuỗi UTF-8 1 byte"

Caused by: org.apache.cocoon.pipeline.ProcessingException: Can't parse the XML string. 
at org.apache.cocoon.sax.component.XMLGenerator$StringGenerator.execute(XMLGenerator.java:326) 
at org.apache.cocoon.sax.component.XMLGenerator.execute(XMLGenerator.java:104) 
at org.apache.cocoon.pipeline.AbstractPipeline.invokeStarter(AbstractPipeline.java:146) 
at org.apache.cocoon.pipeline.AbstractPipeline.execute(AbstractPipeline.java:76) 
at de.grobmeier.tab.webapp.modules.documents.InvoicePipeline.generateInvoice(InvoicePipeline.java:74) 
... 87 more 

Caused by: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence. 
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:684) 
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:554) 

Tôi đã sau đó sửa lỗi ứng dụng của tôi và phát hiện ra, tôi "A" (mà đi kèm Frome cơ sở dữ liệu) có giá trị byte của 196, là C4 trong hex. Đây là những gì tôi đã mong đợi theo điều này: http://www.utf8-zeichentabelle.de/

Tôi không biết tại sao mã của tôi không thành công.

Tôi đã sau đó cố gắng thêm một BOM bằng tay, như thế:

byte[] bom = new byte[3]; 
bom[0] = (byte) 0xEF; 
bom[1] = (byte) 0xBB; 
bom[2] = (byte) 0xBF; 
String myString = new String(bom) + inputString; 

Tôi biết điều này là không chính xác tốt, nhưng tôi đã thử nó - tất nhiên nó thất bại. Tôi đã cố thêm tiêu đề xml vào trước:

<?xml version="1.0" encoding="UTF-8"?> 

cũng không thành công. Sau đó, tôi kết hợp nó. Thất bại.

Sau khi tất cả tôi đã cố gắng một cái gì đó như thế:

xmlInput = new String(xmlInput.getBytes("UTF8"), "UTF8"); 

Đó là không làm gì trong thực tế, bởi vì nó đã là UTF-8. Vẫn thất bại.

Vì vậy ... bất kỳ ý tưởng nào tôi đang làm sai và những gì Xerces mong đợi từ tôi?

Cảm ơn Christian

+0

Đồng ý, nhưng nó không giúp tôi. Vì chuỗi có vấn đề xuất phát từ cơ sở dữ liệu được tạo từ lớp ORM của tôi. Ngoài ra, nó có 0xC4 mà nên làm tốt, phải không? – Christian

+0

Tôi sử dụng MySQL, bảng và cột được mã hóa bằng utf8_general_ci. Tôi đã thêm useUnicode = true & characterEncoding = utf8 vào kết nối jdbc của tôi. – Christian

+0

Nó có thể không phải là một ý tưởng tốt để xác định các tham số trên kết nối JDBC khi bạn xảy ra để kết nối với một DB với một mã hóa khác nhau - chỉ sử dụng nó khi tự động phát hiện sai. Bạn sử dụng gì để ghi dữ liệu và đây có phải là cột BLOB hoặc VARCHAR không? – JBert

Trả lời

12

Nếu cơ sở dữ liệu của bạn chỉ chứa một byte đơn (với giá trị 0xC4) thì bạn không sử dụng mã hóa UTF-8.

Ký tự "LATIN CAPITAL LETTER A WITH DIAERESIS" có giá trị mã điểm U + 00C4, nhưng UTF-8 không thể mã hóa trong một byte đơn. Nếu bạn kiểm tra cột thứ ba "UTF-8 (hex.)" Trên UTF8-zeichentabelle.de bạn sẽ thấy rằng mã hóa UTF-8 là 0xC3 84 (hai byte).

Vui lòng đọc bài viết của Joel "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)" để biết thêm thông tin.


EDIT: Christian tìm thấy câu trả lời; hóa ra đó là một vấn đề trong thành phần Cocoon 3 SAX (tôi đoán đó là phiên bản alpha 3). Nó chỉ ra rằng nếu bạn vượt qua một XML như là một String vào lớp XMLGenerator, một cái gì đó sẽ đi sai trong quá trình phân tích cú pháp SAX gây ra mớ hỗn độn này.

tôi looked up the code để tìm ra vấn đề thực tế trong Cocoon-Stax:

if (XMLGenerator.this.logger.isDebugEnabled()) { 
    XMLGenerator.this.logger.debug("Using a string to produce SAX events."); 
} 
XMLUtils.toSax(new ByteArrayInputStream(this.xmlString.getBytes()), XMLGenerator.this.getSAXConsumer(); 

Như bạn có thể thấy, các cuộc gọi getBytes() sẽ tạo ra một mảng Byte với mã hóa mặc định của JRE mà sau đó sẽ thất bại trong việc phân tích. Điều này là do XML tự khai báo là UTF-8, trong khi dữ liệu hiện đang ở dạng byte và có khả năng sử dụng bảng mã Windows của bạn.

Là một workaround, người ta có thể sử dụng như sau:

new org.apache.cocoon.sax.component.XMLGenerator(xmlInput.getBytes("UTF-8"), 
     "UTF-8"); 

này sẽ kích hoạt các hành động nội bộ bên phải (như Christian phát hiện ra bằng cách thử nghiệm với các API).

Tôi đã opened an issue trong trình theo dõi lỗi của Apache.

CHỈNH SỬA 2: Sự cố được khắc phục và sẽ được đưa vào bản phát hành sắp tới.

+0

Cách để đi xa hơn và xa hơn nữa! – Pops

2

Các C4 bạn nhìn thấy trên trang đó đề cập đến điểm mã unicode, U+00C4. Chuỗi byte được sử dụng để biểu diễn một điểm mã trong UTF-8 là NOT "\xC4". Những gì bạn muốn là những gì trong cột UTF-8 (hex.), Cụ thể là "\xC3\x84".

Do đó, dữ liệu của bạn không có trong UTF-8.

Bạn có thể đọc về cách dữ liệu được mã hóa theo UTF-8 here.

0

Tôi đang chạy Windows 7 với TextPad làm trình soạn thảo văn bản để tạo thủ công tệp dữ liệu xml. Tôi đã nhận được MalformedByteSequenceException. Thông số kỹ thuật của tôi trong tệp xml là UTF-8. Sau khi poking xung quanh, tôi thấy rằng biên tập viên của tôi đã có một công cụ "Tools ... Convert to DOS". Tôi đã làm điều đó, lưu lại tệp và ngoại lệ đã biến mất và mã của tôi chạy tốt.

Sau đó, tôi đã xem mã hóa mặc định cho loại tệp đó trong trình chỉnh sửa của mình. Đó là ASCII, mặc dù khi tôi thay đổi tham số mã hóa xml thành ASCII, tôi nhận được một khác nhau MalformedByteSequenceException.

Vì vậy, trên hệ thống Windows, bạn có thể thử giữ mã hóa xml thành UTF-8, nhưng lưu tệp được mã hóa DOS. Tôi không tìm hiểu thêm về lý do tại sao nó hoạt động.

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