Base template for loops on a single multimap.
authorcantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Tue, 10 Mar 2009 19:23:57 +0000 (19:23 +0000)
committercantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Tue, 10 Mar 2009 19:23:57 +0000 (19:23 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/branches/REL_1@569 de75baf8-a10c-0410-a50a-987c0e22f00f

xmltooling/util/TemplateEngine.cpp
xmltooling/util/TemplateEngine.h
xmltoolingtest/TemplateEngineTest.h
xmltoolingtest/data/template.in
xmltoolingtest/data/template.out

index 2333c8c..4a165d5 100644 (file)
 using namespace xmltooling;
 using namespace std;
 
+namespace {
+    static const pair<string,string> emptyPair;
+}
+
 void TemplateEngine::setTagPrefix(const char* tagPrefix)
 {
     keytag = string("<") + tagPrefix + " ";
@@ -94,6 +98,7 @@ void TemplateEngine::process(
     const char*& lastpos,
     ostream& os,
     const TemplateParameters& parameters,
+    const std::pair<std::string,std::string>& loopentry,
     const XMLToolingException* e
     ) const
 {
@@ -120,11 +125,17 @@ void TemplateEngine::process(
                 string key = buf.substr(lastpos-line, thispos-lastpos);
                 trimspace(key);
 
-                const char* p = parameters.getParameter(key.c_str());
-                if (!p && e)
-                    p = e->getProperty(key.c_str());
-                if (p)
-                    html_encode(os,p);
+                if (key == "$name" && !loopentry.first.empty())
+                    html_encode(os,loopentry.first.c_str());
+                else if (key == "$value" && !loopentry.second.empty())
+                    html_encode(os,loopentry.second.c_str());
+                else {
+                    const char* p = parameters.getParameter(key.c_str());
+                    if (!p && e)
+                        p = e->getProperty(key.c_str());
+                    if (p)
+                        html_encode(os,p);
+                }
                 lastpos = thispos + 2; // strlen("/>")
             }
         }
@@ -145,7 +156,7 @@ void TemplateEngine::process(
                 if (visible)
                     cond = parameters.getParameter(key.c_str()) || (e && e->getProperty(key.c_str()));
                 lastpos = thispos + 1; // strlen(">")
-                process(cond, buf, lastpos, os, parameters, e);
+                process(cond, buf, lastpos, os, parameters, loopentry, e);
             }
         }
 #ifdef HAVE_STRCASECMP
@@ -175,7 +186,7 @@ void TemplateEngine::process(
                 if (visible)
                     cond = !(parameters.getParameter(key.c_str()) || (e && e->getProperty(key.c_str())));
                 lastpos = thispos + 1; // strlen(">")
-                process(cond, buf, lastpos, os, parameters, e);
+                process(cond, buf, lastpos, os, parameters, loopentry, e);
             }
         }
 #ifdef HAVE_STRCASECMP
@@ -207,20 +218,17 @@ void TemplateEngine::process(
                 lastpos = thispos + 1; // strlen(">")
             }
 
-            const vector<TemplateParameters>& forParams = parameters.getParameterCollection(key.c_str());
-            vector<TemplateParameters>::size_type forend = forParams.size();
-            if (forend == 0) {  // have to go through at least once to match end tags
-               cond = false;
-               forend = 1;
+            const multimap<string,string>* forParams = parameters.getLoopCollection(key.c_str());
+            if (!forParams || forParams->size() == 0) {
+                process(false, buf, lastpos, os, parameters, emptyPair, e);
             }
-
-            const char *savlastpos = lastpos;
-            for (vector<TemplateParameters>::size_type i=0; i<forend; ++i) {
-                static TemplateParameters nullp;
-                lastpos = savlastpos;
-                process(cond, buf, lastpos, os, (forParams.size()>0 ? forParams[i] : nullp), e);
+            else {
+                const char* savlastpos = lastpos;
+                for (multimap<string,string>::const_iterator i=forParams->begin(); i!=forParams->end(); ++i) {
+                    lastpos = savlastpos;
+                    process(cond, buf, lastpos, os, parameters, *i, e);
+                }
             }
-
         }
 
 #ifdef HAVE_STRCASECMP
@@ -252,5 +260,5 @@ void TemplateEngine::run(istream& is, ostream& os, const TemplateParameters& par
         buf += line + '\n';
 
     const char* pos=buf.c_str();
-    process(true, buf, pos, os, parameters, e);
+    process(true, buf, pos, os, parameters, emptyPair, e);
 }
index 4023b52..eba0689 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright 2001-2009 Internet2
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -16,7 +16,7 @@
 
 /**
  * @file xmltooling/util/TemplateEngine.h
- * 
+ *
  * Simple template replacement engine.
  */
 
@@ -44,8 +44,10 @@ namespace xmltooling {
      *  <li> &lt;mlpif key&gt; stuff &lt;/mlpif&gt;</li>
      *  <li> &lt;mlpifnot key&gt; stuff &lt;/mlpifnot&gt;</li>
      *  <li> &lt;mlpfor key&gt; stuff &lt;/mlpfor&gt;</li>
+     *  <li> &lt;mlp $name/&gt; (in for loop only) </li>
+     *  <li> &lt;mlp $value/&gt; (in for loop only) </li>
      * </ul>
-     * 
+     *
      * The default tag prefix is "mlp". This can be overridden for
      * compatibility.
      */
@@ -54,18 +56,18 @@ namespace xmltooling {
         MAKE_NONCOPYABLE(TemplateEngine);
     public:
         TemplateEngine() {
-            setTagPrefix("mlp"); 
+            setTagPrefix("mlp");
         }
 
         virtual ~TemplateEngine() {}
-        
+
         /**
          * Sets the tag name to use when locating template replacement tags.
-         * 
+         *
          * @param tagPrefix base prefix for tags
          */
         void setTagPrefix(const char* tagPrefix);
-        
+
         /**
          * Interface to parameters to plug into templates.
          * Allows callers to supply a more dynamic lookup mechanism to supplement a basic map.
@@ -75,17 +77,19 @@ namespace xmltooling {
         public:
             TemplateParameters() : m_request(NULL) {}
             virtual ~TemplateParameters() {}
-            
+
             /** Map of known parameters to supply to template. */
             std::map<std::string,std::string> m_map;
-            std::map<std::string,std::vector<TemplateParameters> > m_collectionMap;
-            
+
+            /** Map of sub-collections used in for loops. */
+            std::map< std::string,std::multimap<std::string,std::string> > m_collectionMap;
+
             /** Request from client that resulted in template being processed. */
             const GenericRequest* m_request;
-            
+
             /**
              * Returns the value of a parameter to plug into the template.
-             * 
+             *
              * @param name  name of parameter
              * @return value of parameter, or NULL
              */
@@ -95,21 +99,21 @@ namespace xmltooling {
             }
 
             /**
-             * Returns the collection of parameters to plug into the template.
-             * 
-             * @param name  name of parameter collection
-             * @return vector of parameters
+             * Returns a named collection of sub-parameters to pass into a loop.
+             *
+             * @param name  name of sub-collection
+             * @return pointer to a multimap of sub-parameters, or NULL
              */
-            virtual const std::vector<TemplateParameters>& getParameterCollection(const char* name) const {
-                std::map<std::string,std::vector<TemplateParameters> >::const_iterator i=m_collectionMap.find(name);
-                return (i->second);
+            virtual const std::multimap<std::string,std::string>* getLoopCollection(const char* name) const {
+                std::map< std::string,std::multimap<std::string,std::string> >::const_iterator i=m_collectionMap.find(name);
+                return (i!=m_collectionMap.end() ? &(i->second) : NULL);
             }
         };
-        
+
         /**
          * Processes template from an input stream and executes replacements and
-         * conditional logic based on parameters. 
-         * 
+         * conditional logic based on parameters.
+         *
          * @param is            input stream providing template
          * @param os            output stream to send results of executing template
          * @param parameters    parameters to plug into template
@@ -137,9 +141,10 @@ namespace xmltooling {
             const char*& lastpos,
             std::ostream& os,
             const TemplateParameters& parameters,
+            const std::pair<std::string,std::string>& loopentry,
             const XMLToolingException* e
             ) const;
-            
+
         std::string keytag,iftag,ifendtag,ifnottag,ifnotendtag,fortag,forendtag;
     };
 };
index ae7c40c..169def6 100644 (file)
@@ -35,6 +35,9 @@ public:
         p.m_map["foo1"] = "bar1";
         p.m_map["foo3"] = "bar3";
         p.m_map["encoded"] = "http://www.example.org/foo/bar#foobar";
+        multimap<string,string>& submap = p.m_collectionMap["sub"];
+        submap.insert(pair<string,string>("subfoo1", "subbar1"));
+        submap.insert(pair<string,string>("subfoo2", "subbar2"));
         
         string path = data_path + "template.in";
         ifstream in(path.c_str());
index 793812e..08c86c7 100644 (file)
@@ -13,3 +13,7 @@ This is a template containing tags for substitution by the template engine.
 </mlpif>
 
 <mlp encoded/>
+
+<mlpfor sub>
+    <mlp $name/> <mlp foo1/> <mlp $value/>
+</mlpfor>
index 2eb8e9f..0929086 100644 (file)
@@ -13,3 +13,9 @@ bar3
 
 
 http&#58;//www.example.org/foo/bar&#35;foobar
+
+
+    subfoo1 bar1 subbar1
+
+    subfoo2 bar1 subbar2
+