You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by ch...@apache.org on 2009/07/29 01:56:18 UTC
svn commit: r798729 - in /incubator/shindig/trunk/php/src/gadgets/templates:
DataPipelining.php ExpressionParser.php TemplateLibrary.php
TemplateParser.php
Author: chabotc
Date: Tue Jul 28 23:56:18 2009
New Revision: 798729
URL: http://svn.apache.org/viewvc?rev=798729&view=rev
Log:
Various fixes to os-templates and osml parsing, main remaining issue turned out to be an issue with the DOMNodeList, if you remove a node while iterating on it it tends to blow up and generate random garbage, doh
Modified:
incubator/shindig/trunk/php/src/gadgets/templates/DataPipelining.php
incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php
incubator/shindig/trunk/php/src/gadgets/templates/TemplateLibrary.php
incubator/shindig/trunk/php/src/gadgets/templates/TemplateParser.php
Modified: incubator/shindig/trunk/php/src/gadgets/templates/DataPipelining.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/templates/DataPipelining.php?rev=798729&r1=798728&r2=798729&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/templates/DataPipelining.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/templates/DataPipelining.php Tue Jul 28 23:56:18 2009
@@ -18,6 +18,8 @@
* under the License.
*/
+require_once 'ExpressionParser.php';
+
//TODO verify os:HttpRequest
class DataPipelining {
@@ -160,6 +162,9 @@
unset($request['key']);
unset($request['method']);
unset($request['type']);
+ if (isset($request['fields'])) {
+ $request['fields'] = explode(',', $request['fields']);
+ }
$jsonRequests[] = array('method' => $method, 'id' => $id, 'params' => $request);
break;
case 'os:HttpRequest':
Modified: incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php?rev=798729&r1=798728&r2=798729&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php Tue Jul 28 23:56:18 2009
@@ -127,7 +127,10 @@
}
if (! $found) {
// variable wasn't found in Cur, My and Top scope, throw an error
- throw new ExpressionException("Unknown variable: " . htmlentities($var) . ($var != $key ? " ($key)" : ''));
+ // throw new ExpressionException("Unknown variable: " . htmlentities($var) . ($var != $key ? " ($key)" : ''));
+
+ //FIXME: OSML templates seem to be build on the assumption that an non-existing var returns NULL, double check if that's how it should be
+ return null;
}
return $context;
}
Modified: incubator/shindig/trunk/php/src/gadgets/templates/TemplateLibrary.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/templates/TemplateLibrary.php?rev=798729&r1=798728&r2=798729&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/templates/TemplateLibrary.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/templates/TemplateLibrary.php Tue Jul 28 23:56:18 2009
@@ -1,5 +1,4 @@
<?php
-
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -28,7 +27,7 @@
* </Require>
*/
class TemplateLibrary {
- private $osmlTags = array('os:Name', 'os:PeopleSelector', 'os:badge');
+ private $osmlTags = array('os:Name', 'os:PeopleSelector', 'os:Badge');
private $templates = array();
private $osmlLoaded = false;
private $gadgetContext;
@@ -39,8 +38,13 @@
public function parseTemplate($tag, $caller) {
$template = $this->getTemplate($tag);
- if ($template->dom instanceof DOMElement) {
+ if ($template->dom) {
$templateDomCopy = new DOMDocument(null, 'utf-8');
+ $templateDomCopy->preserveWhiteSpace = true;
+ $templateDomCopy->formatOutput = false;
+ $templateDomCopy->strictErrorChecking = false;
+ $templateDomCopy->recover = false;
+ $templateDomCopy->resolveExternals = false;
// If this template pulls in any new style and/or javascript, add those to the document
if ($style = $template->getStyle()) {
$styleNode = $templateDomCopy->createElement('style');
@@ -54,12 +58,18 @@
$templateDomCopy->appendChild($scriptNode);
}
// Copy the DOM structure since parseNode() modifies the DOM structure directly
+ $removeNodes = array();
foreach ($template->dom->childNodes as $node) {
- $importedNode = $templateDomCopy->importNode($node, true);
- $templateDomCopy->appendChild($importedNode);
+ $newNode = $templateDomCopy->importNode($node, true);
+ $newNode = $templateDomCopy->appendChild($newNode);
+ // Parse the template's DOM using our current data context (which includes the My context for templates)
+ if (($removeNode = $caller->parseNode($newNode)) !== false) {
+ $removeNodes[] = $removeNode;
+ }
}
- // Parse the template's DOM using our current data context (which includes the My context for templates)
- $caller->parseNode($templateDomCopy);
+ foreach ($removeNodes as $removeNode) {
+ $removeNode->parentNode->removeChild($removeNode);
+ }
return $templateDomCopy;
}
return false;
@@ -111,7 +121,7 @@
}
// Initialize the templates after scanning the entire structure so that all scripts and styles will be included with each template
foreach ($templateNodes as $templateNode) {
- $templateNode->setAttribute('tag', $tag);
+ $templateNode->setAttribute('tag', $tag);
$this->addTemplateByNode($templateNode, $globalScript, $globalStyle);
}
}
@@ -136,8 +146,8 @@
// 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();
+ $globalScript = array();
+ $globalStyle = array();
if (isset($rootNode->tagName) && $rootNode->tagName == 'Templates') {
foreach ($rootNode->childNodes as $childNode) {
if (isset($childNode->tagName)) {
Modified: incubator/shindig/trunk/php/src/gadgets/templates/TemplateParser.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/templates/TemplateParser.php?rev=798729&r1=798728&r2=798729&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/templates/TemplateParser.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/templates/TemplateParser.php Tue Jul 28 23:56:18 2009
@@ -21,16 +21,30 @@
//TODO os:repeat (and <foo repeat="" var="">) has a var="foo" param that hasn't been implmemented yet
//TODO for some reason the OSML spec stats you have to <Require feature="osml"> to use the os:Name etc tags yet no such feature exists, and for the code path's here it's not required at all..
//TODO remove the os-templates javascript if all the templates are rendered on the server (saves many Kb's in gadget size)
-//TODO support for OSML tags (os:name, os:peopleselector, os:badge) and OSML functions (os:render, osx:flash, osx:parsejson, etc)
+//TODO support for OSML tag functions and extensions (os:render, osx:flash, osx:parsejson, etc)
//TODO support os-template tags on OSML tags, ie this should work: <os:Html if="${Foo}" repeat="${Bar}" />
-
require_once 'ExpressionParser.php';
class TemplateParser {
private $dataContext;
private $templateLibrary;
+ public function dumpNode($node, $function) {
+ $doc = new DOMDocument(null, 'utf-8');
+ $doc->preserveWhiteSpace = true;
+ $doc->formatOutput = false;
+ $doc->strictErrorChecking = false;
+ $doc->recover = false;
+ $doc->resolveExternals = false;
+ if (! $newNode = @$doc->importNode($node, false)) {
+ echo "[Invalid node, dump failed]<br><br>";
+ return;
+ }
+ $doc->appendChild($newNode);
+ echo "<b>$function (" . get_class($node) . "):</b><br>" . htmlentities(str_replace('<?xml version="" encoding="utf-8"?>', '', $doc->saveXML()) . "\n") . "<br><br>";
+ }
+
/**
* Processes an os-template
*
@@ -40,7 +54,9 @@
$this->setDataContext($dataContext);
$this->templateLibrary = $templateLibrary;
if ($osTemplate instanceof DOMElement) {
- $this->parseNode($osTemplate);
+ if (($removeNode = $this->parseNode($osTemplate)) !== false) {
+ $removeNode->parentNode->removeChild($removeNode);
+ }
}
}
@@ -58,22 +74,24 @@
}
public function parseNode(DOMNode &$node) {
+ $removeNode = false;
if ($node instanceof DOMText) {
- if (! $node->isWhitespaceInElementContent() && ! empty($node->wholeText)) {
+ if (! $node->isWhitespaceInElementContent() && ! empty($node->nodeValue)) {
$this->parseNodeText($node);
}
} else {
$tagName = isset($node->tagName) ? $node->tagName : '';
if (substr($tagName, 0, 3) == 'os:' || substr($tagName, 0, 4) == 'osx:') {
- $this->parseOsmlNode($node);
+ $removeNode = $this->parseOsmlNode($node);
} elseif ($this->templateLibrary->hasTemplate($tagName)) {
// the tag name refers to an existing template (myapp:EmployeeCard type naming)
// the extra check on the : character is to make sure this is a name spaced custom tag and not some one trying to override basic html tags (br, img, etc)
$this->parseLibrary($tagName, $node);
} else {
- $this->parseNodeAttributes($node);
+ $removeNode = $this->parseNodeAttributes($node);
}
}
+ return is_object($removeNode) ? $removeNode : false;
}
/**
@@ -117,12 +135,11 @@
$this->dataContext['My'] = $myContext;
$ret = $this->templateLibrary->parseTemplate($tagName, $this);
$this->dataContext['My'] = $previousMy;
-
if ($ret) {
// And replace the node with the parsed output
$ownerDocument = $node->ownerDocument;
foreach ($ret->childNodes as $childNode) {
- if ($childNode instanceof DOMElement) {
+ if ($childNode) {
$importedNode = $ownerDocument->importNode($childNode, true);
$node->parentNode->insertBefore($importedNode, $node);
}
@@ -132,7 +149,7 @@
}
private function parseNodeText(DOMText &$node) {
- if (strpos($node->wholeText, '${') !== false) {
+ if (strpos($node->nodeValue, '${') !== false) {
$expressions = array();
preg_match_all('/(\$\{)(.*)(\})/imsxU', $node->wholeText, $expressions);
for ($i = 0; $i < count($expressions[0]); $i ++) {
@@ -140,7 +157,7 @@
$expression = $expressions[2][$i];
$expressionResult = ExpressionParser::evaluate($expression, $this->dataContext);
$stringVal = htmlentities(ExpressionParser::stringValue($expressionResult), ENT_QUOTES, 'UTF-8');
- $node->nodeValue = str_replace($toReplace, $stringVal, $node->wholeText);
+ $node->nodeValue = str_replace($toReplace, $stringVal, $node->nodeValue);
}
}
}
@@ -177,18 +194,18 @@
$this->parseNode($newNode, true);
}
// Remove the original (unparsed) node
- $node->parentNode->removeChild($node);
// And remove the loop data context entries
$this->dataContext['Cur'] = array();
unset($this->dataContext['Context']['Index']);
unset($this->dataContext['Context']['Count']);
- return;
+ return $node;
break;
case 'if':
if (! $expressionResult) {
- $node->parentNode->removeChild($node);
- return; // Since this node is removed, no sense in evaluating it's other attributes and/or child nodes
+ return $node;
+ } else {
+ $node->removeAttribute('if');
}
break;
@@ -244,11 +261,21 @@
}
// if a repeat attribute was found, don't recurse on it's child nodes, the repeat handling already did that
if (isset($node->childNodes) && $node->childNodes->length > 0) {
+ $removeNodes = array();
// recursive loop to all this node's children
foreach ($node->childNodes as $childNode) {
- $this->parseNode($childNode);
+ if (($removeNode = $this->parseNode($childNode)) !== false) {
+ $removeNodes[] = $removeNode;
+ }
+ }
+ if (count($removeNodes)) {
+ foreach ($removeNodes as $removeNode) {
+ $removeNode->parentNode->removeChild($removeNode);
+ }
}
+
}
+ return false;
}
/**
@@ -260,8 +287,7 @@
$tagName = strtolower($node->tagName);
switch ($tagName) {
- // Control statements
-
+ /****** Control statements ******/
case 'os:repeat':
if (! $node->getAttribute('expression')) {
@@ -281,8 +307,8 @@
$this->dataContext['Context']['Index'] = $index;
foreach ($node->childNodes as $childNode) {
$newNode = $childNode->cloneNode(true);
+ $newNode = $node->parentNode->insertBefore($newNode, $node);
$this->parseNode($newNode);
- $node->parentNode->insertBefore($newNode, $node);
}
}
$node->parentNode->removeChild($node);
@@ -297,39 +323,34 @@
throw new ExpressionException("Invalid os:If tag, missing condition attribute");
}
preg_match_all('/(\$\{)(.*)(\})/imsxU', $node->getAttribute('condition'), $expressions);
+ if (! count($expressions[2])) {
+ throw new ExpressionException("Invalid os:If tag, missing condition expression");
+ }
$expression = $expressions[2][0];
$expressionResult = ExpressionParser::evaluate($expression, $this->dataContext);
if ($expressionResult) {
foreach ($node->childNodes as $childNode) {
$newNode = $childNode->cloneNode(true);
$this->parseNode($newNode);
- $node->insertBefore($newNode);
+ $newNode = $node->parentNode->insertBefore($newNode, $node);
}
}
- $node->parentNode->removeChild($node);
+ return $node;
break;
- // OSML tags (os: name space)
-
+ /****** OSML tags (os: name space) ******/
case 'os:name':
$this->parseLibrary('os:Name', $node);
break;
case 'os:badge':
- $myContext = $this->nodeAttributesToScope();
- $previousMy = $this->dataContext['My'];
- $this->dataContext['My'] = $myContext;
- $ret = $this->templateLibrary->parseTemplate('os:Badge', $this);
- $this->dataContext['My'] = $previousMy;
+ $this->parseLibrary('os:Badge', $node);
break;
case 'os:peopleselector':
- $myContext = $this->nodeAttributesToScope();
- $previousMy = $this->dataContext['My'];
- $this->dataContext['My'] = $myContext;
- $ret = $this->templateLibrary->parseTemplate('os:PeopleSelector', $this);
- $this->dataContext['My'] = $previousMy;
+ $this->parseLibrary('os:PeopleSelector', $node);
+
break;
case 'os:html':
@@ -342,8 +363,7 @@
case 'os:render':
break;
- // Extension - Tags
-
+ /****** Extension - Tags ******/
case 'osx:flash':
break;
@@ -354,8 +374,7 @@
case 'osx:navigatetoperson':
break;
- // Extension - Functions
-
+ /****** Extension - Functions ******/
case 'osx:parsejson':
break;
@@ -368,8 +387,7 @@
case 'osx:urldecode':
break;
-
}
+ return false;
}
-
}