2010-09-27 48 views
24

Tôi đã tìm kiếm stackoverflow về vấn đề này và đã tìm thấy một vài chủ đề, nhưng tôi cảm thấy không có câu trả lời chắc chắn cho tôi về vấn đề này.Lỗi trình phân tích cú pháp XML: thực thể không được xác định

Tôi có biểu mẫu mà người dùng gửi và giá trị của trường được lưu trữ trong tệp XML. XML được thiết lập để được mã hóa bằng UTF-8.

Hiện tại, sau đó người dùng sẽ sao chép/dán văn bản từ đâu đó và đó là khi tôi nhận được lỗi "không xác định đối tượng".

Tôi nhận ra XML chỉ hỗ trợ một số thực thể được chọn và bất kỳ thứ gì ngoài đó không được nhận dạng - do đó lỗi trình phân tích cú pháp.

Từ những gì tôi thu thập, có một vài lựa chọn Tôi đã nhìn thấy:

  1. Tôi có thể tìm và thay thế tất cả   và trao đổi chúng ra với   hoặc một không gian thực tế.
  2. Tôi có thể đặt mã được đề cập trong phần CDATA.
  3. Tôi có thể bao gồm các thực thể này trong tệp XML.

Điều tôi đang làm với tệp XML là người dùng có thể nhập nội dung vào biểu mẫu, nó được lưu trữ trong tệp XML và nội dung đó được hiển thị dưới dạng XHTML trên trang Web (được phân tích bằng SimpleXML).

Trong ba tùy chọn hoặc bất kỳ tùy chọn nào khác mà tôi không biết, cách thực sự tốt nhất để giải quyết các thực thể này là gì?

Cảm ơn, Ryan

CẬP NHẬT

Tôi muốn cảm ơn tất cả mọi người cho ý kiến ​​phản hồi tuyệt vời. Tôi thực sự đã xác định nguyên nhân gây ra lỗi của tổ chức của mình. Tất cả những gợi ý khiến tôi nhìn sâu hơn!

Một số hộp văn bản có các hộp văn bản thuần tuý cũ, nhưng văn bản của tôi đã được cải tiến bằng TinyMCE. Hóa ra, trong khi xem xét kỹ hơn, các cảnh báo PHP luôn luôn tham chiếu dữ liệu từ các văn bản nâng cao TinyMCE. Sau đó tôi nhận thấy trên một máy tính rằng tất cả các nhân vật đã được đưa ra (vì nó không thể đọc chúng), nhưng trên một MAC bạn có thể thấy các ô vuông nhỏ tham chiếu số unicode của nhân vật đó. Lý do nó xuất hiện trong hình vuông trên một MAC ở nơi đầu tiên, là vì tôi đã sử dụng utf8_encode để mã hóa dữ liệu không có trong UTF để ngăn chặn các lỗi phân tích cú pháp khác (mà bằng cách nào đó cũng liên quan đến TinyMCE).

Các giải pháp cho tất cả điều này là khá đơn giản:

tôi đã thêm dòng này entity_encoding : "utf-8" trong tinyMCE.init tôi. Bây giờ, tất cả các nhân vật đều xuất hiện theo cách mà họ nghĩ.

Tôi đoán điều duy nhất tôi không hiểu là lý do tại sao các ký tự vẫn hiển thị khi được đặt trong hộp văn bản, vì không có gì chuyển đổi thành UTF, nhưng với TinyMCE thì đó là một vấn đề.

+0

Một số bộ phận quan trọng của câu hỏi của bạn đang ẩn danh, vì họ đã phân tích cú pháp như đánh dấu. Hãy bao quanh các bit đó với các dấu ngoặc kép (''). – LarsH

+0

@LarsH: Hm, tôi không thấy gì trong nguồn câu hỏi cần. – Tomalak

+0

@Tomalak: "1. Tôi có thể tìm và thay thế tất cả * ?? * và trao đổi chúng với * ?? * hoặc một không gian thực tế." Chắc chắn với tôi như một cái gì đó đang thiếu ở đó. – LarsH

Trả lời

13

Bạn có thể phân tích cú pháp văn bản HTML và để nó thoát lại chỉ với các thực thể số tương ứng (như:   ). Trong mọi trường hợp - chỉ cần sử dụng đầu vào người dùng không được vệ sinh là một ý tưởng tồi.

Tất cả các đơn vị số được cho phép trong XML, chỉ những cái tên được biết đến từ HTML không làm việc (với ngoại lệ của &, ", <, >, ').

Hầu hết thời gian, bạn chỉ có thể viết ký tự thực tế (öö) vào tệp XML để không cần sử dụng tham chiếu thực thể. Nếu bạn đang sử dụng một API DOM để thao tác XML của bạn (và bạn nên!), Đây là đặt cược an toàn nhất của bạn.

Cuối cùng (đây là giải pháp dành cho nhà phát triển lười biếng), bạn có thể tạo tệp XML bị hỏng (nghĩa là không đúng định dạng, có lỗi thực thể) và chỉ pass it through tidy cho các bản sửa lỗi cần thiết. Điều này có thể hoạt động hoặc có thể không thành công tùy thuộc vào chỉ cách làm hỏng toàn bộ điều này. Theo kinh nghiệm của tôi, gọn gàng là khá thông minh, mặc dù, và cho phép bạn nhận được đi với rất nhiều.

+0

"Bạn có thể phân tích cú pháp văn bản HTML và để nó thoát lại với các thực thể số tương ứng" - điều đó có nghĩa là bạn luôn có thể lưu trữ các thực thể dạng số trên thực thể văn bản HTML không? -Ryan – NightHawk

+0

@Ryan: Có, các thực thể số được cho phép trong (và được nhận ra bởi) cả XML và HTML. – Tomalak

+0

@Tomalak Điều đó có nghĩa là tôi sẽ phải biết tất cả các thực thể theo tên và thực thể số của chúng trước, phải không? Điều đó sẽ cực kỳ chế biến nếu tôi thêm tất cả vào đó? -Ryan – NightHawk

1

Nếu bạn muốn chuyển đổi tất cả các nhân vật, điều này có thể giúp bạn (Tôi đã viết nó trong một thời gian sau):

http://www.lautr.com/convert-all-applicable-characters-to-numeric-entities-for-use-in-xml

function _convertAlphaEntitysToNumericEntitys($entity) { 
    return '&#'.ord(html_entity_decode($entity[0])).';'; 
} 

$content = preg_replace_callback(
    '/&([\w\d]+);/i', 
    '_convertAlphaEntitysToNumericEntitys', 
    $content); 

function _convertAsciOver127toNumericEntitys($entity) { 
    if(($asciCode = ord($entity[0])) > 127) 
    return '&#'.$asciCode.';'; 
    else 
    return $entity[0]; 
} 

$content = preg_replace_callback(
    '/[^\w\d ]/i', 
    '_convertAsciOver127toNumericEntitys', $content); 
+0

, nếu bạn áp dụng "$ content = preg_replace_callback ('/ & ([\ w \ d] +);/i', '_ convertAlphaEntitysToNumericEntitys', $ content);" tất cả các thực thể HTML (  và whatnot) sẽ được thay đổi thành các thực thể dạng số. Sau đó áp dụng "$ content = preg_replace_callback ('/ [^ \ w \ d]/i', '_ convertAsciOver127toNumericEntitys'), $ content);" và mọi ký tự ở trên 127 (không được xử lý bởi htmlspecialchars) được chuyển thành thực thể dạng số, nếu tôi hiểu sai, bạn có thể đưa ra một đoạn mã ví dụ về đầu vào không? – Hannes

+0

xin lỗi, tôi hiểu lầm mã của bạn đã làm gì. Đang xóa nhận xét trước đó của tôi. – LarsH

4

1 . I can find and replace all [   ?] and swap them out with [   ?] or an actual space.

Đây là một phương pháp mạnh mẽ, nhưng nó đòi hỏi bạn để có một bảng của tất cả các thực thể HTML (tôi cho rằng đầu vào được dán đến từ HTML) và phân tích cú pháp văn bản đã dán cho các tham chiếu thực thể.

2 . I can place the code in question within a CDATA section.

Nói cách khác, hãy tắt phân tích cú pháp cho toàn bộ phần? Sau đó, bạn sẽ phải phân tích nó theo một cách khác. Có thể làm việc.

3 . I can include these entities within the XML file.

Bạn có nghĩa là bao gồm các định nghĩa đối tượng? Tôi nghĩ rằng đây là một cách dễ dàng và mạnh mẽ, nếu bạn không nhớ làm cho tệp XML lớn hơn một chút. Bạn có thể có tệp "được bao gồm" (tìm một tệp trên web), một thực thể bên ngoài, mà bạn tham chiếu từ đầu tệp XML chính của bạn.

Một nhược điểm là trình phân tích cú pháp XML bạn sử dụng phải là trình xử lý bên ngoài (không phải tất cả các trình phân tích cú pháp được yêu cầu phải làm). Và nó phải giải quyết một cách chính xác URL (có thể là tương đối) của thực thể bên ngoài thành một thứ có thể truy cập được. Điều này không quá tệ nhưng nó có thể làm tăng các ràng buộc đối với các công cụ xử lý của bạn.

4. Bạn có thể cấm không phải XML trong nội dung được dán. Trong số những thứ khác, điều này sẽ không cho phép các tham chiếu thực thể không được xác định trước trong XML (số 5 mà Tomalak đã đề cập) hoặc được xác định trong chính nội dung đó. Tuy nhiên, điều này có thể vi phạm các yêu cầu của ứng dụng, nếu người dùng cần để có thể dán HTML vào đó.

5. Bạn có thể phân tích cú pháp nội dung được dán dưới dạng HTML thành một cây DOM bằng cách thiết lập someDiv.innerHTML = thePastedContent; Nói cách khác, tạo một div ở đâu đó (có thể là display = none, ngoại trừ gỡ lỗi). Giả sử bạn có biến javascript myDiv chứa phần tử div này và một biến khác myField chứa phần tử đó là trường văn bản nhập của bạn. Sau đó, trong javascript bạn làm

myDiv.innerHTML = myField.value; 

lấy văn bản chưa được phân tích từ myField, phân tích văn bản đó thành một cây DOM HTML và gắn nó vào myDiv dưới dạng nội dung HTML.

Sau đó, bạn sẽ sử dụng một số phương pháp dựa trên trình duyệt để tuần tự hóa (= "phân tích cú pháp") cây DOM trở lại thành XML. Xem ví dụ this question. Sau đó, bạn gửi kết quả đến máy chủ dưới dạng XML.

Cho dù bạn muốn sửa lỗi này trong trình duyệt hoặc trên máy chủ (như @Hannes được đề xuất) sẽ phụ thuộc vào kích thước của dữ liệu, tốc độ phản hồi nhanh như thế nào quan tâm đến tin tặc gửi XML không đúng định dạng.

+0

@Tomalak - tại sao ö trở thành & ouml ;? Khi văn bản được đưa vào innerhtml, nó sẽ không được phân tích cú pháp vào trong dom như một ký tự đơn âm? – LarsH

+0

1. Có thể có quá nhiều chi phí, phải không? 2. Trên suy nghĩ thứ hai, điều này có vẻ phản tác dụng, vì vậy tôi sẽ loại bỏ tùy chọn đó. 3. Bên cạnh các tập tin được lớn hơn, có những nhược điểm khác? Nếu không, tôi sẽ nói đó là cách để đi. 4. Có, điều đó sẽ vi phạm các yêu cầu. 5. Tôi không hiểu giải pháp này - bạn có thể cung cấp thêm chi tiết không? -Ryan – NightHawk

+0

@Ryan, tôi sẽ chỉnh sửa câu trả lời của tôi để thêm chi tiết vào ngày 3 và 5. – LarsH

19

Tôi đồng ý rằng đó hoàn toàn là sự cố mã hóa. Trong PHP, đây là cách tôi giải quyết vấn đề này:

  1. Trước khi đi qua html-fragment để SimpleXMLElement constructor tôi giải mã nó bằng cách sử html_entity_decode.

  2. Sau đó mã hóa thêm bằng cách sử dụng utf8_encode().

$headerDoc = '<temp>' . utf8_encode(html_entity_decode($headerFragment)) . '</temp>'; 
$xmlHeader = new SimpleXMLElement($headerDoc); 

Bây giờ các mã trên không ném bất kỳ thực thể không xác định lỗi.

+7

Bạn có thể thoát ra mà không sử dụng 'utf8_encode' nếu bạn cung cấp' "UTF-8" 'cho [' html_entity_decode'] (http://php.net/manual/en/function.html-entity-decode. php) làm tham số thứ ba, ví dụ 'html_entity_decode ($ headerFragment, null," UTF-8 ")' –

0

Câu hỏi này là một vấn đề chung đối với bất kỳ ngôn ngữ nào phân tích cú pháp XML hoặc JSON (vì vậy, về cơ bản, mọi ngôn ngữ).

Những câu trả lời trên là dành cho PHP, nhưng một giải pháp Perl sẽ dễ dàng như ...

my $excluderegex = 
    '^\n\x20-\x20' . # Don't Encode Spaces 
     '\x30-\x39' . # Don't Encode Numbers 
     '\x41-\x5a' . # Don't Encode Capitalized Letters 
     '\x61-\x7a' ; # Don't Encode Lowercase Letters 

    # in case anything is already encoded 
$value = HTML::Entities::decode_entities($value); 

    # encode properly to numeric 
$value = HTML::Entities::encode_numeric($value, $excluderegex); 
Các vấn đề liên quan