File indexing completed on 2024-12-22 05:36:40
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-web at this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_Feed 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * Wraps a DOMElement allowing for SimpleXML-like access to attributes. 0026 * 0027 * @category Zend 0028 * @package Zend_Feed 0029 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0030 * @license http://framework.zend.com/license/new-bsd New BSD License 0031 */ 0032 class Zend_Feed_Element implements ArrayAccess 0033 { 0034 0035 /** 0036 * @var DOMElement 0037 */ 0038 protected $_element; 0039 0040 /** 0041 * @var string Character encoding to utilize 0042 */ 0043 protected $_encoding = 'UTF-8'; 0044 0045 /** 0046 * @var Zend_Feed_Element 0047 */ 0048 protected $_parentElement; 0049 0050 /** 0051 * @var boolean 0052 */ 0053 protected $_appended = true; 0054 0055 0056 /** 0057 * Zend_Feed_Element constructor. 0058 * 0059 * @param DOMElement $element The DOM element we're encapsulating. 0060 * @return void 0061 */ 0062 public function __construct($element = null) 0063 { 0064 $this->_element = $element; 0065 } 0066 0067 0068 /** 0069 * Get a DOM representation of the element 0070 * 0071 * Returns the underlying DOM object, which can then be 0072 * manipulated with full DOM methods. 0073 * 0074 * @return DOMDocument 0075 */ 0076 public function getDOM() 0077 { 0078 return $this->_element; 0079 } 0080 0081 0082 /** 0083 * Update the object from a DOM element 0084 * 0085 * Take a DOMElement object, which may be originally from a call 0086 * to getDOM() or may be custom created, and use it as the 0087 * DOM tree for this Zend_Feed_Element. 0088 * 0089 * @param DOMElement $element 0090 * @return void 0091 */ 0092 public function setDOM(DOMElement $element) 0093 { 0094 $this->_element = $this->_element->ownerDocument->importNode($element, true); 0095 } 0096 0097 /** 0098 * Set the parent element of this object to another 0099 * Zend_Feed_Element. 0100 * 0101 * @param Zend_Feed_Element $element 0102 * @return void 0103 */ 0104 public function setParent(Zend_Feed_Element $element) 0105 { 0106 $this->_parentElement = $element; 0107 $this->_appended = false; 0108 } 0109 0110 0111 /** 0112 * Appends this element to its parent if necessary. 0113 * 0114 * @return void 0115 */ 0116 protected function ensureAppended() 0117 { 0118 if (!$this->_appended) { 0119 $this->_parentElement->getDOM()->appendChild($this->_element); 0120 $this->_appended = true; 0121 $this->_parentElement->ensureAppended(); 0122 } 0123 } 0124 0125 0126 /** 0127 * Get an XML string representation of this element 0128 * 0129 * Returns a string of this element's XML, including the XML 0130 * prologue. 0131 * 0132 * @return string 0133 */ 0134 public function saveXml() 0135 { 0136 // Return a complete document including XML prologue. 0137 $doc = new DOMDocument($this->_element->ownerDocument->version, 0138 $this->_element->ownerDocument->actualEncoding); 0139 $doc->appendChild($doc->importNode($this->_element, true)); 0140 return $doc->saveXML(); 0141 } 0142 0143 0144 /** 0145 * Get the XML for only this element 0146 * 0147 * Returns a string of this element's XML without prologue. 0148 * 0149 * @return string 0150 */ 0151 public function saveXmlFragment() 0152 { 0153 return $this->_element->ownerDocument->saveXML($this->_element); 0154 } 0155 0156 /** 0157 * Get encoding 0158 * 0159 * @return string 0160 */ 0161 public function getEncoding() 0162 { 0163 return $this->_encoding; 0164 } 0165 0166 /** 0167 * Set encoding 0168 * 0169 * @param string $value Encoding to use 0170 * @return Zend_Feed_Element 0171 */ 0172 public function setEncoding($value) 0173 { 0174 $this->_encoding = (string) $value; 0175 return $this; 0176 } 0177 0178 /** 0179 * Map variable access onto the underlying entry representation. 0180 * 0181 * Get-style access returns a Zend_Feed_Element representing the 0182 * child element accessed. To get string values, use method syntax 0183 * with the __call() overriding. 0184 * 0185 * @param string $var The property to access. 0186 * @return mixed 0187 */ 0188 public function __get($var) 0189 { 0190 $nodes = $this->_children($var); 0191 $length = count($nodes); 0192 0193 if ($length == 1) { 0194 return new Zend_Feed_Element($nodes[0]); 0195 } elseif ($length > 1) { 0196 return array_map(create_function('$e', 'return new Zend_Feed_Element($e);'), $nodes); 0197 } else { 0198 // When creating anonymous nodes for __set chaining, don't 0199 // call appendChild() on them. Instead we pass the current 0200 // element to them as an extra reference; the child is 0201 // then responsible for appending itself when it is 0202 // actually set. This way "if ($foo->bar)" doesn't create 0203 // a phantom "bar" element in our tree. 0204 if (strpos($var, ':') !== false) { 0205 list($ns, $elt) = explode(':', $var, 2); 0206 $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns), $elt); 0207 } else { 0208 $node = $this->_element->ownerDocument->createElement($var); 0209 } 0210 $node = new self($node); 0211 $node->setParent($this); 0212 return $node; 0213 } 0214 } 0215 0216 0217 /** 0218 * Map variable sets onto the underlying entry representation. 0219 * 0220 * @param string $var The property to change. 0221 * @param string $val The property's new value. 0222 * @return void 0223 * @throws Zend_Feed_Exception 0224 */ 0225 public function __set($var, $val) 0226 { 0227 $this->ensureAppended(); 0228 0229 $nodes = $this->_children($var); 0230 if (!$nodes) { 0231 if (strpos($var, ':') !== false) { 0232 list($ns, $elt) = explode(':', $var, 2); 0233 $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns), 0234 $var, htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding())); 0235 $this->_element->appendChild($node); 0236 } else { 0237 $node = $this->_element->ownerDocument->createElement($var, 0238 htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding())); 0239 $this->_element->appendChild($node); 0240 } 0241 } elseif (count($nodes) > 1) { 0242 /** 0243 * @see Zend_Feed_Exception 0244 */ 0245 // require_once 'Zend/Feed/Exception.php'; 0246 throw new Zend_Feed_Exception('Cannot set the value of multiple tags simultaneously.'); 0247 } else { 0248 $nodes[0]->nodeValue = $val; 0249 } 0250 } 0251 0252 0253 /** 0254 * Map isset calls onto the underlying entry representation. 0255 * 0256 * @param string $var 0257 * @return boolean 0258 */ 0259 public function __isset($var) 0260 { 0261 // Look for access of the form {ns:var}. We don't use 0262 // _children() here because we can break out of the loop 0263 // immediately once we find something. 0264 if (strpos($var, ':') !== false) { 0265 list($ns, $elt) = explode(':', $var, 2); 0266 foreach ($this->_element->childNodes as $child) { 0267 if ($child->localName == $elt && $child->prefix == $ns) { 0268 return true; 0269 } 0270 } 0271 } else { 0272 foreach ($this->_element->childNodes as $child) { 0273 if ($child->localName == $var) { 0274 return true; 0275 } 0276 } 0277 } 0278 } 0279 0280 0281 /** 0282 * Get the value of an element with method syntax. 0283 * 0284 * Map method calls to get the string value of the requested 0285 * element. If there are multiple elements that match, this will 0286 * return an array of those objects. 0287 * 0288 * @param string $var The element to get the string value of. 0289 * @param mixed $unused This parameter is not used. 0290 * @return mixed The node's value, null, or an array of nodes. 0291 */ 0292 public function __call($var, $unused) 0293 { 0294 $nodes = $this->_children($var); 0295 0296 if (!$nodes) { 0297 return null; 0298 } elseif (count($nodes) > 1) { 0299 return $nodes; 0300 } else { 0301 return $nodes[0]->nodeValue; 0302 } 0303 } 0304 0305 0306 /** 0307 * Remove all children matching $var. 0308 * 0309 * @param string $var 0310 * @return void 0311 */ 0312 public function __unset($var) 0313 { 0314 $nodes = $this->_children($var); 0315 foreach ($nodes as $node) { 0316 $parent = $node->parentNode; 0317 $parent->removeChild($node); 0318 } 0319 } 0320 0321 0322 /** 0323 * Returns the nodeValue of this element when this object is used 0324 * in a string context. 0325 * 0326 * @return string 0327 */ 0328 public function __toString() 0329 { 0330 return $this->_element->nodeValue; 0331 } 0332 0333 0334 /** 0335 * Finds children with tagnames matching $var 0336 * 0337 * Similar to SimpleXML's children() method. 0338 * 0339 * @param string $var Tagname to match, can be either namespace:tagName or just tagName. 0340 * @return array 0341 */ 0342 protected function _children($var) 0343 { 0344 $found = array(); 0345 0346 // Look for access of the form {ns:var}. 0347 if (strpos($var, ':') !== false) { 0348 list($ns, $elt) = explode(':', $var, 2); 0349 foreach ($this->_element->childNodes as $child) { 0350 if ($child->localName == $elt && $child->prefix == $ns) { 0351 $found[] = $child; 0352 } 0353 } 0354 } else { 0355 foreach ($this->_element->childNodes as $child) { 0356 if ($child->localName == $var) { 0357 $found[] = $child; 0358 } 0359 } 0360 } 0361 0362 return $found; 0363 } 0364 0365 0366 /** 0367 * Required by the ArrayAccess interface. 0368 * 0369 * @param string $offset 0370 * @return boolean 0371 */ 0372 public function offsetExists($offset) 0373 { 0374 if (strpos($offset, ':') !== false) { 0375 list($ns, $attr) = explode(':', $offset, 2); 0376 return $this->_element->hasAttributeNS(Zend_Feed::lookupNamespace($ns), $attr); 0377 } else { 0378 return $this->_element->hasAttribute($offset); 0379 } 0380 } 0381 0382 0383 /** 0384 * Required by the ArrayAccess interface. 0385 * 0386 * @param string $offset 0387 * @return string 0388 */ 0389 public function offsetGet($offset) 0390 { 0391 if (strpos($offset, ':') !== false) { 0392 list($ns, $attr) = explode(':', $offset, 2); 0393 return $this->_element->getAttributeNS(Zend_Feed::lookupNamespace($ns), $attr); 0394 } else { 0395 return $this->_element->getAttribute($offset); 0396 } 0397 } 0398 0399 0400 /** 0401 * Required by the ArrayAccess interface. 0402 * 0403 * @param string $offset 0404 * @param string $value 0405 * @return string 0406 */ 0407 public function offsetSet($offset, $value) 0408 { 0409 $this->ensureAppended(); 0410 0411 if (strpos($offset, ':') !== false) { 0412 list($ns, $attr) = explode(':', $offset, 2); 0413 // DOMElement::setAttributeNS() requires $qualifiedName to have a prefix 0414 return $this->_element->setAttributeNS(Zend_Feed::lookupNamespace($ns), $offset, $value); 0415 } else { 0416 return $this->_element->setAttribute($offset, $value); 0417 } 0418 } 0419 0420 0421 /** 0422 * Required by the ArrayAccess interface. 0423 * 0424 * @param string $offset 0425 * @return boolean 0426 */ 0427 public function offsetUnset($offset) 0428 { 0429 if (strpos($offset, ':') !== false) { 0430 list($ns, $attr) = explode(':', $offset, 2); 0431 return $this->_element->removeAttributeNS(Zend_Feed::lookupNamespace($ns), $attr); 0432 } else { 0433 return $this->_element->removeAttribute($offset); 0434 } 0435 } 0436 0437 }