/**
  * Returns the concatenated elements of opt:value
  *
  * @internal
  * @param Opt_Xml_Element $node The node to scan.
  * @param array $params The node parameters.
  * @return array
  */
 private function _getValuePairs(Opt_Xml_Element $node, array $params)
 {
     // The more sophisticated behaviour.
     $tags = $node->getElementsByTagNameNS('opt', 'value', false);
     $pairs = new SplQueue();
     $else = null;
     if (isset($params['value'])) {
         $else = $params['value'];
     }
     // Pack the tags into the PHP code.
     foreach ($tags as $tag) {
         if ($tag->countChildren() > 1) {
             throw new Opt_InvalidValue_Exception('opt:value');
         }
         if (!($content = $tag->getLastChild()) instanceof Opt_Xml_Text) {
             throw new Opt_InvalidValue_Exception('opt:value');
         }
         // Concatenate the tag content into an expression
         $code = array();
         foreach ($content as $items) {
             if ($items instanceof Opt_Xml_Cdata) {
                 $code[] = '\'' . (string) $items . '\'';
             } elseif ($items instanceof Opt_Xml_Expression) {
                 $result = $this->_compiler->compileExpression($items->getExpression(), false, Opt_Compiler_Class::ESCAPE_OFF);
                 $code[] = $result[0];
             }
         }
         $code = $this->_compiler->escape(implode('.', $code));
         // Decide, what to do (final alternative or not...)
         if (($condition = $tag->getAttribute('test')) === null) {
             if ($else !== null) {
                 throw new Opt_AttributeNotDefined_Exception('test', 'opt:value');
             }
             $else = $code;
         } else {
             $result = $this->_compiler->compileExpression($condition, true, Opt_Compiler_Class::ESCAPE_OFF);
             $pairs->enqueue(array($result[0], $code));
         }
     }
     return array($pairs, $else);
 }
 /**
  * The common processing part of the dynamically and statically
  * deployed components. Returns the compiled PHP code ready to
  * be appended to the XML tag. The caller must generate a component
  * variable name that will be used in the generated code to refer
  * to the component object. Furthermore, he must pass the results
  * of _extractAttributes() method: both the $params array and the
  * returned values.
  *
  * @internal
  * @param Opt_Xml_Element $node The node with the component data.
  * @param string $componentVariable The PHP component variable name.
  * @param array $params The array of standard component attributes.
  * @param array $args The array of custom component attributes.
  * @return string
  */
 private function _commonProcessing(Opt_Xml_Element $node, $componentVariable, array $params, array $args)
 {
     // Common part of the component processing
     $set2 = array();
     if (!is_null($params['template'])) {
         // Scan for opt:set tags - they may contain some custom arguments.
         $set2 = $node->getElementsByTagNameNS('opt', 'set');
         // Now a little trick - how to cheat the opt:insert instruction
         $attribute = new Opt_Xml_Attribute('opt:use', $params['template']);
         $this->_compiler->processor('snippet')->processAttribute($node, $attribute);
     }
     // Find all the important component elements
     // Remember that some opt:set tags may have been found above and are located in $set2 array.
     $everything = $this->_find($node);
     $everything[0] = array_merge($everything[0], $set2);
     $code = '';
     // opt:set
     foreach ($everything[0] as $set) {
         $tagParams = array('name' => array(self::REQUIRED, self::EXPRESSION), 'value' => array(self::REQUIRED, self::EXPRESSION));
         $this->_extractAttributes($set, $tagParams);
         $code .= $componentVariable . '->set(' . $tagParams['name'] . ', ' . $tagParams['value'] . '); ';
     }
     foreach ($args as $name => $value) {
         $code .= $componentVariable . '->set(\'' . $name . '\', ' . $value . '); ';
     }
     // com:* and opt:component-attributes
     foreach ($everything[1] as $wtf) {
         $id = null;
         if ($wtf->getNamespace() == 'com') {
             $wtf->setNamespace(NULL);
             $subCode = ' $out = ' . $componentVariable . '->manageAttributes(\'' . $wtf->getName() . '\', array(';
         } else {
             $id = $wtf->getAttribute('opt:component-attributes')->getValue();
             $subCode = ' $out = ' . $componentVariable . '->manageAttributes(\'' . $wtf->getName() . '#' . $id . '\', array(';
         }
         foreach ($wtf->getAttributes() as $attribute) {
             $params = array('__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null));
             $vars = $this->_extractAttributes($wtf, $params);
             foreach ($vars as $name => $value) {
                 $subCode .= '\'' . $name . '\' => ' . $value . ',';
             }
         }
         $wtf->removeAttributes();
         $wtf->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $subCode . ')); ');
         $wtf->addAfter(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES, ' if(is_array($out)){ foreach($out as $name=>$value){ echo \' \'.$name.\'="\'.$value.\'"\'; } } ');
     }
     $node->set('postprocess', true);
     if (isset($attribute)) {
         $node->set('_componentTemplate', $attribute);
     }
     $this->_process($node);
     return $code;
 }
 /**
  * An utility method that cleans the contents of the section node, by
  * moving the alternative section (opt:sectionelse etc. tags) code to the end
  * of the children list.
  *
  * In the parameters, we must specify the name and the namespace of the
  * tags that will be treated as the alternative content tags.
  *
  * @param Opt_Xml_Element $node The section node
  * @param String $ns The namespace
  * @param String $name The alternative section content tag name
  */
 protected function _sortSectionContents(Opt_Xml_Element $node, $ns, $name)
 {
     $else = $node->getElementsByTagNameNS($ns, $name, false);
     if (sizeof($else) == 1) {
         if (!$node->hasAttributes()) {
             throw new Opt_InstructionTooManyItems_Exception($ns . ':' . $name, $node->getXmlName(), 'Zero');
         }
         $node->bringToEnd($else[0]);
     } elseif (sizeof($else) > 1) {
         throw new Opt_InstructionTooManyItems_Exception($ns . ':' . $name, $node->getXmlName(), 'Zero or one');
     }
 }