/** * Parses the $xmlContent into a Gadget class * * @param string $xmlContent */ public function parse($xmlContent) { libxml_use_internal_errors(true); $doc = new DOMDocument(); if (!$doc->loadXML($xmlContent, LIBXML_NOCDATA)) { throw new GadgetSpecException("Error parsing gadget xml:\n" . XmlError::getErrors($xmlContent)); } //TODO: we could do a XSD schema validation here, but both the schema and most of the gadgets seem to have some form of schema // violatons, so it's not really practical yet (and slow) // $doc->schemaValidate('gadget.xsd'); $gadget = new GadgetSpec(); $gadget->checksum = md5($xmlContent); $this->parseModulePrefs($doc, $gadget); $this->parseUserPrefs($doc, $gadget); $this->parseViews($doc, $gadget); //TODO: parse pipelined data return $gadget; }
/** * Parses the (remote / fetched) message bundle xml * * @param string $messageBundleData * @return array (MessageBundle) */ protected function parseMessageBundle($messageBundleData) { libxml_use_internal_errors(true); $doc = new DOMDocument(); if (!$doc->loadXML($messageBundleData, LIBXML_NOCDATA)) { throw new GadgetSpecException("Error parsing gadget xml:\n" . XmlError::getErrors($messageBundleData)); } $messageBundle = array(); if (($messageBundleNode = $doc->getElementsByTagName('messagebundle')) != null && $messageBundleNode->length > 0) { $messageBundleNode = $messageBundleNode->item(0); $messages = $messageBundleNode->getElementsByTagName('msg'); foreach ($messages as $msg) { $messageBundle[$msg->getAttribute('name')] = trim($msg->nodeValue); } } return $messageBundle; }
/** * Add a template library set, for details see: * http://opensocial-resources.googlecode.com/svn/spec/0.9/OpenSocial-Templating.xml#rfc.section.13 * * @param string $library */ public function addTemplateLibrary($library) { libxml_use_internal_errors(true); $doc = new DOMDocument(null, 'utf-8'); $doc->preserveWhiteSpace = true; $doc->formatOutput = false; $doc->strictErrorChecking = false; $doc->recover = false; $doc->resolveExternals = false; if (!$doc->loadXML($library)) { throw new ExpressionException("Error parsing template library:\n" . XmlError::getErrors($library)); } // Theoretically this could support multiple <Templates> root nodes, which isn't quite spec, but owell foreach ($doc->childNodes as $rootNode) { $templateNodes = array(); $globalScript = array(); $globalStyle = array(); if (isset($rootNode->tagName) && $rootNode->tagName == 'Templates') { foreach ($rootNode->childNodes as $childNode) { if (isset($childNode->tagName)) { switch ($childNode->tagName) { case 'TemplateDef': $this->addTemplateDef($childNode, $globalScript, $globalStyle); break; case 'Template': $templateNodes[] = $childNode; break; case 'JavaScript': $globalScript[] = new TemplateLibraryContent($childNode->nodeValue); break; case 'Style': $globalStyle[] = new TemplateLibraryContent($childNode->nodeValue); break; } } } } // Initialize the templates after scanning the entire structure so that all scripts and styles will be included with each template foreach ($templateNodes as $templateNode) { $this->addTemplateByNode($templateNode, $globalScript, $globalStyle); } } }
/** * Does the parsing of the template/data script content, then it hands * the os-data parsing to the DataPipeling class, and os-template tags to * the TemplateParser, and then returns the expanded template content (or '' on data) * * @param string $template * @param TemplateLibrary $templateLibrary * @return string */ private function renderTemplate($template, TemplateLibrary $templateLibrary) { libxml_use_internal_errors(true); $this->doc = new DOMDocument(null, 'utf-8'); $this->doc->preserveWhiteSpace = true; $this->doc->formatOutput = false; $this->doc->strictErrorChecking = false; $this->doc->recover = false; $this->doc->resolveExternals = false; if (!$this->doc->loadXML($template)) { return "Error parsing os-template:\n" . XmlError::getErrors($template); } if ($this->doc->childNodes->length < 1 || $this->doc->childNodes->length >> 1) { return 'Invalid script block'; } $childNode = $this->doc->childNodes->item(0); if ($childNode->tagName == 'script' && $childNode->getAttribute('name') == null && $childNode->getAttribute('autoUpdate') != 'true') { // If the require tag is set, check to see if we have all required data parts, and if not leave it to the client to render if (($require = $childNode->getAttribute('require')) != null) { $requires = explode(',', $require); foreach ($requires as $val) { $val = trim($val); if (!isset($this->dataContext[$val])) { return false; } } } // if $childNode->tag exists, add to global $templateLibraries array, else parse normally $childNodeTag = $childNode->getAttribute('tag'); if (!empty($childNodeTag)) { if (isset($this->templateLibraries[$childNode->getAttribute('tag')])) { throw new ExpressionException("Template " . htmlentities($childNode->getAttribute('tag')) . " was already defined"); } $templateLibrary->addTemplateByNode($childNode); } else { // Everything checked out, proceeding to render the template $parser = new TemplateParser(); $parser->process($childNode, $this->dataContext, $templateLibrary); // unwrap the output, ie we only want the script block's content and not the main <script></script> node $output = new DOMDocument(null, 'utf-8'); foreach ($childNode->childNodes as $node) { $outNode = $output->importNode($node, true); $outNode = $output->appendChild($outNode); } // Restore single tags to their html variant, and remove the xml header $ret = str_replace(array('<?xml version="" encoding="utf-8"?>', '<br/>', '<script type="text/javascript"><![CDATA[', ']]></script>'), array('', '<br>', '<script type="text/javascript">', '</script>'), $output->saveXML()); return $ret; } } return false; }