CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 2.0 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.0
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Auth
    • Core
    • Error
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
    • Network
      • Email
      • Http
    • Routing
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper

Classes

  • ClassRegistry
  • Debugger
  • File
  • Folder
  • Inflector
  • ObjectCollection
  • Sanitize
  • Security
  • Set
  • String
  • Validation
  • Xml
  1: <?php
  2: /**
  3:  * XML handling for Cake.
  4:  *
  5:  * The methods in these classes enable the datasources that use XML to work.
  6:  *
  7:  * PHP 5
  8:  *
  9:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 10:  * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 11:  *
 12:  * Licensed under The MIT License
 13:  * Redistributions of files must retain the above copyright notice.
 14:  *
 15:  * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 16:  * @link          http://cakephp.org CakePHP(tm) Project
 17:  * @package       Cake.Utility
 18:  * @since         CakePHP v .0.10.3.1400
 19:  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 20:  */
 21: 
 22: /**
 23:  * XML handling for Cake.
 24:  *
 25:  * The methods in these classes enable the datasources that use XML to work.
 26:  *
 27:  * @package       Cake.Utility
 28:  */
 29: class Xml {
 30: 
 31: /**
 32:  * Initialize SimpleXMLElement or DOMDocument from a given XML string, file path, URL or array.
 33:  *
 34:  * ### Usage:
 35:  *
 36:  * Building XML from a string:
 37:  *
 38:  * `$xml = Xml::build('<example>text</example>');`
 39:  *
 40:  * Building XML from string (output DOMDocument):
 41:  *
 42:  * `$xml = Xml::build('<example>text</example>', array('return' => 'domdocument'));`
 43:  *
 44:  * Building XML from a file path:
 45:  *
 46:  * `$xml = Xml::build('/path/to/an/xml/file.xml');`
 47:  *
 48:  * Building from a remote URL:
 49:  *
 50:  * `$xml = Xml::build('http://example.com/example.xml');`
 51:  *
 52:  * Building from an array:
 53:  *
 54:  * {{{
 55:  *  $value = array(
 56:  *      'tags' => array(
 57:  *          'tag' => array(
 58:  *              array(
 59:  *                  'id' => '1',
 60:  *                  'name' => 'defect'
 61:  *              ),
 62:  *              array(
 63:  *                  'id' => '2',
 64:  *                  'name' => 'enhancement'
 65:  *              )
 66:  *          )
 67:  *      )
 68:  *  );
 69:  * $xml = Xml::build($value);
 70:  * }}}
 71:  *
 72:  * When building XML from an array ensure that there is only one top level element.
 73:  *
 74:  * ### Options
 75:  *
 76:  * - `return` Can be 'simplexml' to return object of SimpleXMLElement or 'domdocument' to return DOMDocument.
 77:  * - If using array as input, you can pass `options` from Xml::fromArray.
 78:  *
 79:  * @param mixed $input XML string, a path to a file, an URL or an array
 80:  * @param array $options The options to use
 81:  * @return SimpleXMLElement|DOMDocument SimpleXMLElement or DOMDocument
 82:  * @throws XmlException
 83:  */
 84:     public static function build($input, $options = array()) {
 85:         if (!is_array($options)) {
 86:             $options = array('return' => (string)$options);
 87:         }
 88:         $defaults = array(
 89:             'return' => 'simplexml'
 90:         );
 91:         $options = array_merge($defaults, $options);
 92: 
 93:         if (is_array($input) || is_object($input)) {
 94:             return self::fromArray((array)$input, $options);
 95:         } elseif (strpos($input, '<') !== false) {
 96:             if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
 97:                 return new SimpleXMLElement($input, LIBXML_NOCDATA);
 98:             }
 99:             $dom = new DOMDocument();
100:             $dom->loadXML($input);
101:             return $dom;
102:         } elseif (file_exists($input) || strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) {
103:             if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
104:                 return new SimpleXMLElement($input, LIBXML_NOCDATA, true);
105:             }
106:             $dom = new DOMDocument();
107:             $dom->load($input);
108:             return $dom;
109:         } elseif (!is_string($input)) {
110:             throw new XmlException(__d('cake_dev', 'Invalid input.'));
111:         }
112:         throw new XmlException(__d('cake_dev', 'XML cannot be read.'));
113:     }
114: 
115: /**
116:  * Transform an array into a SimpleXMLElement
117:  *
118:  * ### Options
119:  *
120:  * - `format` If create childs ('tags') or attributes ('attribute').
121:  * - `version` Version of XML document. Default is 1.0.
122:  * - `encoding` Encoding of XML document. If null remove from XML header. Default is the some of application.
123:  * - `return` If return object of SimpleXMLElement ('simplexml') or DOMDocument ('domdocument'). Default is SimpleXMLElement.
124:  *
125:  * Using the following data:
126:  *
127:  * {{{
128:  * $value = array(
129:  *    'root' => array(
130:  *        'tag' => array(
131:  *            'id' => 1,
132:  *            'value' => 'defect',
133:  *            '@' => 'description'
134:  *         )
135:  *     )
136:  * );
137:  * }}}
138:  *
139:  * Calling `Xml::fromArray($value, 'tags');`  Will generate:
140:  *
141:  * `<root><tag><id>1</id><value>defect</value>description</tag></root>`
142:  *
143:  * And calling `Xml::fromArray($value, 'attribute');` Will generate:
144:  *
145:  * `<root><tag id="1" value="defect">description</tag></root>`
146:  *
147:  * @param array $input Array with data
148:  * @param array $options The options to use
149:  * @return SimpleXMLElement|DOMDocument SimpleXMLElement or DOMDocument
150:  * @throws XmlException
151:  */
152:     public static function fromArray($input, $options = array()) {
153:         if (!is_array($input) || count($input) !== 1) {
154:             throw new XmlException(__d('cake_dev', 'Invalid input.'));
155:         }
156:         $key = key($input);
157:         if (is_integer($key)) {
158:             throw new XmlException(__d('cake_dev', 'The key of input must be alphanumeric'));
159:         }
160: 
161:         if (!is_array($options)) {
162:             $options = array('format' => (string)$options);
163:         }
164:         $defaults = array(
165:             'format' => 'tags',
166:             'version' => '1.0',
167:             'encoding' => Configure::read('App.encoding'),
168:             'return' => 'simplexml'
169:         );
170:         $options = array_merge($defaults, $options);
171: 
172:         $dom = new DOMDocument($options['version'], $options['encoding']);
173:         self::_fromArray($dom, $dom, $input, $options['format']);
174: 
175:         $options['return'] = strtolower($options['return']);
176:         if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
177:             return new SimpleXMLElement($dom->saveXML());
178:         }
179:         return $dom;
180:     }
181: 
182: /**
183:  * Recursive method to create childs from array
184:  *
185:  * @param DOMDocument $dom Handler to DOMDocument
186:  * @param DOMElement $node Handler to DOMElement (child)
187:  * @param array $data Array of data to append to the $node.
188:  * @param string $format Either 'attribute' or 'tags'.  This determines where nested keys go.
189:  * @return void
190:  * @throws XmlException
191:  */
192:     protected static function _fromArray($dom, $node, &$data, $format) {
193:         if (empty($data) || !is_array($data)) {
194:             return;
195:         }
196:         foreach ($data as $key => $value) {
197:             if (is_string($key)) {
198:                 if (!is_array($value)) {
199:                     if (is_bool($value)) {
200:                         $value = (int)$value;
201:                     } elseif ($value === null) {
202:                         $value = '';
203:                     }
204:                     $isNamespace = strpos($key, 'xmlns:');
205:                     if ($isNamespace !== false) {
206:                         $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $key, $value);
207:                         continue;
208:                     }
209:                     if ($key[0] !== '@' && $format === 'tags') {
210:                         $child = null;
211:                         if (!is_numeric($value)) {
212:                             // Escape special characters
213:                             // http://www.w3.org/TR/REC-xml/#syntax
214:                             // https://bugs.php.net/bug.php?id=36795
215:                             $child = $dom->createElement($key, '');
216:                             $child->appendChild(new DOMText($value));
217:                         } else {
218:                             $child = $dom->createElement($key, $value);
219:                         }
220:                         $node->appendChild($child);
221:                     } else {
222:                         if ($key[0] === '@') {
223:                             $key = substr($key, 1);
224:                         }
225:                         $attribute = $dom->createAttribute($key);
226:                         $attribute->appendChild($dom->createTextNode($value));
227:                         $node->appendChild($attribute);
228:                     }
229:                 } else {
230:                     if ($key[0] === '@') {
231:                         throw new XmlException(__d('cake_dev', 'Invalid array'));
232:                     }
233:                     if (array_keys($value) === range(0, count($value) - 1)) { // List
234:                         foreach ($value as $item) {
235:                             $data = compact('dom', 'node', 'key', 'format');
236:                             $data['value'] = $item;
237:                             self::_createChild($data);
238:                         }
239:                     } else { // Struct
240:                         self::_createChild(compact('dom', 'node', 'key', 'value', 'format'));
241:                     }
242:                 }
243:             } else {
244:                 throw new XmlException(__d('cake_dev', 'Invalid array'));
245:             }
246:         }
247:     }
248: 
249: /**
250:  * Helper to _fromArray(). It will create childs of arrays
251:  *
252:  * @param array $data Array with informations to create childs
253:  * @return void
254:  */
255:     protected static function _createChild($data) {
256:         extract($data);
257:         $childNS = $childValue = null;
258:         if (is_array($value)) {
259:             if (isset($value['@'])) {
260:                 $childValue = (string)$value['@'];
261:                 unset($value['@']);
262:             }
263:             if (isset($value['xmlns:'])) {
264:                 $childNS = $value['xmlns:'];
265:                 unset($value['xmlns:']);
266:             }
267:         } elseif (!empty($value) || $value === 0) {
268:             $childValue = (string)$value;
269:         }
270: 
271:         if ($childValue) {
272:             $child = $dom->createElement($key, $childValue);
273:         } else {
274:             $child = $dom->createElement($key);
275:         }
276:         if ($childNS) {
277:             $child->setAttribute('xmlns', $childNS);
278:         }
279: 
280:         self::_fromArray($dom, $child, $value, $format);
281:         $node->appendChild($child);
282:     }
283: 
284: /**
285:  * Returns this XML structure as a array.
286:  *
287:  * @param SimpleXMLElement|DOMDocument|DOMNode $obj SimpleXMLElement, DOMDocument or DOMNode instance
288:  * @return array Array representation of the XML structure.
289:  * @throws XmlException
290:  */
291:     public static function toArray($obj) {
292:         if ($obj instanceof DOMNode) {
293:             $obj = simplexml_import_dom($obj);
294:         }
295:         if (!($obj instanceof SimpleXMLElement)) {
296:             throw new XmlException(__d('cake_dev', 'The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.'));
297:         }
298:         $result = array();
299:         $namespaces = array_merge(array('' => ''), $obj->getNamespaces(true));
300:         self::_toArray($obj, $result, '', array_keys($namespaces));
301:         return $result;
302:     }
303: 
304: /**
305:  * Recursive method to toArray
306:  *
307:  * @param SimpleXMLElement $xml SimpleXMLElement object
308:  * @param array $parentData Parent array with data
309:  * @param string $ns Namespace of current child
310:  * @param array $namespaces List of namespaces in XML
311:  * @return void
312:  */
313:     protected static function _toArray($xml, &$parentData, $ns, $namespaces) {
314:         $data = array();
315: 
316:         foreach ($namespaces as $namespace) {
317:             foreach ($xml->attributes($namespace, true) as $key => $value) {
318:                 if (!empty($namespace)) {
319:                     $key = $namespace . ':' . $key;
320:                 }
321:                 $data['@' . $key] = (string)$value;
322:             }
323: 
324:             foreach ($xml->children($namespace, true) as $child) {
325:                 self::_toArray($child, $data, $namespace, $namespaces);
326:             }
327:         }
328: 
329:         $asString = trim((string)$xml);
330:         if (empty($data)) {
331:             $data = $asString;
332:         } elseif (!empty($asString)) {
333:             $data['@'] = $asString;
334:         }
335: 
336:         if (!empty($ns)) {
337:             $ns .= ':';
338:         }
339:         $name = $ns . $xml->getName();
340:         if (isset($parentData[$name])) {
341:             if (!is_array($parentData[$name]) || !isset($parentData[$name][0])) {
342:                 $parentData[$name] = array($parentData[$name]);
343:             }
344:             $parentData[$name][] = $data;
345:         } else {
346:             $parentData[$name] = $data;
347:         }
348:     }
349: 
350: }
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs