Search code examples
pythonxmllabview

Python list to XML and vice versa


I have some python code that I wrote to convert a python list into an XML element. It's meant for interacting with LabVIEW, hence the weird XML array format. Anyways, here's the code:

def pack(data):
  # create the result element
  result = xml.Element("Array")

  # report the dimensions
  ref = data
  while isinstance(ref, list):
    xml.SubElement(result, "Dimsize").text = str(len(ref))
    ref = ref[0]

  # flatten the data
  while isinstance(data[0], list):
    data = sum(data, [])

  # pack the data
  for d in data:
    result.append(pack_simple(d))

  # return the result
  return result

Now I need to write an unpack() method to convert the packed XML Array back into a python list. I can extract the array dimensions and data just fine:

def unpack(element):
  # retrieve the array dimensions and data
  lengths = []
  data = []
  for entry in element:
    if entry.text == "Dimsize":
      lengths.append(int(entry.text))

    else:
      data.append(unpack_simple(entry))

  # now what?

But I am not sure how to unflatten the array. What would be an efficient way to do that?

Edit: Here's what the python list and corresponding XML looks like. Note: the arrays are n-dimensional.

data = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

And then the XML version:

<Array>
  <Dimsize>2</Dimsize>
  <Dimsize>2</Dimsize>
  <Dimsize>2</Dimsize>
  <I32>
    <Name />
    <Val>1</Val>
  </I32>

  ... 2, 3, 4, etc.
</Array>

The actual format isn't important though, I just don't know how to unflatten the list from:

data = [1, 2, 3, 4, 5, 6, 7, 8]

back into:

data = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

given:

lengths = [2, 2, 2]

Assume pack_simple() and unpack_simple() do the same as pack() and unpack() for the basic data types (int, long, string, boolean).


Solution

  • Try the following:

    from operator import mul
    
    def validate(array, sizes):
        if reduce(mul, sizes) != len(array):
            raise ValueError("Array dimension incompatible with desired sizes")
    
        return array, sizes
    
    def reshape(array, sizes):
        for s in sizes:
            array = [array[i:i + s] for i in range(0, len(array), s)]
    
        return array[0]
    
    data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    length = [2, 2, 3]
    
    print reshape(validate(data, length))
    
    length = [2, 2, 2]
    
    print reshape(validate(data, length))
    

    Output being:

    [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]
    Traceback:
       (...)
    ValueError: Array dimension incompatible with desired sizes
    

    An alternative is using numpy arrays. Note that for this simple task, numpy is a rather big dependency, though you will find that most (common) array related tasks/problems already have an implementation there:

    from numpy import array
    
    print array(data).reshape(*length)  # optionally add .tolist() to convert to list
    

    EDIT: Added data validation

    EDIT: Example using numpy arrays (thanks to J.F.Sebastian for the hint)