読者です 読者をやめる 読者になる 読者になる

suzukiyou blog

建築設計とかpythonとかその辺をとりあえずする

ET.Elementを書き出せるDictっぽいものを作る

ポイント
  • プログラム上ではdict型(らしきもの)でいろいろ動かせるようにする
  • 保存するときにElement型にしてtree.write()で出力する
  • 読出するときはET.parse()で読んでdict型(らしきもの)に入れる。
  • Dictでは動的型付けのまましたい。
  • ただし変換した時にtagにあたるものや、ファイル内での唯一keyとなるnameとかはstrかunicodeとする。
  • Elementに変換するときに型チェックを行いたい。intとかfloatはプログラム上での型情報を付加した上でstrに変換する。
  • 読み出し時にDictを復元する。intとかは元通りに戻す。
  • 保存・読出時にめんどくさそうなのでDictを要素に持つDictとかは作らない。再帰して終わらなさそう。
  • とはいえ最低Dictには前者・後者が欲しい。プログラム上ではイテレータっぽい動きをしたい。
  • とすれば、Dictはリストに前者・後者のポインタを持っときたい。
  • 唯一keyがわかっていればポインタを再構成できる。
  • fileハンドルを作ろう。そうすればファイルネームとかヘッダとかの管理もさせられる。
実際にやってみた
#EDsys.py
#coding:utf-8

import xml.etree.ElementTree as ET
from is_ETwritable import is_ETwritable
from is_numeric import is_numeric
class FileHandle(object):
  def __init__(self,filename):
    self.dict={}
    self.dict["filename"]=filename
    self.Items={}
  def __getitem__(self,key):
    return self.dict[key]
  def __setitem__(self,key,value):
    if is_ETwritable(key):
      self.dict[key]=value
    else:
      raise
  def setItem(self,item):
    if type(item)==Item:
      self.Items[item["name"]]=item
    else:
      raise
  def getItem(self,key):
    return self.Items[key]
  def write(self):
    a=ET.Element(self["filename"])
    td=dict(self.dict)
    del td["filename"]
    for i in td:
      aa=ET.Element(i)
      if is_ETwritable(td[i]):
        aa.text=td[i]
      elif is_numeric(td[i]):
        aa.text=str(td[i])
        aa.attrib["progtype"]=str(type(td[i]))
      else:
        raise
      a.append(aa)
    for i in self.Items:
      a.append(self.getItem(i).toElement())
    t=ET.ElementTree(a)
    print self["filename"]
    t.write(self["filename"],"utf-8")

class Item(object):
  def __init__(self,Itemtype,name):
    if is_ETwritable(Itemtype) and is_ETwritable(name):
      self.dict={}
      self.dict["Itemtype"]=Itemtype
      self.dict["name"]=name
      self.before=[]
      self.next=[]
    else:
      raise
  def __getitem__(self,key):
    return self.dict[key]
  def __setitem__(self,key,value):
    if is_ETwritable(key):
      self.dict[key]=value
    else:
      raise
  def setnext(self,node):
    if type(node)==Item:
      self.next.append(node)
      node.before.append(self)
    else:
      raise
  def setbefore(self,node):
    if type(node)==Item:
      self.before.append(node)
      node.next.append(self)
    else:
      raise
  """def dictprint(self):
    print self.dict.__repr__()
  def fullprint(self):
    self.dictprint()
    print "before"
    for i in self.before:
      i.dictprint()
    print "next"
    for i in self.next:
      i.dictprint()"""
  def toElement(self):
    a=ET.Element("Item")
    #print self.dict
    td=dict(self.dict)
    #print td
    for i in td:
      aa=ET.Element(i)
      #print i
      if is_ETwritable(td[i]):
        aa.text=td[i]
      elif is_numeric(td[i]):
        aa.text=str(td[i])
        aa.attrib["progtype"]=str(type(td[i]))
      else:
        raise
      a.append(aa)
    for i in self.before:
      aa=ET.Element("before")
      aa.attrib["name"]=i["name"]
      a.append(aa)
    for i in self.next:
      aa=ET.Element("next")
      aa.attrib["name"]=i["name"]
      a.append(aa)
    return a

def parse(filename):
  EL=ET.parse(filename).getroot()
  fh=FileHandle(filename)
  for i in EL.getchildren():
    if i.tag =="Item":
      itemtype=None
      name=None
      somedict={}
      for j in i.getchildren():
        if j.tag=="Itemtype":
          itemtype=j.text
        elif j.tag=="name":
          name=j.text
        elif j.tag=="next" or j.tag=="before":
          continue
        else:
          if "progtype" in j.attrib:
            somedict[j.tag]=typedecode(j.attrib["progtype"],j.text)
        
      assert not itemtype==None
      assert not name==None
      a=Item(itemtype,name)
      for i in somedict:
        a[i]=somedict[i]
      fh.setItem(a)
    else:
      fh[i.tag]=i.text
  for i in EL.findall("Item"):
    x=fh.getItem(i.find("name").text)
    for j in i.findall("before"):
      x.before.append(fh.getItem(j.attrib["name"]))
    for j in i.findall("next"):
      x.next.append(fh.getItem(j.attrib["name"]))
  return fh,EL

def typedecode(str,value):
  if str=="<type 'int'>":
    return int(value)
  if str=="<type 'float'>":
    return float(value)  

あとis_ETwritable.pyに関しては

#coding:utf-8

def is_ETwritable(string):
  if type(string)==str or type(str)==unicode:
    return True
  else:
    return False
おもむろに

これからこれつかいます。