web/lib/Zend/Feed/Element.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * Zend Framework
       
     5  *
       
     6  * LICENSE
       
     7  *
       
     8  * This source file is subject to the new BSD license that is bundled
       
     9  * with this package in the file LICENSE.txt.
       
    10  * It is also available through the world-wide-web at this URL:
       
    11  * http://framework.zend.com/license/new-bsd
       
    12  * If you did not receive a copy of the license and are unable to
       
    13  * obtain it through the world-wide-web, please send an email
       
    14  * to license@zend.com so we can send you a copy immediately.
       
    15  *
       
    16  * @category   Zend
       
    17  * @package    Zend_Feed
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: Element.php 20104 2010-01-06 21:26:01Z matthew $
       
    21  */
       
    22 
       
    23 
       
    24 /**
       
    25  * Wraps a DOMElement allowing for SimpleXML-like access to attributes.
       
    26  *
       
    27  * @category   Zend
       
    28  * @package    Zend_Feed
       
    29  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    30  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    31  */
       
    32 class Zend_Feed_Element implements ArrayAccess
       
    33 {
       
    34 
       
    35     /**
       
    36      * @var DOMElement
       
    37      */
       
    38     protected $_element;
       
    39 
       
    40     /**
       
    41      * @var string Character encoding to utilize
       
    42      */
       
    43     protected $_encoding = 'UTF-8';
       
    44 
       
    45     /**
       
    46      * @var Zend_Feed_Element
       
    47      */
       
    48     protected $_parentElement;
       
    49 
       
    50     /**
       
    51      * @var boolean
       
    52      */
       
    53     protected $_appended = true;
       
    54 
       
    55 
       
    56     /**
       
    57      * Zend_Feed_Element constructor.
       
    58      *
       
    59      * @param  DOMElement $element The DOM element we're encapsulating.
       
    60      * @return void
       
    61      */
       
    62     public function __construct($element = null)
       
    63     {
       
    64         $this->_element = $element;
       
    65     }
       
    66 
       
    67 
       
    68     /**
       
    69      * Get a DOM representation of the element
       
    70      *
       
    71      * Returns the underlying DOM object, which can then be
       
    72      * manipulated with full DOM methods.
       
    73      *
       
    74      * @return DOMDocument
       
    75      */
       
    76     public function getDOM()
       
    77     {
       
    78         return $this->_element;
       
    79     }
       
    80 
       
    81 
       
    82     /**
       
    83      * Update the object from a DOM element
       
    84      *
       
    85      * Take a DOMElement object, which may be originally from a call
       
    86      * to getDOM() or may be custom created, and use it as the
       
    87      * DOM tree for this Zend_Feed_Element.
       
    88      *
       
    89      * @param  DOMElement $element
       
    90      * @return void
       
    91      */
       
    92     public function setDOM(DOMElement $element)
       
    93     {
       
    94         $this->_element = $this->_element->ownerDocument->importNode($element, true);
       
    95     }
       
    96 
       
    97     /**
       
    98      * Set the parent element of this object to another
       
    99      * Zend_Feed_Element.
       
   100      *
       
   101      * @param  Zend_Feed_Element $element
       
   102      * @return void
       
   103      */
       
   104     public function setParent(Zend_Feed_Element $element)
       
   105     {
       
   106         $this->_parentElement = $element;
       
   107         $this->_appended = false;
       
   108     }
       
   109 
       
   110 
       
   111     /**
       
   112      * Appends this element to its parent if necessary.
       
   113      *
       
   114      * @return void
       
   115      */
       
   116     protected function ensureAppended()
       
   117     {
       
   118         if (!$this->_appended) {
       
   119             $this->_parentElement->getDOM()->appendChild($this->_element);
       
   120             $this->_appended = true;
       
   121             $this->_parentElement->ensureAppended();
       
   122         }
       
   123     }
       
   124 
       
   125 
       
   126     /**
       
   127      * Get an XML string representation of this element
       
   128      *
       
   129      * Returns a string of this element's XML, including the XML
       
   130      * prologue.
       
   131      *
       
   132      * @return string
       
   133      */
       
   134     public function saveXml()
       
   135     {
       
   136         // Return a complete document including XML prologue.
       
   137         $doc = new DOMDocument($this->_element->ownerDocument->version,
       
   138                                $this->_element->ownerDocument->actualEncoding);
       
   139         $doc->appendChild($doc->importNode($this->_element, true));
       
   140         return $doc->saveXML();
       
   141     }
       
   142 
       
   143 
       
   144     /**
       
   145      * Get the XML for only this element
       
   146      *
       
   147      * Returns a string of this element's XML without prologue.
       
   148      *
       
   149      * @return string
       
   150      */
       
   151     public function saveXmlFragment()
       
   152     {
       
   153         return $this->_element->ownerDocument->saveXML($this->_element);
       
   154     }
       
   155 
       
   156     /**
       
   157      * Get encoding
       
   158      *
       
   159      * @return string
       
   160      */
       
   161     public function getEncoding()
       
   162     {
       
   163         return $this->_encoding;
       
   164     }
       
   165 
       
   166     /**
       
   167      * Set encoding
       
   168      *
       
   169      * @param  string $value Encoding to use
       
   170      * @return Zend_Feed_Element
       
   171      */
       
   172     public function setEncoding($value)
       
   173     {
       
   174         $this->_encoding = (string) $value;
       
   175         return $this;
       
   176     }
       
   177 
       
   178     /**
       
   179      * Map variable access onto the underlying entry representation.
       
   180      *
       
   181      * Get-style access returns a Zend_Feed_Element representing the
       
   182      * child element accessed. To get string values, use method syntax
       
   183      * with the __call() overriding.
       
   184      *
       
   185      * @param  string $var The property to access.
       
   186      * @return mixed
       
   187      */
       
   188     public function __get($var)
       
   189     {
       
   190         $nodes = $this->_children($var);
       
   191         $length = count($nodes);
       
   192 
       
   193         if ($length == 1) {
       
   194             return new Zend_Feed_Element($nodes[0]);
       
   195         } elseif ($length > 1) {
       
   196             return array_map(create_function('$e', 'return new Zend_Feed_Element($e);'), $nodes);
       
   197         } else {
       
   198             // When creating anonymous nodes for __set chaining, don't
       
   199             // call appendChild() on them. Instead we pass the current
       
   200             // element to them as an extra reference; the child is
       
   201             // then responsible for appending itself when it is
       
   202             // actually set. This way "if ($foo->bar)" doesn't create
       
   203             // a phantom "bar" element in our tree.
       
   204             if (strpos($var, ':') !== false) {
       
   205                 list($ns, $elt) = explode(':', $var, 2);
       
   206                 $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns), $elt);
       
   207             } else {
       
   208                 $node = $this->_element->ownerDocument->createElement($var);
       
   209             }
       
   210             $node = new self($node);
       
   211             $node->setParent($this);
       
   212             return $node;
       
   213         }
       
   214     }
       
   215 
       
   216 
       
   217     /**
       
   218      * Map variable sets onto the underlying entry representation.
       
   219      *
       
   220      * @param  string $var The property to change.
       
   221      * @param  string $val The property's new value.
       
   222      * @return void
       
   223      * @throws Zend_Feed_Exception
       
   224      */
       
   225     public function __set($var, $val)
       
   226     {
       
   227         $this->ensureAppended();
       
   228 
       
   229         $nodes = $this->_children($var);
       
   230         if (!$nodes) {
       
   231             if (strpos($var, ':') !== false) {
       
   232                 list($ns, $elt) = explode(':', $var, 2);
       
   233                 $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns),
       
   234                     $var, htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding()));
       
   235                 $this->_element->appendChild($node);
       
   236             } else {
       
   237                 $node = $this->_element->ownerDocument->createElement($var,
       
   238                     htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding()));
       
   239                 $this->_element->appendChild($node);
       
   240             }
       
   241         } elseif (count($nodes) > 1) {
       
   242             /**
       
   243              * @see Zend_Feed_Exception
       
   244              */
       
   245             require_once 'Zend/Feed/Exception.php';
       
   246             throw new Zend_Feed_Exception('Cannot set the value of multiple tags simultaneously.');
       
   247         } else {
       
   248             $nodes[0]->nodeValue = $val;
       
   249         }
       
   250     }
       
   251 
       
   252 
       
   253     /**
       
   254      * Map isset calls onto the underlying entry representation.
       
   255      *
       
   256      * @param  string $var
       
   257      * @return boolean
       
   258      */
       
   259     public function __isset($var)
       
   260     {
       
   261         // Look for access of the form {ns:var}. We don't use
       
   262         // _children() here because we can break out of the loop
       
   263         // immediately once we find something.
       
   264         if (strpos($var, ':') !== false) {
       
   265             list($ns, $elt) = explode(':', $var, 2);
       
   266             foreach ($this->_element->childNodes as $child) {
       
   267                 if ($child->localName == $elt && $child->prefix == $ns) {
       
   268                     return true;
       
   269                 }
       
   270             }
       
   271         } else {
       
   272             foreach ($this->_element->childNodes as $child) {
       
   273                 if ($child->localName == $var) {
       
   274                     return true;
       
   275                 }
       
   276             }
       
   277         }
       
   278     }
       
   279 
       
   280 
       
   281     /**
       
   282      * Get the value of an element with method syntax.
       
   283      *
       
   284      * Map method calls to get the string value of the requested
       
   285      * element. If there are multiple elements that match, this will
       
   286      * return an array of those objects.
       
   287      *
       
   288      * @param  string $var    The element to get the string value of.
       
   289      * @param  mixed  $unused This parameter is not used.
       
   290      * @return mixed The node's value, null, or an array of nodes.
       
   291      */
       
   292     public function __call($var, $unused)
       
   293     {
       
   294         $nodes = $this->_children($var);
       
   295 
       
   296         if (!$nodes) {
       
   297             return null;
       
   298         } elseif (count($nodes) > 1) {
       
   299             return $nodes;
       
   300         } else {
       
   301             return $nodes[0]->nodeValue;
       
   302         }
       
   303     }
       
   304 
       
   305 
       
   306     /**
       
   307      * Remove all children matching $var.
       
   308      *
       
   309      * @param  string $var
       
   310      * @return void
       
   311      */
       
   312     public function __unset($var)
       
   313     {
       
   314         $nodes = $this->_children($var);
       
   315         foreach ($nodes as $node) {
       
   316             $parent = $node->parentNode;
       
   317             $parent->removeChild($node);
       
   318         }
       
   319     }
       
   320 
       
   321 
       
   322     /**
       
   323      * Returns the nodeValue of this element when this object is used
       
   324      * in a string context.
       
   325      *
       
   326      * @return string
       
   327      */
       
   328     public function __toString()
       
   329     {
       
   330         return $this->_element->nodeValue;
       
   331     }
       
   332 
       
   333 
       
   334     /**
       
   335      * Finds children with tagnames matching $var
       
   336      *
       
   337      * Similar to SimpleXML's children() method.
       
   338      *
       
   339      * @param  string $var Tagname to match, can be either namespace:tagName or just tagName.
       
   340      * @return array
       
   341      */
       
   342     protected function _children($var)
       
   343     {
       
   344         $found = array();
       
   345 
       
   346         // Look for access of the form {ns:var}.
       
   347         if (strpos($var, ':') !== false) {
       
   348             list($ns, $elt) = explode(':', $var, 2);
       
   349             foreach ($this->_element->childNodes as $child) {
       
   350                 if ($child->localName == $elt && $child->prefix == $ns) {
       
   351                     $found[] = $child;
       
   352                 }
       
   353             }
       
   354         } else {
       
   355             foreach ($this->_element->childNodes as $child) {
       
   356                 if ($child->localName == $var) {
       
   357                     $found[] = $child;
       
   358                 }
       
   359             }
       
   360         }
       
   361 
       
   362         return $found;
       
   363     }
       
   364 
       
   365 
       
   366     /**
       
   367      * Required by the ArrayAccess interface.
       
   368      *
       
   369      * @param  string $offset
       
   370      * @return boolean
       
   371      */
       
   372     public function offsetExists($offset)
       
   373     {
       
   374         if (strpos($offset, ':') !== false) {
       
   375             list($ns, $attr) = explode(':', $offset, 2);
       
   376             return $this->_element->hasAttributeNS(Zend_Feed::lookupNamespace($ns), $attr);
       
   377         } else {
       
   378             return $this->_element->hasAttribute($offset);
       
   379         }
       
   380     }
       
   381 
       
   382 
       
   383     /**
       
   384      * Required by the ArrayAccess interface.
       
   385      *
       
   386      * @param  string $offset
       
   387      * @return string
       
   388      */
       
   389     public function offsetGet($offset)
       
   390     {
       
   391         if (strpos($offset, ':') !== false) {
       
   392             list($ns, $attr) = explode(':', $offset, 2);
       
   393             return $this->_element->getAttributeNS(Zend_Feed::lookupNamespace($ns), $attr);
       
   394         } else {
       
   395             return $this->_element->getAttribute($offset);
       
   396         }
       
   397     }
       
   398 
       
   399 
       
   400     /**
       
   401      * Required by the ArrayAccess interface.
       
   402      *
       
   403      * @param  string $offset
       
   404      * @param  string $value
       
   405      * @return string
       
   406      */
       
   407     public function offsetSet($offset, $value)
       
   408     {
       
   409         $this->ensureAppended();
       
   410 
       
   411         if (strpos($offset, ':') !== false) {
       
   412             list($ns, $attr) = explode(':', $offset, 2);
       
   413             // DOMElement::setAttributeNS() requires $qualifiedName to have a prefix
       
   414             return $this->_element->setAttributeNS(Zend_Feed::lookupNamespace($ns), $offset, $value);
       
   415         } else {
       
   416             return $this->_element->setAttribute($offset, $value);
       
   417         }
       
   418     }
       
   419 
       
   420 
       
   421     /**
       
   422      * Required by the ArrayAccess interface.
       
   423      *
       
   424      * @param  string $offset
       
   425      * @return boolean
       
   426      */
       
   427     public function offsetUnset($offset)
       
   428     {
       
   429         if (strpos($offset, ':') !== false) {
       
   430             list($ns, $attr) = explode(':', $offset, 2);
       
   431             return $this->_element->removeAttributeNS(Zend_Feed::lookupNamespace($ns), $attr);
       
   432         } else {
       
   433             return $this->_element->removeAttribute($offset);
       
   434         }
       
   435     }
       
   436 
       
   437 }