XmlTest.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. <?php
  2. /**
  3. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  12. * @since 1.2.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Utility;
  16. use Cake\Collection\Collection;
  17. use Cake\Core\Configure;
  18. use Cake\ORM\Entity;
  19. use Cake\TestSuite\TestCase;
  20. use Cake\Utility\Exception\XmlException;
  21. use Cake\Utility\Xml;
  22. /**
  23. * XmlTest class
  24. *
  25. */
  26. class XmlTest extends TestCase
  27. {
  28. /**
  29. * autoFixtures property
  30. *
  31. * @var bool
  32. */
  33. public $autoFixtures = false;
  34. /**
  35. * fixtures property
  36. * @var array
  37. */
  38. public $fixtures = [
  39. 'core.articles', 'core.users'
  40. ];
  41. /**
  42. * setUp method
  43. *
  44. * @return void
  45. */
  46. public function setUp()
  47. {
  48. parent::setUp();
  49. $this->_appEncoding = Configure::read('App.encoding');
  50. Configure::write('App.encoding', 'UTF-8');
  51. }
  52. /**
  53. * tearDown method
  54. *
  55. * @return void
  56. */
  57. public function tearDown()
  58. {
  59. parent::tearDown();
  60. Configure::write('App.encoding', $this->_appEncoding);
  61. }
  62. /**
  63. * testBuild method
  64. *
  65. * @return void
  66. */
  67. public function testBuild()
  68. {
  69. $xml = '<tag>value</tag>';
  70. $obj = Xml::build($xml);
  71. $this->assertTrue($obj instanceof \SimpleXMLElement);
  72. $this->assertEquals('tag', (string)$obj->getName());
  73. $this->assertEquals('value', (string)$obj);
  74. $xml = '<?xml version="1.0" encoding="UTF-8"?><tag>value</tag>';
  75. $this->assertEquals($obj, Xml::build($xml));
  76. $obj = Xml::build($xml, ['return' => 'domdocument']);
  77. $this->assertTrue($obj instanceof \DOMDocument);
  78. $this->assertEquals('tag', $obj->firstChild->nodeName);
  79. $this->assertEquals('value', $obj->firstChild->nodeValue);
  80. $xml = CORE_TESTS . 'Fixture/sample.xml';
  81. $obj = Xml::build($xml);
  82. $this->assertEquals('tags', $obj->getName());
  83. $this->assertEquals(2, count($obj));
  84. $this->assertEquals(Xml::build($xml), Xml::build(file_get_contents($xml)));
  85. $obj = Xml::build($xml, ['return' => 'domdocument']);
  86. $this->assertEquals('tags', $obj->firstChild->nodeName);
  87. $this->assertEquals(
  88. Xml::build($xml, ['return' => 'domdocument']),
  89. Xml::build(file_get_contents($xml), ['return' => 'domdocument'])
  90. );
  91. $xml = ['tag' => 'value'];
  92. $obj = Xml::build($xml);
  93. $this->assertEquals('tag', $obj->getName());
  94. $this->assertEquals('value', (string)$obj);
  95. $obj = Xml::build($xml, ['return' => 'domdocument']);
  96. $this->assertEquals('tag', $obj->firstChild->nodeName);
  97. $this->assertEquals('value', $obj->firstChild->nodeValue);
  98. $obj = Xml::build($xml, ['return' => 'domdocument', 'encoding' => null]);
  99. $this->assertNotRegExp('/encoding/', $obj->saveXML());
  100. }
  101. /**
  102. * Test build() with a Collection instance.
  103. *
  104. * @return void
  105. */
  106. public function testBuildCollection()
  107. {
  108. $xml = new Collection(['tag' => 'value']);
  109. $obj = Xml::build($xml);
  110. $this->assertEquals('tag', $obj->getName());
  111. $this->assertEquals('value', (string)$obj);
  112. $xml = new Collection([
  113. 'response' => [
  114. 'users' => new Collection(['leonardo', 'raphael'])
  115. ]
  116. ]);
  117. $obj = Xml::build($xml);
  118. $this->assertContains('<users>leonardo</users>', $obj->saveXML());
  119. }
  120. /**
  121. * Test build() with ORM\Entity instances wrapped in a Collection.
  122. *
  123. * @return void
  124. */
  125. public function testBuildOrmEntity()
  126. {
  127. $user = new Entity(['username' => 'mark', 'email' => 'mark@example.com']);
  128. $xml = new Collection([
  129. 'response' => [
  130. 'users' => new Collection([$user])
  131. ]
  132. ]);
  133. $obj = Xml::build($xml);
  134. $output = $obj->saveXML();
  135. $this->assertContains('<username>mark</username>', $output);
  136. $this->assertContains('<email>mark@example.com</email>', $output);
  137. }
  138. /**
  139. * data provider function for testBuildInvalidData
  140. *
  141. * @return array
  142. */
  143. public static function invalidDataProvider()
  144. {
  145. return [
  146. [null],
  147. [false],
  148. [''],
  149. ['http://localhost/notthere.xml'],
  150. ];
  151. }
  152. /**
  153. * testBuildInvalidData
  154. *
  155. * @dataProvider invalidDataProvider
  156. * @expectedException \RuntimeException
  157. * @return void
  158. */
  159. public function testBuildInvalidData($value)
  160. {
  161. Xml::build($value);
  162. }
  163. /**
  164. * Test that building SimpleXmlElement with invalid XML causes the right exception.
  165. *
  166. * @expectedException \Cake\Utility\Exception\XmlException
  167. * @return void
  168. */
  169. public function testBuildInvalidDataSimpleXml()
  170. {
  171. $input = '<derp';
  172. Xml::build($input, ['return' => 'simplexml']);
  173. }
  174. /**
  175. * test build with a single empty tag
  176. *
  177. * @return void
  178. */
  179. public function testBuildEmptyTag()
  180. {
  181. try {
  182. Xml::build('<tag>');
  183. $this->fail('No exception');
  184. } catch (\Exception $e) {
  185. $this->assertTrue(true, 'An exception was raised');
  186. }
  187. }
  188. /**
  189. * testFromArray method
  190. *
  191. * @return void
  192. */
  193. public function testFromArray()
  194. {
  195. $xml = ['tag' => 'value'];
  196. $obj = Xml::fromArray($xml);
  197. $this->assertEquals('tag', $obj->getName());
  198. $this->assertEquals('value', (string)$obj);
  199. $xml = ['tag' => null];
  200. $obj = Xml::fromArray($xml);
  201. $this->assertEquals('tag', $obj->getName());
  202. $this->assertEquals('', (string)$obj);
  203. $xml = ['tag' => ['@' => 'value']];
  204. $obj = Xml::fromArray($xml);
  205. $this->assertEquals('tag', $obj->getName());
  206. $this->assertEquals('value', (string)$obj);
  207. $xml = [
  208. 'tags' => [
  209. 'tag' => [
  210. [
  211. 'id' => '1',
  212. 'name' => 'defect'
  213. ],
  214. [
  215. 'id' => '2',
  216. 'name' => 'enhancement'
  217. ]
  218. ]
  219. ]
  220. ];
  221. $obj = Xml::fromArray($xml, 'attributes');
  222. $this->assertTrue($obj instanceof \SimpleXMLElement);
  223. $this->assertEquals('tags', $obj->getName());
  224. $this->assertEquals(2, count($obj));
  225. $xmlText = <<<XML
  226. <?xml version="1.0" encoding="UTF-8"?>
  227. <tags>
  228. <tag id="1" name="defect"/>
  229. <tag id="2" name="enhancement"/>
  230. </tags>
  231. XML;
  232. $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML());
  233. $obj = Xml::fromArray($xml);
  234. $this->assertTrue($obj instanceof \SimpleXMLElement);
  235. $this->assertEquals('tags', $obj->getName());
  236. $this->assertEquals(2, count($obj));
  237. $xmlText = <<<XML
  238. <?xml version="1.0" encoding="UTF-8"?>
  239. <tags>
  240. <tag>
  241. <id>1</id>
  242. <name>defect</name>
  243. </tag>
  244. <tag>
  245. <id>2</id>
  246. <name>enhancement</name>
  247. </tag>
  248. </tags>
  249. XML;
  250. $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML());
  251. $xml = [
  252. 'tags' => [
  253. ]
  254. ];
  255. $obj = Xml::fromArray($xml);
  256. $this->assertEquals('tags', $obj->getName());
  257. $this->assertEquals('', (string)$obj);
  258. $xml = [
  259. 'tags' => [
  260. 'bool' => true,
  261. 'int' => 1,
  262. 'float' => 10.2,
  263. 'string' => 'ok',
  264. 'null' => null,
  265. 'array' => []
  266. ]
  267. ];
  268. $obj = Xml::fromArray($xml, 'tags');
  269. $this->assertEquals(6, count($obj));
  270. $this->assertSame((string)$obj->bool, '1');
  271. $this->assertSame((string)$obj->int, '1');
  272. $this->assertSame((string)$obj->float, '10.2');
  273. $this->assertSame((string)$obj->string, 'ok');
  274. $this->assertSame((string)$obj->null, '');
  275. $this->assertSame((string)$obj->array, '');
  276. $xml = [
  277. 'tags' => [
  278. 'tag' => [
  279. [
  280. '@id' => '1',
  281. 'name' => 'defect'
  282. ],
  283. [
  284. '@id' => '2',
  285. 'name' => 'enhancement'
  286. ]
  287. ]
  288. ]
  289. ];
  290. $obj = Xml::fromArray($xml, 'tags');
  291. $xmlText = <<<XML
  292. <?xml version="1.0" encoding="UTF-8"?>
  293. <tags>
  294. <tag id="1">
  295. <name>defect</name>
  296. </tag>
  297. <tag id="2">
  298. <name>enhancement</name>
  299. </tag>
  300. </tags>
  301. XML;
  302. $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML());
  303. $xml = [
  304. 'tags' => [
  305. 'tag' => [
  306. [
  307. '@id' => '1',
  308. 'name' => 'defect',
  309. '@' => 'Tag 1'
  310. ],
  311. [
  312. '@id' => '2',
  313. 'name' => 'enhancement'
  314. ],
  315. ],
  316. '@' => 'All tags'
  317. ]
  318. ];
  319. $obj = Xml::fromArray($xml, 'tags');
  320. $xmlText = <<<XML
  321. <?xml version="1.0" encoding="UTF-8"?>
  322. <tags>All tags<tag id="1">Tag 1<name>defect</name></tag><tag id="2"><name>enhancement</name></tag></tags>
  323. XML;
  324. $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML());
  325. $xml = [
  326. 'tags' => [
  327. 'tag' => [
  328. 'id' => 1,
  329. '@' => 'defect'
  330. ]
  331. ]
  332. ];
  333. $obj = Xml::fromArray($xml, 'attributes');
  334. $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?><tags><tag id="1">defect</tag></tags>';
  335. $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML());
  336. $xml = [
  337. 'tag' => [
  338. '@' => 0,
  339. '@test' => 'A test'
  340. ]
  341. ];
  342. $obj = Xml::fromArray($xml);
  343. $xmlText = <<<XML
  344. <?xml version="1.0" encoding="UTF-8"?>
  345. <tag test="A test">0</tag>
  346. XML;
  347. $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML());
  348. }
  349. /**
  350. * Test non-sequential keys in list types.
  351. *
  352. * @return void
  353. */
  354. public function testFromArrayNonSequentialKeys()
  355. {
  356. $xmlArray = [
  357. 'Event' => [
  358. [
  359. 'id' => '235',
  360. 'Attribute' => [
  361. 0 => [
  362. 'id' => '9646',
  363. ],
  364. 2 => [
  365. 'id' => '9647',
  366. ]
  367. ]
  368. ]
  369. ]
  370. ];
  371. $obj = Xml::fromArray($xmlArray);
  372. $expected = <<<XML
  373. <?xml version="1.0" encoding="UTF-8"?>
  374. <Event>
  375. <id>235</id>
  376. <Attribute>
  377. <id>9646</id>
  378. </Attribute>
  379. <Attribute>
  380. <id>9647</id>
  381. </Attribute>
  382. </Event>
  383. XML;
  384. $this->assertXmlStringEqualsXmlString($expected, $obj->asXML());
  385. }
  386. /**
  387. * testFromArrayPretty method
  388. *
  389. * @return void
  390. */
  391. public function testFromArrayPretty()
  392. {
  393. $xml = [
  394. 'tags' => [
  395. 'tag' => [
  396. [
  397. 'id' => '1',
  398. 'name' => 'defect'
  399. ],
  400. [
  401. 'id' => '2',
  402. 'name' => 'enhancement'
  403. ]
  404. ]
  405. ]
  406. ];
  407. $expected = <<<XML
  408. <?xml version="1.0" encoding="UTF-8"?>
  409. <tags><tag><id>1</id><name>defect</name></tag><tag><id>2</id><name>enhancement</name></tag></tags>
  410. XML;
  411. $xmlResponse = Xml::fromArray($xml, ['pretty' => false]);
  412. $this->assertTextEquals($expected, $xmlResponse->asXML());
  413. $expected = <<<XML
  414. <?xml version="1.0" encoding="UTF-8"?>
  415. <tags>
  416. <tag>
  417. <id>1</id>
  418. <name>defect</name>
  419. </tag>
  420. <tag>
  421. <id>2</id>
  422. <name>enhancement</name>
  423. </tag>
  424. </tags>
  425. XML;
  426. $xmlResponse = Xml::fromArray($xml, ['pretty' => true]);
  427. $this->assertTextEquals($expected, $xmlResponse->asXML());
  428. $xml = [
  429. 'tags' => [
  430. 'tag' => [
  431. [
  432. 'id' => '1',
  433. 'name' => 'defect'
  434. ],
  435. [
  436. 'id' => '2',
  437. 'name' => 'enhancement'
  438. ]
  439. ]
  440. ]
  441. ];
  442. $expected = <<<XML
  443. <?xml version="1.0" encoding="UTF-8"?>
  444. <tags><tag id="1" name="defect"/><tag id="2" name="enhancement"/></tags>
  445. XML;
  446. $xmlResponse = Xml::fromArray($xml, ['pretty' => false, 'format' => 'attributes']);
  447. $this->assertTextEquals($expected, $xmlResponse->asXML());
  448. $expected = <<<XML
  449. <?xml version="1.0" encoding="UTF-8"?>
  450. <tags>
  451. <tag id="1" name="defect"/>
  452. <tag id="2" name="enhancement"/>
  453. </tags>
  454. XML;
  455. $xmlResponse = Xml::fromArray($xml, ['pretty' => true, 'format' => 'attributes']);
  456. $this->assertTextEquals($expected, $xmlResponse->asXML());
  457. }
  458. /**
  459. * data provider for fromArray() failures
  460. *
  461. * @return array
  462. */
  463. public static function invalidArrayDataProvider()
  464. {
  465. return [
  466. [''],
  467. [null],
  468. [false],
  469. [[]],
  470. [['numeric key as root']],
  471. [['item1' => '', 'item2' => '']],
  472. [['items' => ['item1', 'item2']]],
  473. [[
  474. 'tags' => [
  475. 'tag' => [
  476. [
  477. [
  478. 'string'
  479. ]
  480. ]
  481. ]
  482. ]
  483. ]],
  484. [[
  485. 'tags' => [
  486. '@tag' => [
  487. [
  488. '@id' => '1',
  489. 'name' => 'defect'
  490. ],
  491. [
  492. '@id' => '2',
  493. 'name' => 'enhancement'
  494. ]
  495. ]
  496. ]
  497. ]],
  498. [new \DateTime()]
  499. ];
  500. }
  501. /**
  502. * testFromArrayFail method
  503. *
  504. * @dataProvider invalidArrayDataProvider
  505. * @expectedException \Exception
  506. * @return void
  507. */
  508. public function testFromArrayFail($value)
  509. {
  510. Xml::fromArray($value);
  511. }
  512. /**
  513. * Test that there are not unterminated errors when building xml
  514. *
  515. * @return void
  516. */
  517. public function testFromArrayUnterminatedError()
  518. {
  519. $data = [
  520. 'product_ID' => 'GENERT-DL',
  521. 'deeplink' => 'http://example.com/deep',
  522. 'image_URL' => 'http://example.com/image',
  523. 'thumbnail_image_URL' => 'http://example.com/thumb',
  524. 'brand' => 'Malte Lange & Co',
  525. 'availability' => 'in stock',
  526. 'authors' => [
  527. 'author' => ['Malte Lange & Co']
  528. ]
  529. ];
  530. $xml = Xml::fromArray(['products' => $data], 'tags');
  531. $expected = <<<XML
  532. <?xml version="1.0" encoding="UTF-8"?>
  533. <products>
  534. <product_ID>GENERT-DL</product_ID>
  535. <deeplink>http://example.com/deep</deeplink>
  536. <image_URL>http://example.com/image</image_URL>
  537. <thumbnail_image_URL>http://example.com/thumb</thumbnail_image_URL>
  538. <brand>Malte Lange &amp; Co</brand>
  539. <availability>in stock</availability>
  540. <authors>
  541. <author>Malte Lange &amp; Co</author>
  542. </authors>
  543. </products>
  544. XML;
  545. $this->assertXmlStringEqualsXmlString($expected, $xml->asXML());
  546. }
  547. /**
  548. * testToArray method
  549. *
  550. * @return void
  551. */
  552. public function testToArray()
  553. {
  554. $xml = '<tag>name</tag>';
  555. $obj = Xml::build($xml);
  556. $this->assertEquals(['tag' => 'name'], Xml::toArray($obj));
  557. $xml = CORE_TESTS . 'Fixture/sample.xml';
  558. $obj = Xml::build($xml);
  559. $expected = [
  560. 'tags' => [
  561. 'tag' => [
  562. [
  563. '@id' => '1',
  564. 'name' => 'defect'
  565. ],
  566. [
  567. '@id' => '2',
  568. 'name' => 'enhancement'
  569. ]
  570. ]
  571. ]
  572. ];
  573. $this->assertEquals($expected, Xml::toArray($obj));
  574. $array = [
  575. 'tags' => [
  576. 'tag' => [
  577. [
  578. 'id' => '1',
  579. 'name' => 'defect'
  580. ],
  581. [
  582. 'id' => '2',
  583. 'name' => 'enhancement'
  584. ]
  585. ]
  586. ]
  587. ];
  588. $this->assertEquals(Xml::toArray(Xml::fromArray($array, 'tags')), $array);
  589. $expected = [
  590. 'tags' => [
  591. 'tag' => [
  592. [
  593. '@id' => '1',
  594. '@name' => 'defect'
  595. ],
  596. [
  597. '@id' => '2',
  598. '@name' => 'enhancement'
  599. ]
  600. ]
  601. ]
  602. ];
  603. $this->assertEquals($expected, Xml::toArray(Xml::fromArray($array, 'attributes')));
  604. $this->assertEquals($expected, Xml::toArray(Xml::fromArray($array, ['return' => 'domdocument', 'format' => 'attributes'])));
  605. $this->assertEquals(Xml::toArray(Xml::fromArray($array)), $array);
  606. $this->assertEquals(Xml::toArray(Xml::fromArray($array, ['return' => 'domdocument'])), $array);
  607. $array = [
  608. 'tags' => [
  609. 'tag' => [
  610. 'id' => '1',
  611. 'posts' => [
  612. ['id' => '1'],
  613. ['id' => '2']
  614. ]
  615. ],
  616. 'tagOther' => [
  617. 'subtag' => [
  618. 'id' => '1'
  619. ]
  620. ]
  621. ]
  622. ];
  623. $expected = [
  624. 'tags' => [
  625. 'tag' => [
  626. '@id' => '1',
  627. 'posts' => [
  628. ['@id' => '1'],
  629. ['@id' => '2']
  630. ]
  631. ],
  632. 'tagOther' => [
  633. 'subtag' => [
  634. '@id' => '1'
  635. ]
  636. ]
  637. ]
  638. ];
  639. $this->assertEquals($expected, Xml::toArray(Xml::fromArray($array, 'attributes')));
  640. $this->assertEquals($expected, Xml::toArray(Xml::fromArray($array, ['format' => 'attributes', 'return' => 'domdocument'])));
  641. $xml = <<<XML
  642. <root>
  643. <tag id="1">defect</tag>
  644. </root>
  645. XML;
  646. $obj = Xml::build($xml);
  647. $expected = [
  648. 'root' => [
  649. 'tag' => [
  650. '@id' => 1,
  651. '@' => 'defect'
  652. ]
  653. ]
  654. ];
  655. $this->assertEquals($expected, Xml::toArray($obj));
  656. $xml = <<<XML
  657. <root>
  658. <table xmlns="http://www.w3.org/TR/html4/"><tr><td>Apples</td><td>Bananas</td></tr></table>
  659. <table xmlns="http://www.cakephp.org"><name>CakePHP</name><license>MIT</license></table>
  660. <table>The book is on the table.</table>
  661. </root>
  662. XML;
  663. $obj = Xml::build($xml);
  664. $expected = [
  665. 'root' => [
  666. 'table' => [
  667. ['tr' => ['td' => ['Apples', 'Bananas']]],
  668. ['name' => 'CakePHP', 'license' => 'MIT'],
  669. 'The book is on the table.'
  670. ]
  671. ]
  672. ];
  673. $this->assertEquals($expected, Xml::toArray($obj));
  674. $xml = <<<XML
  675. <root xmlns:cake="http://www.cakephp.org/">
  676. <tag>defect</tag>
  677. <cake:bug>1</cake:bug>
  678. </root>
  679. XML;
  680. $obj = Xml::build($xml);
  681. $expected = [
  682. 'root' => [
  683. 'tag' => 'defect',
  684. 'cake:bug' => 1
  685. ]
  686. ];
  687. $this->assertEquals($expected, Xml::toArray($obj));
  688. $xml = '<tag type="myType">0</tag>';
  689. $obj = Xml::build($xml);
  690. $expected = [
  691. 'tag' => [
  692. '@type' => 'myType',
  693. '@' => 0
  694. ]
  695. ];
  696. $this->assertEquals($expected, Xml::toArray($obj));
  697. }
  698. /**
  699. * testRss
  700. *
  701. * @return void
  702. */
  703. public function testRss()
  704. {
  705. $rss = file_get_contents(CORE_TESTS . 'Fixture/rss.xml');
  706. $rssAsArray = Xml::toArray(Xml::build($rss));
  707. $this->assertEquals('2.0', $rssAsArray['rss']['@version']);
  708. $this->assertEquals(2, count($rssAsArray['rss']['channel']['item']));
  709. $atomLink = ['@href' => 'http://bakery.cakephp.org/articles/rss', '@rel' => 'self', '@type' => 'application/rss+xml'];
  710. $this->assertEquals($rssAsArray['rss']['channel']['atom:link'], $atomLink);
  711. $this->assertEquals('http://bakery.cakephp.org/', $rssAsArray['rss']['channel']['link']);
  712. $expected = [
  713. 'title' => 'Alertpay automated sales via IPN',
  714. 'link' => 'http://bakery.cakephp.org/articles/view/alertpay-automated-sales-via-ipn',
  715. 'description' => 'I\'m going to show you how I implemented a payment module via the Alertpay payment processor.',
  716. 'pubDate' => 'Tue, 31 Aug 2010 01:42:00 -0500',
  717. 'guid' => 'http://bakery.cakephp.org/articles/view/alertpay-automated-sales-via-ipn'
  718. ];
  719. $this->assertSame($expected, $rssAsArray['rss']['channel']['item'][1]);
  720. $rss = [
  721. 'rss' => [
  722. 'xmlns:atom' => 'http://www.w3.org/2005/Atom',
  723. '@version' => '2.0',
  724. 'channel' => [
  725. 'atom:link' => [
  726. '@href' => 'http://bakery.cakephp.org/articles/rss',
  727. '@rel' => 'self',
  728. '@type' => 'application/rss+xml'
  729. ],
  730. 'title' => 'The Bakery: ',
  731. 'link' => 'http://bakery.cakephp.org/',
  732. 'description' => 'Recent Articles at The Bakery.',
  733. 'pubDate' => 'Sun, 12 Sep 2010 04:18:26 -0500',
  734. 'item' => [
  735. [
  736. 'title' => 'CakePHP 1.3.4 released',
  737. 'link' => 'http://bakery.cakephp.org/articles/view/cakephp-1-3-4-released'
  738. ],
  739. [
  740. 'title' => 'Wizard Component 1.2 Tutorial',
  741. 'link' => 'http://bakery.cakephp.org/articles/view/wizard-component-1-2-tutorial'
  742. ]
  743. ]
  744. ]
  745. ]
  746. ];
  747. $rssAsSimpleXML = Xml::fromArray($rss);
  748. $xmlText = <<<XML
  749. <?xml version="1.0" encoding="UTF-8"?>
  750. <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  751. <channel>
  752. <atom:link href="http://bakery.cakephp.org/articles/rss" rel="self" type="application/rss+xml"/>
  753. <title>The Bakery: </title>
  754. <link>http://bakery.cakephp.org/</link>
  755. <description>Recent Articles at The Bakery.</description>
  756. <pubDate>Sun, 12 Sep 2010 04:18:26 -0500</pubDate>
  757. <item>
  758. <title>CakePHP 1.3.4 released</title>
  759. <link>http://bakery.cakephp.org/articles/view/cakephp-1-3-4-released</link>
  760. </item>
  761. <item>
  762. <title>Wizard Component 1.2 Tutorial</title>
  763. <link>http://bakery.cakephp.org/articles/view/wizard-component-1-2-tutorial</link>
  764. </item>
  765. </channel>
  766. </rss>
  767. XML;
  768. $this->assertXmlStringEqualsXmlString($xmlText, $rssAsSimpleXML->asXML());
  769. }
  770. /**
  771. * testXmlRpc
  772. *
  773. * @return void
  774. */
  775. public function testXmlRpc()
  776. {
  777. $xml = Xml::build('<methodCall><methodName>test</methodName><params /></methodCall>');
  778. $expected = [
  779. 'methodCall' => [
  780. 'methodName' => 'test',
  781. 'params' => ''
  782. ]
  783. ];
  784. $this->assertSame($expected, Xml::toArray($xml));
  785. $xml = Xml::build('<methodCall><methodName>test</methodName><params><param><value><array><data><value><int>12</int></value><value><string>Egypt</string></value><value><boolean>0</boolean></value><value><int>-31</int></value></data></array></value></param></params></methodCall>');
  786. $expected = [
  787. 'methodCall' => [
  788. 'methodName' => 'test',
  789. 'params' => [
  790. 'param' => [
  791. 'value' => [
  792. 'array' => [
  793. 'data' => [
  794. 'value' => [
  795. ['int' => '12'],
  796. ['string' => 'Egypt'],
  797. ['boolean' => '0'],
  798. ['int' => '-31']
  799. ]
  800. ]
  801. ]
  802. ]
  803. ]
  804. ]
  805. ]
  806. ];
  807. $this->assertSame($expected, Xml::toArray($xml));
  808. $xmlText = <<<XML
  809. <?xml version="1.0" encoding="UTF-8"?>
  810. <methodResponse>
  811. <params>
  812. <param>
  813. <value>
  814. <array>
  815. <data>
  816. <value>
  817. <int>1</int>
  818. </value>
  819. <value>
  820. <string>testing</string>
  821. </value>
  822. </data>
  823. </array>
  824. </value>
  825. </param>
  826. </params>
  827. </methodResponse>
  828. XML;
  829. $xml = Xml::build($xmlText);
  830. $expected = [
  831. 'methodResponse' => [
  832. 'params' => [
  833. 'param' => [
  834. 'value' => [
  835. 'array' => [
  836. 'data' => [
  837. 'value' => [
  838. ['int' => '1'],
  839. ['string' => 'testing']
  840. ]
  841. ]
  842. ]
  843. ]
  844. ]
  845. ]
  846. ]
  847. ];
  848. $this->assertSame($expected, Xml::toArray($xml));
  849. $xml = Xml::fromArray($expected, 'tags');
  850. $this->assertXmlStringEqualsXmlString($xmlText, $xml->asXML());
  851. }
  852. /**
  853. * testSoap
  854. *
  855. * @return void
  856. */
  857. public function testSoap()
  858. {
  859. $xmlRequest = Xml::build(CORE_TESTS . 'Fixture/soap_request.xml');
  860. $expected = [
  861. 'Envelope' => [
  862. '@soap:encodingStyle' => 'http://www.w3.org/2001/12/soap-encoding',
  863. 'soap:Body' => [
  864. 'm:GetStockPrice' => [
  865. 'm:StockName' => 'IBM'
  866. ]
  867. ]
  868. ]
  869. ];
  870. $this->assertEquals($expected, Xml::toArray($xmlRequest));
  871. $xmlResponse = Xml::build(CORE_TESTS . DS . 'Fixture/soap_response.xml');
  872. $expected = [
  873. 'Envelope' => [
  874. '@soap:encodingStyle' => 'http://www.w3.org/2001/12/soap-encoding',
  875. 'soap:Body' => [
  876. 'm:GetStockPriceResponse' => [
  877. 'm:Price' => '34.5'
  878. ]
  879. ]
  880. ]
  881. ];
  882. $this->assertEquals($expected, Xml::toArray($xmlResponse));
  883. $xml = [
  884. 'soap:Envelope' => [
  885. 'xmlns:soap' => 'http://www.w3.org/2001/12/soap-envelope',
  886. '@soap:encodingStyle' => 'http://www.w3.org/2001/12/soap-encoding',
  887. 'soap:Body' => [
  888. 'xmlns:m' => 'http://www.example.org/stock',
  889. 'm:GetStockPrice' => [
  890. 'm:StockName' => 'IBM'
  891. ]
  892. ]
  893. ]
  894. ];
  895. $xmlRequest = Xml::fromArray($xml, ['encoding' => null]);
  896. $xmlText = <<<XML
  897. <?xml version="1.0"?>
  898. <soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  899. <soap:Body xmlns:m="http://www.example.org/stock">
  900. <m:GetStockPrice><m:StockName>IBM</m:StockName></m:GetStockPrice>
  901. </soap:Body>
  902. </soap:Envelope>
  903. XML;
  904. $this->assertXmlStringEqualsXmlString($xmlText, $xmlRequest->asXML());
  905. }
  906. /**
  907. * testNamespace
  908. *
  909. * @return void
  910. */
  911. public function testNamespace()
  912. {
  913. $xml = <<<XML
  914. <root xmlns:ns="http://cakephp.org">
  915. <ns:tag id="1">
  916. <child>good</child>
  917. <otherchild>bad</otherchild>
  918. </ns:tag>
  919. <tag>Tag without ns</tag>
  920. </root>
  921. XML;
  922. $xmlResponse = Xml::build($xml);
  923. $expected = [
  924. 'root' => [
  925. 'ns:tag' => [
  926. '@id' => '1',
  927. 'child' => 'good',
  928. 'otherchild' => 'bad'
  929. ],
  930. 'tag' => 'Tag without ns'
  931. ]
  932. ];
  933. $this->assertEquals($expected, Xml::toArray($xmlResponse));
  934. $xmlResponse = Xml::build('<root xmlns:ns="http://cakephp.org"><ns:tag id="1" /><tag><id>1</id></tag></root>');
  935. $expected = [
  936. 'root' => [
  937. 'ns:tag' => [
  938. '@id' => '1'
  939. ],
  940. 'tag' => [
  941. 'id' => '1'
  942. ]
  943. ]
  944. ];
  945. $this->assertEquals($expected, Xml::toArray($xmlResponse));
  946. $xmlResponse = Xml::build('<root xmlns:ns="http://cakephp.org"><ns:attr>1</ns:attr></root>');
  947. $expected = [
  948. 'root' => [
  949. 'ns:attr' => '1'
  950. ]
  951. ];
  952. $this->assertEquals($expected, Xml::toArray($xmlResponse));
  953. $xmlResponse = Xml::build('<root><ns:attr xmlns:ns="http://cakephp.org">1</ns:attr></root>');
  954. $this->assertEquals($expected, Xml::toArray($xmlResponse));
  955. $xml = [
  956. 'root' => [
  957. 'ns:attr' => [
  958. 'xmlns:ns' => 'http://cakephp.org',
  959. '@' => 1
  960. ]
  961. ]
  962. ];
  963. $expected = '<' . '?xml version="1.0" encoding="UTF-8"?><root><ns:attr xmlns:ns="http://cakephp.org">1</ns:attr></root>';
  964. $xmlResponse = Xml::fromArray($xml);
  965. $this->assertEquals($expected, str_replace(["\r", "\n"], '', $xmlResponse->asXML()));
  966. $xml = [
  967. 'root' => [
  968. 'tag' => [
  969. 'xmlns:pref' => 'http://cakephp.org',
  970. 'pref:item' => [
  971. 'item 1',
  972. 'item 2'
  973. ]
  974. ]
  975. ]
  976. ];
  977. $expected = <<<XML
  978. <?xml version="1.0" encoding="UTF-8"?>
  979. <root>
  980. <tag xmlns:pref="http://cakephp.org">
  981. <pref:item>item 1</pref:item>
  982. <pref:item>item 2</pref:item>
  983. </tag>
  984. </root>
  985. XML;
  986. $xmlResponse = Xml::fromArray($xml);
  987. $this->assertXmlStringEqualsXmlString($expected, $xmlResponse->asXML());
  988. $xml = [
  989. 'root' => [
  990. 'tag' => [
  991. 'xmlns:' => 'http://cakephp.org'
  992. ]
  993. ]
  994. ];
  995. $expected = '<' . '?xml version="1.0" encoding="UTF-8"?><root><tag xmlns="http://cakephp.org"/></root>';
  996. $xmlResponse = Xml::fromArray($xml);
  997. $this->assertXmlStringEqualsXmlString($expected, $xmlResponse->asXML());
  998. $xml = [
  999. 'root' => [
  1000. 'xmlns:' => 'http://cakephp.org'
  1001. ]
  1002. ];
  1003. $expected = '<' . '?xml version="1.0" encoding="UTF-8"?><root xmlns="http://cakephp.org"/>';
  1004. $xmlResponse = Xml::fromArray($xml);
  1005. $this->assertXmlStringEqualsXmlString($expected, $xmlResponse->asXML());
  1006. $xml = [
  1007. 'root' => [
  1008. 'xmlns:ns' => 'http://cakephp.org'
  1009. ]
  1010. ];
  1011. $expected = '<' . '?xml version="1.0" encoding="UTF-8"?><root xmlns:ns="http://cakephp.org"/>';
  1012. $xmlResponse = Xml::fromArray($xml);
  1013. $this->assertXmlStringEqualsXmlString($expected, $xmlResponse->asXML());
  1014. }
  1015. /**
  1016. * test that CDATA blocks don't get screwed up by SimpleXml
  1017. *
  1018. * @return void
  1019. */
  1020. public function testCdata()
  1021. {
  1022. $xml = '<' . '?xml version="1.0" encoding="UTF-8"?>' .
  1023. '<people><name><![CDATA[ Mark ]]></name></people>';
  1024. $result = Xml::build($xml);
  1025. $this->assertEquals(' Mark ', (string)$result->name);
  1026. }
  1027. /**
  1028. * data provider for toArray() failures
  1029. *
  1030. * @return array
  1031. */
  1032. public static function invalidToArrayDataProvider()
  1033. {
  1034. return [
  1035. [new \DateTime()],
  1036. [[]]
  1037. ];
  1038. }
  1039. /**
  1040. * testToArrayFail method
  1041. *
  1042. * @dataProvider invalidToArrayDataProvider
  1043. * @expectedException \Cake\Utility\Exception\XmlException
  1044. * @return void
  1045. */
  1046. public function testToArrayFail($value)
  1047. {
  1048. Xml::toArray($value);
  1049. }
  1050. /**
  1051. * Test ampersand in text elements.
  1052. *
  1053. * @return void
  1054. */
  1055. public function testAmpInText()
  1056. {
  1057. $data = [
  1058. 'outer' => [
  1059. 'inner' => ['name' => 'mark & mark']
  1060. ]
  1061. ];
  1062. $obj = Xml::build($data);
  1063. $result = $obj->asXml();
  1064. $this->assertContains('mark &amp; mark', $result);
  1065. }
  1066. /**
  1067. * Test that entity loading is disabled by default.
  1068. *
  1069. * @return void
  1070. */
  1071. public function testNoEntityLoading()
  1072. {
  1073. $file = str_replace(' ', '%20', CAKE . 'VERSION.txt');
  1074. $xml = <<<XML
  1075. <!DOCTYPE cakephp [
  1076. <!ENTITY payload SYSTEM "file://$file" >]>
  1077. <request>
  1078. <xxe>&payload;</xxe>
  1079. </request>
  1080. XML;
  1081. $result = Xml::build($xml);
  1082. }
  1083. }