From 76e64fd3204aff433ad2383258e65e62809ca41c Mon Sep 17 00:00:00 2001 From: Prakash Bailkeri Date: Wed, 7 Dec 2016 22:26:48 +0530 Subject: [PATCH] Support attribute for xmpp messaging Currently, XML for xmpp message doesn't support attribute declaration. Example: Mobility extended community needs two information. sequence number and sticky bit In the current schema, this needs to be defined as two different element. This will add two xml nodes to xmpp message making it more verbose and bulky 1 False This xmpp message can be represented with one XML node with attributes. Add support for XML attribute in schema and auto generation of types/parser code Change-Id: Idbd238ec414f7b18c897c8482cfdff04c0f77876 Related-bug: #1645092 --- generateDS.py | 2 + type_model.py | 80 +++++++++++++++++++++------------- type_parser.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 164 insertions(+), 33 deletions(-) diff --git a/generateDS.py b/generateDS.py index bf52136..94cb42d 100755 --- a/generateDS.py +++ b/generateDS.py @@ -1807,11 +1807,13 @@ class XschemaAttribute: def __init__(self, parser_generator, name, data_type='xs:string', use='optional', default=None): self._PGenr = parser_generator self.name = name + self.cleanName = self._PGenr.cleanupName(name) self.data_type = data_type self.use = use self.default = default # Enumeration values for the attribute. self.values = list() + def getCleanName(self): return self.cleanName def setName(self, name): self.name = name def getName(self): return self.name def setData_type(self, data_type): self.data_type = data_type diff --git a/type_model.py b/type_model.py index 1596eec..a493a9e 100644 --- a/type_model.py +++ b/type_model.py @@ -27,6 +27,7 @@ def __init__(self): class ComplexType(object): def __init__(self, name): self._name = name + self._is_attribute = False self._data_types = [] self._data_members = [] @@ -48,37 +49,58 @@ def Build(self, xsdTypeDict, cTypeDict): self._xsd_type = xsdTypeDict[self._name] children = self._xsd_type.getChildren() - for child in children: - if child.isComplex(): - descendent = ComplexTypeLocate(xsdTypeDict, cTypeDict, child.getType()) - self._data_types.append(descendent) - cpptype = child.getType() - jtype = child.getType() - cppname = child.getCleanName() - else: - cpptype = getCppType(child.getType()) - jtype = getJavaType(child.getType()) + if children: + for child in children: + if child.isComplex(): + descendent = ComplexTypeLocate(xsdTypeDict, cTypeDict, child.getType()) + self._data_types.append(descendent) + cpptype = child.getType() + jtype = child.getType() + cppname = child.getCleanName() + else: + cpptype = getCppType(child.getType()) + jtype = getJavaType(child.getType()) + if cpptype == 'void': + logger = logging.getLogger('type_model') + logger.warning('simpleType %s: unknown' % child.getType()) + cppname = child.getCleanName() + + member = MemberInfo() + member.elementname = child.getName() + member.membername = CppVariableName(cppname) + member.xsd_object = child + member.isComplex = child.isComplex() + if child.getMaxOccurs() > 1: + member.membername = cppname# + '_list' + member.sequenceType = cpptype + cpptype = 'std::vector<%s>' % cpptype + jtype = 'List<%s>' % jtype + member.isSequence = True + + member.ctypename = cpptype + member.jtypename = jtype + member.default = child.getDefault() + self._data_members.append(member) + else: + attributes = self._xsd_type.getAttributeDefs().values() + if attributes: + self._is_attribute = True + for attribute in attributes: + cpptype = getCppType(attribute.getType()) + jtype = getJavaType(attribute.getType()) if cpptype == 'void': logger = logging.getLogger('type_model') - logger.warning('simpleType %s: unknown' % child.getType()) - cppname = child.getCleanName() - - member = MemberInfo() - member.elementname = child.getName() - member.membername = CppVariableName(cppname) - member.xsd_object = child - member.isComplex = child.isComplex() - if child.getMaxOccurs() > 1: - member.membername = cppname# + '_list' - member.sequenceType = cpptype - cpptype = 'std::vector<%s>' % cpptype - jtype = 'List<%s>' % jtype - member.isSequence = True - - member.ctypename = cpptype - member.jtypename = jtype - member.default = child.getDefault() - self._data_members.append(member) + logger.warning('simpleType %s: unknown' % attribute.getType()) + cppname = attribute.getCleanName() + member = MemberInfo() + member.elementname = attribute.getName() + member.membername = CppVariableName(cppname) + member.xsd_object = attribute + member.isComplex = False + member.ctypename = cpptype + member.jtypename = jtype + member.default = attribute.getDefault() + self._data_members.append(member) def ComplexTypeLocate(xsdTypeDict, cTypeDict, xtypename): diff --git a/type_parser.py b/type_parser.py index 2459cfc..e99a285 100644 --- a/type_parser.py +++ b/type_parser.py @@ -91,7 +91,7 @@ def GenerateTypeParser(self, file, ctype): file.write(export) for member in ctype.getDataMembers(): - indent = ' ' * 4 + indent = ' ' * 4 cpptype = member.ctypename if cpptype == 'int': file.write(indent + "// Add child node \n"); @@ -141,7 +141,7 @@ def GenerateTypeParser(self, file, ctype): 'membername': member.membername, 'elementname': member.elementname } file.write(item) - elif member.isSequence and member.sequenceType == 'std::string': + elif member.isSequence and member.sequenceType == 'std::string': item = """ for (%(type)s::const_iterator iter = %(membername)s.begin(); iter != %(membername)s.end(); ++iter) { @@ -183,6 +183,88 @@ def GenerateTypeParser(self, file, ctype): file.write(indent + fmt % (member.membername)) file.write('}\n') + def GenerateAttributeParser(self, file, ctype): + print "generating parser for attribute %s" %ctype.getName() + start = """ +bool %s::XmlParse(const xml_node &parent) { + for (xml_attribute attr = parent.first_attribute(); attr; + attr = attr.next_attribute()) { +""" % ctype.getName() + file.write(start) + for member in ctype.getDataMembers(): + file.write(' if (strcmp(attr.name(), "%s") == 0) {\n' % + member.xsd_object.getName()) + indent = ' ' * 12 + cpptype = member.ctypename + if cpptype == 'int': + fmt = 'if (!ParseInteger(attr, &%s)) return false;\n' + file.write(indent + fmt % member.membername) + elif cpptype == 'uint64_t': + fmt = 'if (!ParseUnsignedLong(attr, &%s)) return false;\n' + file.write(indent + fmt % member.membername) + elif cpptype == 'bool': + fmt = 'if (!ParseBoolean(attr, &%s)) return false;\n' + file.write(indent + fmt % member.membername) + elif cpptype == 'std::string': + fmt = '%s = attr.value();\n' + file.write(indent + fmt % member.membername) + file.write(' }\n') + file.write(' }\n return true;\n}\n') + + static_fn = """ +bool %s::XmlParseProperty(const xml_node &parent, + auto_ptr *resultp) { + %s *ptr = new %s(); + resultp->reset(ptr); + if (!ptr->XmlParse(parent)) { + return false; + } + return true; +} +""" % (ctype.getName(), ctype.getName(), ctype.getName()) + file.write(static_fn) + + export = """ +void %s::Encode(xml_node *node_p) const { + pugi::xml_attribute attr; + +""" % (ctype.getName()) + file.write(export) + + for member in ctype.getDataMembers(): + indent = ' ' * 4 + cpptype = member.ctypename + if cpptype == 'int': + file.write(indent + "// Add child node \n"); + fmt = 'attr = node_p->append_attribute("%s");\n' + file.write(indent + fmt % member.elementname) + fmt = 'attr.set_value(%s::%s);\n\n' + file.write(indent + fmt % (ctype.getName(),member.membername)) + if cpptype == 'uint64_t': + cdecl = """ + attr = node_p->append_attribute("%(elementname)s"); + { + ostringstream oss; + oss << %(membername)s; + attr.set_value(oss.str().c_str()); + } +""" % {'elementname': member.xsd_object.getName(), 'membername': member.membername} + file.write(cdecl) + elif cpptype == 'bool': + file.write(indent + "// Add child node \n"); + fmt = 'attr = node_p->append_attribute("%s");\n' + file.write(indent + fmt % member.elementname) + fmt = 'attr.set_value(%s::%s);\n\n' + file.write(indent + fmt % (ctype.getName(),member.membername)) + elif cpptype == 'std::string': + file.write(indent + "// Add child node \n"); + fmt = 'attr = node_p->append_attribute("%s");\n' + file.write(indent + fmt % member.elementname) + fmt = 'attr.set_value(%s::%s.c_str());\n\n' + file.write(indent + fmt % (ctype.getName(),member.membername)) + file.write('}\n') + + def Generate(self, file, hdrname): header = """ @@ -203,6 +285,28 @@ def Generate(self, file, hdrname): #endif namespace autogen { +static bool ParseInteger(const pugi::xml_attribute &attr, int *valuep) { + char *endp; + *valuep = strtoul(attr.value(), &endp, 10); + while (isspace(*endp)) endp++; + return endp[0] == '\\0'; +} + +static bool ParseUnsignedLong(const pugi::xml_attribute &attr, uint64_t *valuep) { + char *endp; + *valuep = strtoull(attr.value(), &endp, 10); + while (isspace(*endp)) endp++; + return endp[0] == '\\0'; +} + +static bool ParseBoolean(const pugi::xml_attribute &attr, bool *valuep) { + if (strcmp(attr.value(), "true") ==0) + *valuep = true; + else + *valuep = false; + return true; +} + static bool ParseInteger(const pugi::xml_node &node, int *valuep) { char *endp; *valuep = strtoul(node.child_value(), &endp, 10); @@ -218,7 +322,7 @@ def Generate(self, file, hdrname): } static bool ParseBoolean(const pugi::xml_node &node, bool *valuep) { - if (strcmp(node.child_value(), "true") ==0) + if (strcmp(node.child_value(), "true") ==0) *valuep = true; else *valuep = false; @@ -264,5 +368,8 @@ def Generate(self, file, hdrname): """ % hdrname file.write(header) for ctype in self._cTypeDict.values(): - self.GenerateTypeParser(file, ctype) + if ctype._is_attribute: + self.GenerateAttributeParser(file, ctype) + else: + self.GenerateTypeParser(file, ctype) file.write('} // namespace autogen\n')