r1317@opsdev009 (orig r70384): mcslee | 2007-11-16 16:32:36 -0800
[amiethrift.git] / compiler / cpp / src / generate / t_xsd_generator.cc
blob04645d2e1181fdd92b67cf8e7bc3bb768e758cb6
1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
3 //
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <sstream>
10 #include "t_xsd_generator.h"
11 using namespace std;
13 void t_xsd_generator::init_generator() {
14 // Make output directory
15 mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
17 // Make output file
18 string f_php_name = get_out_dir()+program_->get_name()+"_xsd.php";
19 f_php_.open(f_php_name.c_str());
21 f_php_ <<
22 "<?php" << endl;
26 void t_xsd_generator::close_generator() {
27 f_php_ << "?>" << endl;
28 f_php_.close();
31 void t_xsd_generator::generate_typedef(t_typedef* ttypedef) {
32 indent(s_xsd_types_) <<
33 "<xsd:simpleType name=\"" << ttypedef->get_name() << "\">" << endl;
34 indent_up();
35 if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) {
36 indent(s_xsd_types_) <<
37 "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">" << endl;
38 indent_up();
39 const vector<string>& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals();
40 vector<string>::const_iterator v_iter;
41 for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) {
42 indent(s_xsd_types_) <<
43 "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
45 indent_down();
46 indent(s_xsd_types_) <<
47 "</xsd:restriction>" << endl;
48 } else {
49 indent(s_xsd_types_) <<
50 "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />" << endl;
52 indent_down();
53 indent(s_xsd_types_) <<
54 "</xsd:simpleType>" << endl << endl;
57 void t_xsd_generator::generate_struct(t_struct* tstruct) {
58 vector<t_field*>::const_iterator m_iter;
59 const vector<t_field*>& members = tstruct->get_members();
60 bool xsd_all = tstruct->get_xsd_all();
62 indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
63 indent_up();
64 if (xsd_all) {
65 indent(s_xsd_types_) << "<xsd:all>" << endl;
66 } else {
67 indent(s_xsd_types_) << "<xsd:sequence>" << endl;
69 indent_up();
71 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
72 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());
75 indent_down();
76 if (xsd_all) {
77 indent(s_xsd_types_) << "</xsd:all>" << endl;
78 } else {
79 indent(s_xsd_types_) << "</xsd:sequence>" << endl;
81 indent_down();
82 indent(s_xsd_types_) <<
83 "</xsd:complexType>" << endl <<
84 endl;
87 void t_xsd_generator::generate_element(ostream& out,
88 string name,
89 t_type* ttype,
90 t_struct* attrs,
91 bool optional,
92 bool nillable,
93 bool list_element) {
94 string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
95 string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
96 string soptional = sminOccurs + smaxOccurs;
97 string snillable = nillable ? " nillable=\"true\"" : "";
99 if (ttype->is_void() || ttype->is_list()) {
100 indent(out) <<
101 "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
102 indent_up();
103 if (attrs == NULL && ttype->is_void()) {
104 indent(out) <<
105 "<xsd:complexType />" << endl;
106 } else {
107 indent(out) <<
108 "<xsd:complexType>" << endl;
109 indent_up();
110 if (ttype->is_list()) {
111 indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
112 indent_up();
113 string subname;
114 t_type* subtype = ((t_list*)ttype)->get_elem_type();
115 if (subtype->is_base_type() || subtype->is_container()) {
116 subname = name + "_elt";
117 } else {
118 subname = type_name(subtype);
120 f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl;
121 generate_element(out, subname, subtype, NULL, false, false, true);
122 indent_down();
123 indent(out) << "</xsd:sequence>" << endl;
124 indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
126 if (attrs != NULL) {
127 const vector<t_field*>& members = attrs->get_members();
128 vector<t_field*>::const_iterator a_iter;
129 for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
130 indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
133 indent_down();
134 indent(out) <<
135 "</xsd:complexType>" << endl;
137 indent_down();
138 indent(out) <<
139 "</xsd:element>" << endl;
140 } else {
141 if (attrs == NULL) {
142 indent(out) <<
143 "<xsd:element name=\"" << name << "\"" << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />" << endl;
144 } else {
145 // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
146 indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
147 indent_up();
148 indent(out) << "<xsd:complexType>" << endl;
149 indent_up();
150 indent(out) << "<xsd:complexContent>" << endl;
151 indent_up();
152 indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
153 indent_up();
154 const vector<t_field*>& members = attrs->get_members();
155 vector<t_field*>::const_iterator a_iter;
156 for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
157 indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
159 indent_down();
160 indent(out) << "</xsd:extension>" << endl;
161 indent_down();
162 indent(out) << "</xsd:complexContent>" << endl;
163 indent_down();
164 indent(out) << "</xsd:complexType>" << endl;
165 indent_down();
166 indent(out) << "</xsd:element>" << endl;
171 void t_xsd_generator::generate_service(t_service* tservice) {
172 // Make output file
173 string f_xsd_name = get_out_dir()+tservice->get_name()+".xsd";
174 f_xsd_.open(f_xsd_name.c_str());
176 string ns = program_->get_xsd_namespace();
177 if (ns.size() > 0) {
178 ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " +
179 "elementFormDefault=\"qualified\"";
182 // Print the XSD header
183 f_xsd_ <<
184 "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl <<
185 "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl <<
186 endl <<
187 "<!-- Yo yo yo, this XSD woz be generated by Thrift. -->" << endl <<
188 endl;
190 // Print out the type definitions
191 indent(f_xsd_) << s_xsd_types_.str();
193 // Keep a list of all the possible exceptions that might get thrown
194 map<string, t_struct*> all_xceptions;
196 // List the elements that you might actually get
197 vector<t_function*> functions = tservice->get_functions();
198 vector<t_function*>::iterator f_iter;
199 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
200 string elemname = (*f_iter)->get_name() + "_response";
201 t_type* returntype = (*f_iter)->get_returntype();
202 generate_element(f_xsd_, elemname, returntype);
203 f_xsd_ << endl;
205 t_struct* xs = (*f_iter)->get_xceptions();
206 const std::vector<t_field*>& xceptions = xs->get_members();
207 vector<t_field*>::const_iterator x_iter;
208 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
209 all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type());
213 map<string, t_struct*>::iterator ax_iter;
214 for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) {
215 generate_element(f_xsd_, ax_iter->first, ax_iter->second);
218 // Close the XSD document
219 f_xsd_ << endl << "</xsd:schema>" << endl;
220 f_xsd_.close();
223 string t_xsd_generator::type_name(t_type* ttype) {
224 if (ttype->is_typedef()) {
225 return ttype->get_name();
228 if (ttype->is_base_type()) {
229 return xsd(base_type_name(((t_base_type*)ttype)->get_base()));
232 if (ttype->is_enum()) {
233 return xsd("int");
236 if (ttype->is_struct() || ttype->is_xception()) {
237 return ttype->get_name();
240 return "container";
244 * Returns the XSD type that corresponds to the thrift type.
246 * @param tbase The base type
247 * @return Explicit XSD type, i.e. xsd:string
249 string t_xsd_generator::base_type_name(t_base_type::t_base tbase) {
250 switch (tbase) {
251 case t_base_type::TYPE_VOID:
252 return "void";
253 case t_base_type::TYPE_STRING:
254 return "string";
255 case t_base_type::TYPE_BOOL:
256 return "boolean";
257 case t_base_type::TYPE_BYTE:
258 return "byte";
259 case t_base_type::TYPE_I16:
260 return "short";
261 case t_base_type::TYPE_I32:
262 return "int";
263 case t_base_type::TYPE_I64:
264 return "long";
265 case t_base_type::TYPE_DOUBLE:
266 return "decimal";
267 default:
268 throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);