Thrift support for the xsd_nillable attribute

Reviewed By: dave


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664981 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
index 49550b1..06803ec 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.cc
+++ b/compiler/cpp/src/generate/t_xsd_generator.cc
@@ -48,7 +48,7 @@
   indent_up();
   
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_attrs(), (*m_iter)->get_xsd_optional() || xsd_all);
+    generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_attrs(), (*m_iter)->get_xsd_optional() || xsd_all, (*m_iter)->get_xsd_nillable());
   } 
 
   indent_down();
@@ -68,14 +68,16 @@
                                        t_type* ttype,
                                        vector<string> attrs,
                                        bool optional,
+                                       bool nillable,
                                        bool list_element) {
   string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
   string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
   string soptional = sminOccurs + smaxOccurs;
+  string snillable = nillable ? " nillable=\"true\"" : "";
 
   if (ttype->is_void() || ttype->is_list()) {
     indent(out) <<
-      "<xsd:element name=\"" << name << "\"" << soptional << ">" << endl;
+      "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
     indent_up();
     if (attrs.size() == 0 && ttype->is_void()) {
       indent(out) << 
@@ -83,15 +85,8 @@
     } else {
       indent(out) <<
         "<xsd:complexType>" << endl;
-      indent_up();
-      
-      vector<string>::iterator a_iter;
-      for (a_iter = attrs.begin(); a_iter != attrs.end(); ++a_iter) {
-        indent(out) << "<xsd:attribute name=\"" << (*a_iter) << "\" type=\"xsd:boolean\" />" << endl;
-      }
-      
+      indent_up();    
       if (ttype->is_list()) {
-        indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;       
         indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
         indent_up();
         string subname;
@@ -102,9 +97,14 @@
           subname = type_name(subtype);
         }
         f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl;
-        generate_element(out, subname, subtype, vector<string>(), false, true);
+        generate_element(out, subname, subtype, vector<string>(), false, false, true);
         indent_down();
         indent(out) << "</xsd:sequence>" << endl;
+        indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
+      }
+      vector<string>::iterator a_iter;
+      for (a_iter = attrs.begin(); a_iter != attrs.end(); ++a_iter) {
+        indent(out) << "<xsd:attribute name=\"" << (*a_iter) << "\" type=\"xsd:boolean\" />" << endl;
       }
       indent_down();
       indent(out) <<
@@ -116,10 +116,10 @@
   } else {
     if (attrs.size() == 0) {
       indent(out) <<
-        "<xsd:element name=\"" << name << "\"" << soptional << " type=\"" << type_name(ttype) << "\" />" << endl;
+        "<xsd:element name=\"" << name << "\"" << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />" << endl;
     } else {
       // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
-      indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << ">" << endl;
+      indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
       indent_up();
       indent(out) << "<xsd:complexType>" << endl;
       indent_up();
diff --git a/compiler/cpp/src/generate/t_xsd_generator.h b/compiler/cpp/src/generate/t_xsd_generator.h
index 7a60283..21e74fb 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.h
+++ b/compiler/cpp/src/generate/t_xsd_generator.h
@@ -40,7 +40,7 @@
 
  private:
 
-  void generate_element(std::ostream& out, std::string name, t_type* ttype, std::vector<std::string> attrs=std::vector<std::string>(), bool optional=false, bool list_element=false);
+  void generate_element(std::ostream& out, std::string name, t_type* ttype, std::vector<std::string> attrs=std::vector<std::string>(), bool optional=false, bool nillable=false, bool list_element=false);
 
   std::string ns(std::string in, std::string ns) {
     return ns + ":" + in;
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index 090426a..dfa5cac 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -16,14 +16,16 @@
     name_(name),
     key_(0),
     value_(NULL),
-    xsd_optional_(false) {}
+    xsd_optional_(false),
+    xsd_nillable_(false) {}
 
   t_field(t_type* type, std::string name, int32_t key) :
     type_(type),
     name_(name),
     key_(key),
     value_(NULL),
-    xsd_optional_(false) {}
+    xsd_optional_(false),
+    xsd_nillable_(false) {}
 
   ~t_field() {}
 
@@ -55,6 +57,14 @@
     return xsd_optional_;
   }
 
+  void set_xsd_nillable(bool xsd_nillable) {
+    xsd_nillable_ = xsd_nillable;
+  }
+
+  bool get_xsd_nillable() const {
+    return xsd_nillable_;
+  }
+
   void add_xsd_attr(std::string attr) {
     xsd_attrs_.push_back(attr);
   }
@@ -83,6 +93,7 @@
   t_const_value* value_;
 
   bool xsd_optional_;
+  bool xsd_nillable_;
   std::vector<std::string> xsd_attrs_;
 
   std::string doc_;                                           
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index 5486ada..593df10 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -63,6 +63,7 @@
 "php_namespace" { return tok_php_namespace; }
 "xsd_all"       { return tok_xsd_all;       }
 "xsd_optional"  { return tok_xsd_optional;  }
+"xsd_nillable"  { return tok_xsd_nillable;  }
 "xsd_namespace" { return tok_xsd_namespace; }
 "xsd_attrs"     { return tok_xsd_attrs;     }
 "include"       { return tok_include;       }
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index a53d002..c1d383b 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -70,6 +70,7 @@
 %token tok_java_package
 %token tok_xsd_all
 %token tok_xsd_optional
+%token tok_xsd_nillable
 %token tok_xsd_namespace
 %token tok_xsd_attrs
 
@@ -155,6 +156,7 @@
 %type<tbool>     Async
 %type<tbool>     XsdAll
 %type<tbool>     XsdOptional
+%type<tbool>     XsdNillable
 %type<id>        XsdAttributes
 %type<id>        CppType
 
@@ -517,6 +519,16 @@
       $$ = false;
     }
 
+XsdNillable:
+  tok_xsd_nillable
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
 XsdAttributes:
   tok_xsd_attrs tok_identifier
     {
@@ -631,7 +643,7 @@
     }
 
 Field:
-  DocTextOptional FieldIdentifier FieldType tok_identifier FieldValue XsdOptional XsdAttributes CommaOrSemicolonOptional
+  DocTextOptional FieldIdentifier FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes CommaOrSemicolonOptional
     {
       pdebug("tok_int_constant : Field -> FieldType tok_identifier");
       if ($2 < 0) {
@@ -643,11 +655,12 @@
         $$->set_value($5);
       }
       $$->set_xsd_optional($6);
+      $$->set_xsd_nillable($7);
       if ($1 != NULL) {
         $$->set_doc($1);
       }
-      if ($7 != NULL) {
-        $$->add_xsd_attr($7);
+      if ($8 != NULL) {
+        $$->add_xsd_attr($8);
       }
     }