Skip to content

Commit

Permalink
Support attribute for xmpp messaging
Browse files Browse the repository at this point in the history
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.
        <xsd:element name="sequence-number" type="xsd:integer"/>
        <xsd:element name="sticky" type="xsd:integer"/>

This will add two xml nodes to xmpp message making it more verbose and bulky
<xmpp-message>
    <sequence-number> 1 </sequence-number>
    <sticky> False </sticky>
</xmpp-message>

This xmpp message can be represented with one XML node with attributes.
<xmpp-message>
    <mobility seqno="2" sticky="true" />
</xmpp-message>

Add support for XML attribute in schema and auto generation of types/parser code

Change-Id: Idbd238ec414f7b18c897c8482cfdff04c0f77876
Related-bug: #1645092
  • Loading branch information
bailkeri committed Dec 7, 2016
1 parent 5b0014f commit 76e64fd
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 33 deletions.
2 changes: 2 additions & 0 deletions generateDS.py
Expand Up @@ -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
Expand Down
80 changes: 51 additions & 29 deletions type_model.py
Expand Up @@ -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 = []

Expand All @@ -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):
Expand Down
115 changes: 111 additions & 4 deletions type_parser.py
Expand Up @@ -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");
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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<AutogenProperty> *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 = """
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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')

0 comments on commit 76e64fd

Please sign in to comment.