Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions llsd/serde_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ class LLSDXMLFormatter(LLSDBaseFormatter):
interface to this functionality.
"""

def __init__(self, indent_atom = b'', eol = b''):
def __init__(self, indent_atom = b'', eol = b'', c_compat = False, sort_maps = False):
"Construct a serializer."
# Call the super class constructor so that we have the type map
super(LLSDXMLFormatter, self).__init__()
self._indent_atom = indent_atom
self._eol = eol
self._depth = 1
self.c_compat = c_compat
self.sort_maps = sort_maps

def _indent(self):
pass
Expand All @@ -85,13 +87,22 @@ def _LLSD(self, v):
def _UNDEF(self, _v):
self.stream.writelines([b'<undef/>', self._eol])
def _BOOLEAN(self, v):
if v:
return self.stream.writelines([b'<boolean>true</boolean>', self._eol])
self.stream.writelines([b'<boolean>false</boolean>', self._eol])
if self.c_compat:
s = b'1' if v else b'0'
else:
s = b'true' if v else b'false'
self.stream.writelines([b'<boolean>', s, b'</boolean>', self._eol])
def _INTEGER(self, v):
self.stream.writelines([b'<integer>', str(v).encode('utf-8'), b'</integer>', self._eol])
def _REAL(self, v):
self.stream.writelines([b'<real>', str(v).encode('utf-8'), b'</real>', self._eol])
if self.c_compat:
if int(v) == v:
s = str(int(v))
else:
s = "%.25g" % v
else:
s = str(v)
self.stream.writelines([b'<real>', s.encode('utf-8'), b'</real>', self._eol])
def _UUID(self, v):
if v.int == 0:
return self.stream.writelines([b'<uuid/>', self._eol])
Expand Down Expand Up @@ -124,7 +135,11 @@ def _ARRAY(self, v):
def _MAP(self, v):
self.stream.writelines([b'<map>', self._eol])
self._depth += 1
for key, value in v.items():
keys = v.keys()
if self.sort_maps:
keys = sorted(keys)
for key in keys:
value = v[key]
self._indent()
if PY2: # pragma: no cover
self.stream.writelines([b'<key>',
Expand Down Expand Up @@ -162,6 +177,7 @@ def _write(self, something):
"""
self.stream.writelines([b'<?xml version="1.0" ?>', self._eol,
b'<llsd>', self._eol])
self._indent()
self._generate(something)
self.stream.write(b'</llsd>' + self._eol)

Expand All @@ -179,17 +195,29 @@ class LLSDXMLPrettyFormatter(LLSDXMLFormatter):
This class is not necessarily suited for serializing very large objects.
It sorts on dict (llsd map) keys alphabetically to ease human reading.
"""
def __init__(self, indent_atom = b' ', eol = b'\n'):
def __init__(self, indent_atom = b' ', eol = b'\n', c_compat = False, sort_maps = True):
"Construct a pretty serializer."
# Call the super class constructor so that we have the type map
super(LLSDXMLPrettyFormatter, self).__init__(indent_atom = indent_atom, eol = eol)
super(LLSDXMLPrettyFormatter, self).__init__(indent_atom = indent_atom, eol = eol, c_compat=c_compat, sort_maps = sort_maps)

def _indent(self):
"Write an indentation based on the atom and indentation level."
self.stream.writelines([self._indent_atom] * self._depth)

def _ARRAY(self, v):
if not v:
self.stream.writelines([b'<array />', self._eol])
else:
super(LLSDXMLPrettyFormatter, self)._ARRAY(v)

def _STRING(self, v):
if not v:
self.stream.writelines([b'<string />', self._eol])
else:
super(LLSDXMLPrettyFormatter, self)._STRING(v)


def format_pretty_xml(something):
def format_pretty_xml(something, indent = 2, c_compat = False, sort_maps = True):
"""
Serialize a python object as 'pretty' application/llsd+xml.

Expand All @@ -205,10 +233,10 @@ def format_pretty_xml(something):
objects. It sorts on dict (llsd map) keys alphabetically to ease human
reading.
"""
return LLSDXMLPrettyFormatter().format(something)
return LLSDXMLPrettyFormatter(indent_atom=b' '*indent, c_compat=c_compat, sort_maps=sort_maps).format(something)


def write_pretty_xml(stream, something):
def write_pretty_xml(stream, something, indent = 2, c_compat = False, sort_maps = True):
"""
Serialize to passed 'stream' the python object 'something' as 'pretty'
application/llsd+xml.
Expand All @@ -225,7 +253,7 @@ def write_pretty_xml(stream, something):
objects. It sorts on dict (llsd map) keys alphabetically to ease human
reading.
"""
return LLSDXMLPrettyFormatter().write(stream, something)
return LLSDXMLPrettyFormatter(indent_atom=b' '*indent, c_compat=c_compat, sort_maps=sort_maps).write(stream, something)


def parse_xml(something):
Expand Down Expand Up @@ -274,7 +302,7 @@ def parse_xml_nohdr(baseparser):
return _to_python(element[0])


def format_xml(something):
def format_xml(something, c_compat = False, sort_maps = False):
"""
Format a python object as application/llsd+xml

Expand All @@ -283,7 +311,7 @@ def format_xml(something):

See http://wiki.secondlife.com/wiki/LLSD#XML_Serialization
"""
return LLSDXMLFormatter().format(something)
return LLSDXMLFormatter(c_compat = c_compat, sort_maps = sort_maps).format(something)


def write_xml(stream, something):
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/viewer-autobuild.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" ?>
<llsd>
<map>
<map>
<key>installables</key>
<map>
<key>SDL</key>
Expand Down
2 changes: 1 addition & 1 deletion tests/llsd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,7 @@ def testFormatPrettyXML(self):

self.assertEqual(output_xml.decode("utf8"), """<?xml version="1.0" ?>
<llsd>
<map>
<map>
<key>id</key>
<array>
<string>string1</string>
Expand Down