Example algorithm for xml serialization of Python data

Allikas: Lambda
Redaktsioon seisuga 6. oktoober 2015, kell 07:10 kasutajalt Tammet (arutelu | kaastöö) (Uus lehekülg: '<pre> Principles of data conversion to/from XML ========================================== This memo presents a general algorithm for converting native datatypes to XML and, vi...')
(erin) ←Vanem redaktsioon | Viimane redaktsiooni (erin) | Uuem redaktsioon→ (erin)
Mine navigeerimisribale Mine otsikasti
Principles of data conversion to/from XML
==========================================


This memo presents a general algorithm for
converting native datatypes to XML and, vice
versa, XML to native datatypes.

The main goals of the algorithm:

- language-agnostic: support python, php, javascript, java, c, lisp,  ...

- convert native python and php data to/from XML without adding
  any kinds of extra infomation to native data

- allow using user's own xml tags and attributes if necessary

- fit well into the soap and arbitrary-xml-usage frameworks

For example, a suitable use of the algorithm for treating
soap messages is to convert the whole soap envelope with
all the content directly into the native datastructure, and
then let user program handle the native data as it pleases.


Short overview
==============

XML uses three special tags: Array, Struct and item in
their own namespace.

Array and Struct have the same semantics as SOAP-ENC
Array and Struct.

When simple native data (integers, strings, etc) are converted to xml,
the type will be indicated in xml as a type attribute with xml schema
values.

Native arrays,lists and tuples are converted to xml Array.
Native structures, dictionaries and objects are converted to xml Struct.

xml Array is always converted to native array (not tuple, dict, etc).
xml Struct is always converted to native struct or dict or object, whichever
is available natively.

In case the user wants to use his/her own XML tags and property
lists, he has to create a special four-element array which contains
the tag name, attribute list and children list. 

XML tags except Array, Struct, item are converted to such native
four-element arrays.


Primitive data conversion
=========================


3     <->  <av:item av:type="xsd:integer">3</av:item> 
"abc" <->  <av:item av:type="xsd:string">abc</av:item> 
1.3   <->  <av:item av:type="xsd:float">1.3</av:item>
True  <->  <av:item av:type="xsd:boolean">true</av:item>
False <->  <av:item av:type="xsd:boolean">false</av:item>
datetime.date(2006, 2, 13)  <-> 
     <av:item type="xsd:date">2006-02-13</av:item>
time.struct_time(2006, 2, 13, 11, 22, 11, 2, 347, 0) <-> 
      <av:item type="xsd:dateTime">2006-02-13T11:22:2.347</av:item>


Array/tuple conversion
======================

Nested array conversion example:

[2,"a",[],["b",3]]
   

<->

   <av:Array>
     <av:item av:type="xsd:integer">2</av:item>
     <av:item av:type="xsd:string">a</av:item> 
     <av:Array/>
     <av:Array>
       <av:item av:type="xsd:string">b</av:item>
       <av:item av:type="xsd:integer">3</av:item>
     <av:Array>
   <av:Array>


Tuples, like (2,"a",(),("b",3)), will be
converted in exactly same way to XML. 
Xml will then be converted back to array, not tuple.
 

Structure/dict/object conversion
=================================

Analogous nested Python dict (similarly struct/object
in other languages) conversion example:

{'k1': 2, 'k2' : "a", 'k3' : {}, 'k4' : {'m1' : "b", 'm2' : 3}}  

<-> 

  <av:Struct>
    <k1 av:type="xsd:integer">2</k1>
    <k2 av:type="xsd:string">a</k2>
    <k3>
      <av:Struct/>
    </k3>
    <k4>
      <av:Struct>
        <m1 av:type="xsd:string">b</m1>
        <m2 av:type="xsd:integer">3</m2>
      </av:Struct>
    </k4>
  </av:Struct>  


User tag usage
===============

To avoid Array, Struct or item default names and/or
for adding attributes to tags, the user will have to
use a special four-element array or tuple which contains,
in that order:

0) 'xmltag' special string
1) tag name string
2) attribute dict with simple data values or a list of two-element pairs
3) value inside the tag (None or null if missing)

The value (last element above) will then be surrounded by the
tag name given, not the default Array/Struct/item.

When converting back from xml, always an array will be used, and the
last element will be always present (may be None or null). 
 
 
Missing content example with attributes:
----------------------------------------

['xmltag','somename',{'someattr' : 3,'otherattr' : 'mm'},None]
or equivalently ['xmltag','somename',[['someattr',3],['otherattr','mm']],None]

<->

<somename someattr='3' otherattr='mm'/>

When converting back from xml, always a dict/struct/object will be used
for attribute list.


Example with a simple value: 
----------------------------

Note that the <item> tag is not put around the value!


['xmltag','somename',None, 'somevalue']
or
('xmltag','somename',None, 'somevalue')

<->

<somename>somevalue</somename>


Example with a nested array:
----------------------------

The nested array is exactly the same as the
first Array example above: in the example
below the tag 'somename' will be used instead
of the default 'Array':


['xmltag','somename',None,2,
  ["a",[],['xmltag','othername',None,["b",3]]]]

<->

<somename>
     <av:item av:type="xsd:integer">2</av:item>
     <av:item av:type="xsd:string">a</av:item> 
     <av:Array/>
     <othername>
       <av:item av:type="xsd:string">b</av:item>
       <av:item av:type="xsd:integer">3</av:item>
     <othername>
</somename>


Example with a nested dict/struct/object:
-----------------------------------------

The nested dict is exactly same as the
first dict example above: compare these!


['xmltag','somename',None,2,
   {'k1': 2, 'k2' : "a", 'k3' : {}, 'k4' : {'m1' : "b", 'm2' : 3}}]

<->

  <somename>
    <k1 av:type="xsd:integer">2</k1>
    <k2 av:type="xsd:string">a</k2>
    <k3>
      <av:Struct/>
    </k3>
    <k4>
      <av:Struct>
        <m1 av:type="xsd:string">b</m1>
        <m2 av:type="xsd:integer">3</m2>
      </av:Struct>
    </k4>
  </somename>