2012-12-20 32 views
6

Tôi đang trải qua những hành vi sau đây:PHP, SimpleXML, giải mã các thực thể trong CDATA

$xml_string1 = "<person><name><![CDATA[ Someone&#039;s Name ]]></name></person>"; 
$xml_string2 = "<person><name> Someone&#039;s Name </name></person>"; 

$person = new SimpleXMLElement($xml_string1); 
print (string) $person->name; # Someone&#039;s Name 

$person = new SimpleXMLElement($xml_string2); 
print (string) $person->name; # Someone's Name 

$person = new SimpleXMLElement($xml_string1, LIBXML_NOCDATA); 
print (string) $person->name; # Someone&#039;s Name 

Các tài liệu php nói rằng NOCDATA "Hợp nhất [s] CDATA như các nút văn bản". Với tôi điều này có nghĩa là CDATA sau đó sẽ được xử lý giống như các nút văn bản - hoặc hành vi của ví dụ thứ 3 bây giờ sẽ giống như ví dụ thứ 2.

Tôi không có quyền kiểm soát XML (đó là nguồn cấp dữ liệu từ nguồn bên ngoài), nếu không tôi chỉ xóa thẻ CDATA vì không có gì và hủy hoại hành vi tôi muốn.

Tại sao ví dụ trên hoạt động theo cách thực hiện? Có cách nào để làm cho SimpleXML xử lý các nút CDATA giống như cách nó xử lý các nút văn bản không? "Merge CDATA như các nút văn bản" thực sự làm gì, vì tôi dường như không hiểu được lựa chọn đó?

Tôi hiện đang giải mã sau khi tôi lấy dữ liệu ra, nhưng ví dụ trên vẫn không có ý nghĩa với tôi.

+0

'print' có ngữ cảnh chuỗi không cần phải đúc thành chuỗi trong trường hợp đó. – hakre

+0

@hakre nhưng 'print' (thường được viết là' echo') có thể được sử dụng như một phần mềm đứng trong khi gỡ lỗi sau đó được thay thế bằng một thứ khác, vì vậy tôi muốn nói rằng đó là thói quen tốt để thực hiện chuỗi tránh nhầm lẫn sau này. – IMSoP

Trả lời

9

Mục đích của phần CDATA trong XML là đóng gói một khối văn bản "nguyên bản", nếu không sẽ yêu cầu các ký tự đặc biệt (cụ thể là >, <&) để thoát. Phần CDATA chứa ký tự & giống với một nút văn bản thông thường có chứa &amp;.

Nếu một phân tích cú pháp là để cung cấp cho bỏ qua điều này, và giả vờ tất cả các nút CDATA là thực sự chỉ là các nút văn bản, nó ngay lập tức sẽ phá vỡ ngay khi ai đó đề cập "P & O Cruises" - đó & chỉ đơn giản là không thể có mặt trên của riêng nó (thay vì là &amp; hoặc &somethingElse;).

LIBXML_NOCDATA thực sự khá vô ích với SimpleXML, vì (string)$foo gọn gàng kết hợp bất kỳ chuỗi văn bản và nút CDATA nào vào chuỗi PHP thông thường. Điều này không nhất thiết đúng với các phương thức truy cập có hệ thống hơn, chẳng hạn như DOM, nơi bạn có thể thao tác các nút văn bản và các nút CDATA như các đối tượng theo đúng nghĩa của chúng.

Điều gì có hiệu quả là xem qua tài liệu và bất cứ nơi nào nó gặp phần CDATA, nó lấy nội dung, thoát nó và đặt nó trở lại dưới dạng nút văn bản thông thường hoặc "hợp nhất" nó với bất kỳ nút văn bản nào hai bên. Văn bản được biểu diễn giống hệt nhau, chỉ được lưu trữ trong tài liệu theo cách khác; bạn có thể thấy sự khác biệt nếu bạn xuất trở lại XML, như trong ví dụ này:

$xml_string = "<person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person>"; 

$person = new SimpleXMLElement($xml_string); 
echo 'CDATA retained: ', $person->asXML(); 
// CDATA retained: <?xml version="1.0"?> 
// <person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person> 

$person = new SimpleXMLElement($xml_string, LIBXML_NOCDATA); 
echo 'CDATA merged: ', $person->asXML(); 
// CDATA merged: <?xml version="1.0"?> 
// <person><name>Welcome aboard this P&amp;O Cruises voyage!</name></person> 

Nếu tài liệu XML bạn đang phân tích có chứa một phần CDATA mà thực sự chứa các thực thể, bạn cần phải thực hiện rằng chuỗi và unescape nó hoàn toàn độc lập với XML. Một lý do phổ biến để làm điều này (ngoài sự lười biếng với các thư viện kém hiểu) là xử lý nội dung nào đó được đánh dấu bằng HTML như bất kỳ chuỗi cũ nào bên trong tài liệu XML, như sau:

<Comment> 
<SubmittedBy>IMSoP</SubmittedBy> 
<Text><![CDATA[I'm <em>really</em> bad at keeping my answers brief <tt>;)</tt>]]></Text> 
</Comment> 
+1

Câu trả lời hay, rất nhiều thông tin –

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