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;
   }
-
 }