2011-08-03 27 views
10

Đây là những gì tôi sauthêm một không gian tên khi sử dụng SimpleXMLElement

<!-- language: lang-xml --> 
<ws:Test> 
    <ws:somename2>somevalue2</ws:somename2> 
    <ws:make> 
     <ws:model>foo</ws:model> 
     <ws:model>bar</ws:model> 
    </ws:make> 
</ws:Test> 

Đây là mã hiện tại của tôi

<!-- language: lang-php --> 
$xmlTest = new SimpleXMLElement('<Test/>', 0, false, 'ws', true); 
$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/'); 
$make = $xmlTest->addChild('ws:make', null, 'ws'); 
#$make->addAttribute('name','Ford'); 
$make->addChild('ws:model', 'foo', 'ws'); 
$make->addChild('ws:model', 'bar', 'ws'); 
header ("Content-Type:text/xml"); 
print_r($xmlTest->asXML()); 

nhưng nó ra

<!-- language: lang-xml --> 
<Test> 
    <ws:somename2>somevalue2</ws:somename2> 
    <ws:make> 
     <ws:model>foo</ws:model> 
     <ws:model>bar</ws:model> 
    </ws:make> 
</Test> 

Như bạn có thể thấy ws : bị thiếu trong Bài kiểm tra

Trả lời

28

SimpleXML có một quirk khác thường nơi tiền tố không gian tên được lọc từ phần tử gốc. Tôi không chắc tại sao nó lại như thế.

Tuy nhiên, một workaround Tôi đã sử dụng đã được cơ bản tiền tố tiền tố, do đó phân tích cú pháp chỉ loại bỏ những người đầu tiên, và lá thứ hai

$xmlTest = new SimpleXMLElement('<xmlns:ws:Test></xmlns:ws:Test>', LIBXML_NOERROR, false, 'ws', true); 
$xmlTest->addAttribute('xmlns:xmlns:ws', 'http://url.to.namespace'); 
$xmlTest->addAttribute('xmlns:xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); 

Điều này dường như làm việc cho tôi, mặc dù tôi quan tâm để hiểu tại sao SimpleXML thực hiện điều này một cách chính xác.

+0

thực sự hoạt động, cảm ơn –

+0

Vì vậy, thêm tiền tố vào tiền tố đã khắc phục sự cố :) –

+0

Bạn có tìm thấy giải pháp nào khác ngoài giải pháp này không? – Hitesh

0
$xmlTest = new \SimpleXMLElement('<ws:Test></ws:Test>', LIBXML_NOERROR, false, 'ws', true); 
$xmlTest->addAttribute('xmlns:xmlns:ws', 'http://url.to.namespace'); 
$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/'); 
$make = $xmlTest->addChild('ws:make', null, 'ws'); 
#$make->addAttribute('name','Ford'); 
$make->addChild('ws:model', 'foo', 'ws'); 
$make->addChild('ws:model', 'bar', 'ws'); 
+1

Vui lòng thêm một số giải thích. – gofr1

+0

Trong khi mã này có thể trả lời câu hỏi, sẽ tốt hơn nếu đưa vào một số ngữ cảnh, giải thích cách hoạt động và thời điểm sử dụng nó. Câu trả lời chỉ có mã không hữu ích trong thời gian dài. – Bono

4

Vấn đề

Vấn đề với mã này là trong dòng đầu tiên:

$xmlTest = new SimpleXMLElement('<Test/>', 0, false, 'ws', true); 

Trước khi làm bất cứ điều gì khác, chúng ta hãy đầu ra này như XML:

echo $xmlTest->asXML(); 

<?xml version="1.0"?> 
<Test/> 

Điều đó có ý nghĩa, chúng tôi đã tìm ra những gì chúng tôi đưa vào.

Hướng dẫn này khá mơ hồ về những gì đối số $ns làm, nhưng trong trường hợp này nó không làm bất cứ điều gì hữu ích. Những gì nó làm là đặt bối cảnh cho đọc XML, sao cho ->foo đề cập đến <ws:foo>['bar'] đề cập đến ws:bar="...". Nó không làm bất cứ điều gì để thay đổi cấu trúc của chính XML.

Thiết lập một gốc Namespace

Để thiết lập một không gian tên trên phần tử gốc, chúng tôi chỉ phải bao gồm nó trong chuỗi của chúng tôi xác định phần tử gốc:

$xmlTest = new SimpleXMLElement('<ws:Test xmlns:ws="http://microsoft.com/wsdl/types/" />'); 
echo $xmlTest->asXML(); 

<?xml version="1.0"?> 
<ws:Test xmlns:ws="http://microsoft.com/wsdl/types/"/> 

Cho đến nay rất tốt ...

Namespaces Setting trên trẻ em

Tiếp theo, chúng ta hãy tỉnh táo kiểm tra những mã trong câu hỏi thực sự kết quả đầu ra (tôi đã thêm một số khoảng trắng để làm cho nó dễ đọc hơn):

<?xml version="1.0"?> 
<Test> 
    <ws:somename2 xmlns:ws="http://microsoft.com/wsdl/types/">somevalue2</ws:somename2> 
    <ws:make xmlns:ws="ws"> 
     <ws:model>foo</ws:model> 
     <ws:model>bar</ws:model> 
    </ws:make> 
</Test> 

OK, vì vậy đây tài liệu chứa hai tờ khai namespace:

  • xmlns:ws="http://microsoft.com/wsdl/types/" trên các yếu tố somename2
  • xmlns:ws="ws" trên các yếu tố make, sau đó được thừa hưởng bởi các yếu tố model

gì sẽ xảy ra nếu chúng ta thêm phần tử gốc được sửa chữa của chúng tôi?

<?xml version="1.0"?> 
<ws:Test xmlns:ws="http://microsoft.com/wsdl/types/"> 
    <ws:somename2>somevalue2</ws:somename2> 
    <ws:make xmlns:ws="ws"> 
     <ws:model>foo</ws:model> 
     <ws:model>bar</ws:model> 
    </ws:make> 
</ws:Test> 

mát, do đó yếu tố somename2 giờ đây thừa hưởng nét gian tên của nó từ phần tử gốc, và không tái khai báo nó. Nhưng có gì sai với makemodel s? Hãy so sánh:

$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/'); 
$make = $xmlTest->addChild('ws:make', null, 'ws'); 

Đó số thứ ba được coi là các namespace URI, không chỉ là tiền tố. Vì vậy, khi chúng tôi đưa nó như là 'ws', SimpleXML giả định chúng tôi muốn khai báo URI không gian tên thực tế là ws, vì vậy hãy thêm thuộc tính xmlns để làm như vậy.

gì chúng tôi thực sự muốn là tất cả các yếu tố để được trong không gian tên giống nhau:

$xmlTest = new SimpleXMLElement('<ws:Test xmlns:ws="http://microsoft.com/wsdl/types/" />'); 
$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/'); 
$make = $xmlTest->addChild('ws:make', null, 'http://microsoft.com/wsdl/types/'); 
#$make->addAttribute('name','Ford', 'http://microsoft.com/wsdl/types/'); 
$make->addChild('ws:model', 'foo', 'http://microsoft.com/wsdl/types/'); 
$make->addChild('ws:model', 'bar', 'http://microsoft.com/wsdl/types/'); 
echo $xmlTest->asXML(); 

<?xml version="1.0"?> 
<ws:Test xmlns:ws="http://microsoft.com/wsdl/types/"> 
    <ws:somename2>somevalue2</ws:somename2> 
    <ws:make> 
     <ws:model>foo</ws:model> 
     <ws:model>bar</ws:model> 
    </ws:make> 
</ws:Test> 

Tuyệt vời, chúng tôi đã có đầu ra mong muốn của chúng tôi!

Tidying Up

Nhưng mã đó trông khá xấu, tại sao chúng ta phải lặp lại URI ở mọi nơi? Vâng, như xa như SimpleXML là có liên quan, không có nhiều sự lựa chọn: cùng một tiền tố có thể có nghĩa là những thứ khác nhau trong các phần khác nhau của tài liệu, vì vậy chúng tôi phải nói với nó những gì chúng ta muốn.

Những gì chúng ta thể làm là dọn dẹp mã của chúng tôi sử dụng một biến hoặc hằng số cho namespace URI, chứ không phải viết nó ra đầy đủ mỗi lần:

define('XMLNS_WS', 'http://microsoft.com/wsdl/types/'); 

$xmlTest = new SimpleXMLElement('<ws:Test xmlns:ws="' . XMLNS_WS . '" />'); 
$xmlTest->addChild("ws:somename2", "somevalue2", XMLNS_WS); 
$make = $xmlTest->addChild('ws:make', null, XMLNS_WS); 
#$make->addAttribute('name','Ford', XMLNS_WS); 
$make->addChild('ws:model', 'foo', XMLNS_WS); 
$make->addChild('ws:model', 'bar', XMLNS_WS); 

Không có gì đặc biệt về tên XMLNS_WS đây và nó có thể là một biến, hằng số lớp hoặc hằng số không gian tên. Mã chạy chính xác như nhau, nó chỉ dễ dàng hơn một chút trên mắt.

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