python--结构化文件存储

为解决不同设备间的信息交换,可以通过ros、zmq等消息系统机制,也可以通过结构化文件进行存储,两种方式适用不同的情况。这里总结一下python的结构化文件存储方面的内容,主要包括xml和json。

一、xml
xml的一些基础内容:

XML文档的构成
    - 处理指令(可以认为一个文件内只有一个处理指令)
        - 最多只有一行
        - 且必须在第一行
        - 内容是与xml本身处理起相关的一些声明或者指令
        - 以xml关键字开头
        - 一般用于声明XML的版本和采用的编码
            - version属性是必须的
            - encoding属性用来支出xml解释器使用的编码
    - 根元素(一个文件内只有一个根元素)
        - 在整个xml文件中,可以把他看作一个树形结构
        - 根元素有且只能由一个
    - 子元素
    - 属性
    - 内容
        - 表明标签所存储的信息
    - 注释
        - 起说明作用的信息
        - 注释不能嵌套在标签里
        - 只有在注释的开始和结尾使用双短横线
        - 三短横线只能出现在注释的开头而不能用在结尾
        
                <name> <!-- wangdapeng -->   </name> #可以
                <name <!-- wangdapeng -->>   </name> #不可以,注释在标签内
                
                <!--my-name-by-wang--> #可以,注释内容可以有一个短横线
                <!--my--name--by--wang-->#不可以,双短横线只能出现在开头或结尾
                
                <!---my-name--> #可以, 三短横线只能出现在开头
                <!---my-name---> #不可以, 三短横线只能出现在开头        
                
- 保留字符的处理
    - XML中使用的符号可能跟实际符号相冲突,典型的就是左右尖括号
    - 使用实体引用(EntityReference)来表示保留字符
    
             <score> score>80 </score> #有错误,xml中不能出现>
             <score> score&gt;80</score> #使用实体引用
    - 把含有保留字符的部分放在CDATA块内部,CDATA块把内部信息视为不需要转义
    
              <![CDATA[
                 select name,age
                 from Student
                 where score>80
                 ]]>
                 
    - 常用的需要转移的保留字符和对应实体引用
    
            - &:&amp;
            - <:&lt;
            - >:&gt;
            - ':&apos;
            - ":&quot;
            - 一共五个, 每个实体引用都以&开头并且以分号结尾
            
- XML标签的命名规则
    - Pascal命名法
    - 用单词表示,第一个字母大写
    - 大小写严格区分
    - 配对的标签必须一致
    
- 命名空间
    - 为了防止命名冲突
        
              <Student>
                  <Name>LiuYing</Name>
                  <Age>23</Age>
              </Student>
              <Room>
                  <Name>2014</Name>
                  <Location>1-23-1</Location>
              </Room>
                      
    - 如果归并上述两个内容信息,会产生冲突
    
              <Schooler>
                  <Name>LiuYing</Name>
                  <Age>23</Age>
                  <Name>2014</Name>
                  <Location>1-23-1</Location>
              </Schooler>
                      
    - 为了避免冲突,需要给可能冲突元素添加命名空间
    - xmlns: xml name space 的缩写
    
              <Schooler xmlns:student="http://my_student" xmlns:room="http://my_room">
                  <student:Name>LiuYing</student:Name>
                  <Age>23</Age>
                  <room:Name>2014</room:Name>
                  <Location>1-23-1</Location>
              </Schooler>

# XML访问

## 读取
- XML读取分两个主要技术,SAX, DOM
- SAX(Simple API for XML):
    - 基于事件驱动的API
    - 利用SAX解析文档设计到解析器和事件处理两部分
    - 特点:
        - 快
        - 流式读取
        
- DOM
    - 是W3C规定的XML编程接口
    - 一个XML文件再缓存中以树形结构保存,读取
    - 用途
        - 定位浏览XML任何一个节点信息
        - 添加删除相应内容
    - minidom
        - minidom.parse(filename):加载读取的xml文件, filename也可以是xml代码
        - doc.documentElement:获取xml文档对象,一个xml文件只有一个对于的文档对象
        - node.getAttribute(attr_name):获取xml节点的属性值
        - node.getElementByTagName(tage_name):得到一个节点对象集合
        - node.childNodes:得到所有孩子节点
        - node.childNodes[index].nodeValue:获取单个节点值
        - node.firstNode:得到第一个节点,等价于node.childNodes[0]
        - node.attributes[tage_name]

    - etree 
        - 以树形结构来表示xml
        - root.getiterator:得到相应的可迭代的node集合
        - root.iter
        - find(node_name):查找指定node_name的节点,返回一个node
        - root.findall(node_name):返回多个node_name的节点
        - node.tag: node对应的tagename
        - node.text:node的文本值
        - node.attrib: 是node的属性的字典类型的内容
        
- xml文件写入
    - 更改
        - ele.set:修改属性
        - ele.append: 添加子元素
        - ele.remove:删除元素

    - 生成创建
        - SubElement
        - minidom 写入
        - etree创建

一个xml文件示例:

<?xml version="1.0" encoding="utf-8" ?>
<System>
   <Device desc="ControlDevice" size="normal">
       <Type>computer</Type>
       <Cpu Detail="The type of cpu">core_i7</Cpu>
       <Gpu>6G</Gpu>
   </Device>
   <Camera>
       <Type Other="可见光">Visible</Type>
       <Size Detail="The size of get picture">240000</Size>
   </Camera>
   <Camera>
       <Type>Infrared</Type>
       <Size>120000</Size>
   </Camera>
</System>

示例代码及结果:

#!/usr/bin/env python
# -*- coding:utf-8 -*- 

# 使用minidom打开xml文件
import xml.dom.minidom

DOMTree = xml.dom.minidom.parse("device.xml")
#得到文档对象
doc = DOMTree.documentElement

# 显示子元素
for ele in doc.childNodes:
    if ele.nodeName == "Device":
        print("-------Node:{0}-----".format(ele.nodeName))
        childs = ele.childNodes
        for child in childs:
            if child.nodeName == "Type":
                # data是文本节点的一个属性,表示他的值
                print("Type: {0}".format(child.childNodes[0].data))
            if child.nodeName == "Gpu":
                # data是文本节点的一个属性,表示他的值
                print("Gpu: {0}".format(child.childNodes[0].data))
            if child.nodeName == "Cpu":
                # data是文本节点的一个属性,表示他的值
                print("Cpu: {0}".format(child.childNodes[0].data))
                if child.hasAttribute("Detail"):
                    print("Cpu-detail: {0}".format(child.getAttribute("Detail")))
                    
'''
运行结果:
-------Node:Device-----
Type: computer
Cpu: core_i7
Cpu-detail: The type of cpu
Gpu: 6G
'''

# 使用etree打开xml文件
import xml.etree.ElementTree

root = xml.etree.ElementTree.parse("device.xml")
print("利用getiterator访问:")
nodes = root.getiterator()
for node in nodes:
    print("{0}--{1}".format(node.tag, node.text))

print("利用find和findall方法:")
ele_device = root.find("Device")
print(type(ele_device))
print("{0}--{1}".format(ele_device.tag, ele_device.text))

ele_camera = root.findall("Camera")
print(type(ele_camera))
for ele in ele_camera:
    print("{0}--{1}".format(ele.tag, ele.text))
    for cam in ele.getiterator():
        if cam.tag =="Type":
            if "Other" in cam.attrib.keys():
                print(cam.attrib['Other'])

'''
运行结果:
利用getiterator访问:
System--
   
Device--
       
Type--computer
Cpu--core_i7
Gpu--6G
Camera--
       
Type--Visible
Size--240000
Camera--
       
Type--Infrared
Size--120000
利用find和findall方法:
<class 'xml.etree.ElementTree.Element'>
Device--
       
<class 'list'>
Camera--
       
可见光
Camera--
       
'''

自行封装的函数(该部分内容从之前写的程序中抽出的):

#读取并解析xml文件 
def read_xml(in_path):
    tree = ET.parse(in_path)
    return tree

#将xml文件写出 
def write_xml(tree, out_path):
    tree.write(out_path)

#查找某个路径匹配的所有节点 tree: xml树 path: 节点路径
def find_nodes(tree, path):
    root = tree.getroot()
    nodes = root.findall(path)
    return nodes  

#判断某个节点是否包含传入参数属性 node:节点 kv_map:属性及属性值组成的map
def if_match(node, kv_map):   
    for key in kv_map:  
        if node.get(key) != kv_map.get(key):  
            return False  
    return True  

#根据属性及属性值定位节点 nodelist: 节点列表 kv_map: 匹配属性及属性值
def get_node_by_keyvalue(nodelist, kv_map):    
    result_nodes = []  
    for node in nodelist:  
        if if_match(node, kv_map):  
            result_nodes.append(node)  
    return result_nodes  

#修改/增加 /删除 节点的属性及属性值 nodelist: 节点列表 kv_map:属性及属性值
def change_node_properties(nodelist, kv_map, is_delete=False):
    for node in nodelist:
        for key in kv_map:
            if is_delete:
                if key in node.attrib:
                    del node.attrib[key]
            else:
                node.set(key, kv_map.get(key))

#1. 读取xml文件  
tree = read_xml('./devicestatus.xml')
#2. 属性修改  
#A. 找到父节点  
nodes = find_nodes(tree, 'device')
#for i in nodes:
#	print i.tag, i.attrib

#B. 通过属性准确定位子节点  
result_nodes = get_node_by_keyvalue(nodes, {"name":"CarEleStatus"})
#print result_nodes[0].tag, result_nodes[0].attrib
#C. 修改节点属性
change_node_properties(result_nodes, {"value": str(carelevalue)})
#3. 输出到结果文件  
write_xml(tree, "./devicestatus.xml")

二、json
json的一些基础内容:

- 在线工具
    - https://www.sojson.com/
    - http://www.w3school.com.cn/json/
    - http://www.runoob.com/json/json-tutorial.html
- JSON(JavaScriptObjectNotation) 
- 轻量级的数据交换格式,基于ECMAScript
- json格式是一个键值对形式的数据集    
    - key: 字符串
    - value:字符串,数字,列表,json
    - json使用大括号包裹
    - 键值对直接用都好隔开
    
               
        student={
            "name": "wangdapeng",
            "age": 18,
            "mobile":"13260446055"
            }
            
- json和python格式的对应
    - 字符串:字符串
    - 数字:数字
    - 队列:list
    - 对象:dict
    - 布尔值:布尔值
- python for json
    - json包
    - json和python对象的转换
        - json.dumps():对数据编码,把python格式表示成json格式
        - json.loads(): 对数据解码,把json格式转换成python格式
    - python读取json文件
        - json.dump(): 把内容写入文件
        - json.load(): 把json文件内容读入python
#!/usr/bin/env python
# -*- coding:utf-8 -*- 

import json

obj2 = {'Type':('Notebook_2'),'Cpu':('i5'),'Gpu':("GTX1070"),'Id':(2)}
obj3 = {'Type':('Notebook'),'Cpu':('i5'),'Gpu':("GTX1080"),'Id':(3)}

with open('json.txt', 'r') as fp:
    load_dict = json.load(fp)
    tasksinfo = load_dict["Computer"]
    tasksinfo.append(obj2)
    tasksinfo.append(obj3)
    load_dict["Computer"] = tasksinfo
with open("json.txt","w") as dump:
    json.dump(load_dict, dump, indent=4)

代码执行前json:

{
    "System": "", 
    "Computer": [
        {
            "Type": "Notebook", 
            "Detail": "A new computer", 
            "Cpu": "core_i7", 
            "Gpu": "GTX1060", 
            "Id": "1"
        }
    ]
}

代码执行后json:

{
    "System": "",
    "Computer": [
        {
            "Type": "Notebook",
            "Detail": "A new computer",
            "Cpu": "core_i7",
            "Gpu": "GTX1060",
            "Id": "1"
        },
        {
            "Type": "Notebook_2",
            "Cpu": "i5",
            "Gpu": "GTX1070",
            "Id": 2
        },
        {
            "Type": "Notebook",
            "Cpu": "i5",
            "Gpu": "GTX1080",
            "Id": 3
        }
    ]
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值