2009-09-21 36 views
6

Tôi phải phân tích cú pháp XML được cung cấp bên ngoài có thuộc tính có ngắt dòng trong chúng. Sử dụng SimpleXML, các ngắt dòng dường như bị mất. Theo số another stackoverflow question, ngắt dòng phải hợp lệ (mặc dù ít hơn nhiều so với lý tưởng!) Cho XML.PHP SimpleXML không bảo toàn ngắt dòng trong thuộc tính XML

Tại sao chúng bị mất? [sửa] Và làm thế nào tôi có thể bảo tồn chúng? [/ edit]

Đây là tập lệnh bản giới thiệu (lưu ý rằng khi ngắt dòng không nằm trong thuộc tính mà chúng được giữ nguyên).

PHP tập tin với XML nhúng

$xml = <<<XML 
<?xml version="1.0" encoding="utf-8"?> 
<Rows> 
    <data Title='Data Title' Remarks='First line of the row. 
Followed by the second line. 
Even a third!' /> 
    <data Title='Full Title' Remarks='None really'>First line of the row. 
Followed by the second line. 
Even a third!</data> 
</Rows> 
XML; 

$xml = new SimpleXMLElement($xml); 
print '<pre>'; print_r($xml); print '</pre>'; 

Output từ print_r

SimpleXMLElement Object 
(
    [data] => Array 
     (
      [0] => SimpleXMLElement Object 
       (
        [@attributes] => Array 
         (
          [Title] => Data Title 
          [Remarks] => First line of the row. Followed by the second line. Even a third! 
         ) 

       ) 

      [1] => First line of the row. 
Followed by the second line. 
Even a third! 
     ) 

) 
+0

Bạn nên đặt câu hỏi này trong trang chủ PHP. Tôi đoán đó là bởi vì đó là trình phân tích cú pháp xml SIMPLE. – jbasko

+0

Bạn có thể giải thích thêm một chút về ý nghĩa của trang chủ PHP không? – Joshua

+0

Ban đầu câu hỏi của bạn là "Tại sao SimpleXML thực hiện những gì nó làm?" Đó là những gì bạn có thể hỏi đó là nhà phát triển không phải người dùng. – jbasko

Trả lời

4

Thực thể cho một dòng sản phẩm mới là &#10;. Tôi chơi với mã của bạn cho đến khi tôi tìm thấy một cái gì đó đã làm các trick. Nó không phải rất thanh lịch, tôi cảnh báo bạn:

//First remove any indentations: 
$xml = str_replace("  ","", $xml); 
$xml = str_replace("\t","", $xml); 

//Next replace unify all new-lines into unix LF: 
$xml = str_replace("\r","\n", $xml); 
$xml = str_replace("\n\n","\n", $xml); 

//Next replace all new lines with the unicode: 
$xml = str_replace("\n","&#10;", $xml); 

Finally, replace any new line entities between >< with a new line: 
$xml = str_replace(">&#10;<",">\n<", $xml); 

Giả định, dựa trên ví dụ của bạn, đó là bất kỳ dòng mới xảy ra bên trong một nút hoặc thuộc tính sẽ có nhiều văn bản hơn trên dòng tiếp theo, không phải là một < để mở một yếu tố mới.

Điều này tất nhiên sẽ thất bại nếu dòng tiếp theo của bạn có một số văn bản được gói trong phần tử cấp dòng.

+0

Rất thông minh !!! Việc bắt duy nhất là tôi đang làm việc với lớn SOAP bao phủ XML spewing từ các dịch vụ web SharePoint, do đó, nó làm cho tôi một chút lo lắng để làm một cái gì đó để lực lượng vũ phu. Dựa trên bài đăng của bobince, có vẻ như tôi có thể phải đi theo hướng này. Tôi tự hỏi nếu có cách nào thanh lịch hơn để kéo nó đi. – Joshua

11

Sử dụng SimpleXML, ngắt dòng dường như bị mất.

Có, đó là mong đợi ... trên thực tế nó là bắt buộc đối với bất kỳ trình phân tích cú pháp XML tuân thủ nào mà các dòng mới trong các giá trị thuộc tính thể hiện các khoảng trắng đơn giản. Xem attribute value normalisation trong thông số XML.

Nếu có nghĩa vụ phải là ký tự dòng mới thực trong giá trị thuộc tính, XML phải bao gồm tham chiếu ký tự &#10; thay vì dòng mới thô.

+2

Để làm rõ chỉ một chút: các dòng mới là * VALID *, nhưng trình phân tích cú pháp XML (để tuân thủ đặc tả) ** PHẢI ** giảm chúng xuống một ký tự khoảng trắng (xem mục 3 của liên kết của bobince) . – TML

+0

Cảm ơn bạn đã liên kết với bobince và TML làm rõ. Vì vậy, tôi cho rằng câu hỏi của tôi bây giờ đã trở thành, làm thế nào tôi có thể giữ lại những ngắt dòng? Tôi nhận được dữ liệu này từ một dịch vụ web SharePoint, vì vậy tôi không thể thay đổi XML để bao gồm & # 10. Có cách nào để ghi đè sự tuân thủ của trình phân tích cú pháp trong lĩnh vực này không? – Joshua

+0

Thật không may là, XML hoàn toàn không linh hoạt vào thời điểm này; nếu dịch vụ web đang tạo '\ n' khi nó có nghĩa là ' ' thì đó là lỗi. (Và một điều đáng ngạc nhiên vì đây là một tính năng cơ bản mà bất kỳ serialiser XML nào được mong đợi sẽ nhận được đúng ... trừ khi dịch vụ đang mút xung quanh với regex hoặc chuỗi templating thay vì sử dụng một thư viện XML thích hợp!) – bobince

0

Đây là những gì làm việc cho tôi:

Đầu tiên, lấy xml như là một chuỗi:

$xml = file_get_contents($urlXml); 

Sau đó làm việc thay thế: ""

$xml = str_replace(".\xe2\x80\xa9<as:eol/>",".\n\n<as:eol/>",$xml); 

Các và "< là: eol />" đã có bởi vì tôi cần thêm dấu ngắt trong trường hợp đó. Các dòng mới "\ n" có thể được thay thế bằng bất cứ thứ gì bạn thích.

Sau khi thay thế, chỉ cần nạp xml-chuỗi như một đối tượng SimpleXMLElement:

$xmlo = new SimpleXMLElement($xml); 

Et Voila

1

Giả sử $ xmlData được chuỗi XML của bạn trước khi nó được gửi tới bộ phân tích, điều này sẽ thay thế tất cả dòng mới trong thuộc tính với thực thể đúng. Tôi đã có vấn đề với XML đến từ SQL Server.

$parts = explode("<", $xmlData); //split over < 
array_shift($parts); //remove the blank array element 
$newParts = array(); //create array for storing new parts 
foreach($parts as $p) 
{ 
    list($attr,$other) = explode(">", $p, 2); //get attribute data into $attr 
    $attr = str_replace("\r\n", "&#10;", $attr); //do the replacement 
    $newParts[] = $attr.">".$other; // put parts back together 
} 
$xmlData = "<".implode("<", $newParts); // put parts back together prefixing with < 

Có thể làm đơn giản hơn với regex, nhưng đó không phải là điểm mạnh cho tôi.

+0

Chính xác, vấn đề là các dòng mới về mặt kỹ thuật không hợp lệ trong các thuộc tính XML. Tuy nhiên, phân tích cú pháp có xu hướng sửa chữa mọi thứ rất nhiều. Trong mọi trường hợp, các thực thể không hợp lệ phải được mã hóa.Giải pháp tốt nhất là sửa chữa nguồn, nhưng điều này có vẻ hợp pháp nếu điều đó không có sẵn. –

0

Vâng, câu hỏi này là cũ nhưng giống như tôi, ai đó có thể đến trang này cuối cùng. Tôi đã có cách tiếp cận hơi khác và tôi nghĩ rằng thanh lịch nhất trong số này đã đề cập.

Bên trong xml, bạn đặt một số từ duy nhất mà bạn sẽ sử dụng cho dòng mới.

Thay đổi xml để

<data Title='Data Title' Remarks='First line of the row. \n 
Followed by the second line. \n 
Even a third!' /> 

Và sau đó khi bạn nhận được đường dẫn đến nút mong muốn trong SimpleXML trong chuỗi đầu ra ghi một cái gì đó như thế này:

$findme = '\n'; 
$pos = strpos($output, $findme); 
if($pos!=0) 
{ 
$output = str_replace("\n","<br/>",$output); 

Nó không phải là '\ n , nó có thể là bất kỳ char độc đáo nào.

1

Đây là mã để thay thế các dòng mới bằng tham chiếu ký tự thích hợp trong đoạn XML cụ thể đó. Chạy mã này trước khi phân tích cú pháp.

$replaceFunction = function ($matches) { 
    return str_replace("\n", "&#10;", $matches[0]); 
}; 
$xml = preg_replace_callback(
    "/<data Title='[^']+' Remarks='[^']+'/i", 
    $replaceFunction, $xml); 
Các vấn đề liên quan