结构化文件存储

结构化文件存储

  • XML
    • XML(eXtensibleMarkupLanguage),可扩展标记语言
    • XML文档的构成
    • 保留字符的处理
    • XML标签的命名规则
    • 命名空间
    • XML访问
      • 读取
  • JSON
    • JSON(JavaSciptObjectNotation)
  • 正则表达式(RegularExpression,re)
    • 正则的写法
  • RE练习
    • 大致步骤
    • Re常用函数
    • 查找
    • 替换
    • 匹配中文
    • 贪婪和非贪婪
  • XPath
    • XPath开发工具
    • 选取节点
    • 谓语-Predicates
    • XPath的一些操作

XML

  • XML,JSON
  • 为了解决不同设备之间的信息交换
  • 参考资料:
    • https://docs.python.org/3/library/xml.etree.elementtree.html
    • http://www.runoob.com/python/python-xml.html
    • https://blog.csdn.net/seetheworld518/article/details/49535285

XML(eXtensibleMarkupLanguage),可扩展标记语言

  • 标记语言,语言中使用尖括号括起来的文本字符串标记

  • 可扩展:用户可以自己定义需要的标记

  • 例如:

    
    	自定义标记Teacher
    	在两个标记之间任何内容都应该跟Teacher相关
    
    
  • 是W3C组织指定的一个标准

  • XML描述的是数据本身,即数据的结构和语义

  • HTML侧重于如何显示web页面中的数据

XML文档的构成

  • 处理指令(可以认为一个文件内只有一个处理指令)
    • 最多只有一行,且必须在第一行
    • 内容是与XML本身处理器相关的一些声明或者指令
    • 以XML关键字开头
    • 一般用于声明XML的版本和采用的编码
      • version 属性是必须的
      • encoding 属性用来指出XML解释器使用的编码
  • 根元素(一个文件内只有一个根元素)
    • 在整个XML文件中,可以把根元素看作一个树状结构
    • 根元素有且只能有一个
  • 子元素
  • 属性
  • 内容
    • 表明标签所存储的信息
  • 注释
    • 起说明作用的信息
    • 注释不能嵌套在标签内
    • 只有在注释的开始和结尾使用双短横线
    • 三短横线只能出现在注释的开头而不能用在结尾
         #可以
    >    #不可以,注释在标签内
    
      #可以,注释内容可以有一个短横线
      #不可以,双短横线只能出现在开头或结尾
    
     #可以,三短横线只能出现在开头
     #不可以,三短横线只能出现在开头
    

保留字符的处理

  • XML中使用的符号可能跟实际符号相冲突,典型的就是左右尖括号

  • 使用实体引用(EntityReference)来表示保留字符

     score>80  #有错误,xml中不能出现>
     score>80 #使用实体引用
    
  • 把含有保留字符的部分放在CDATA块的内部,CDATA块把内部信息视为不需要转义。

    80
    	]]>
    
  • 常用的需要转义的保留字符和对应的实体引用

    • &:&
    • <:<
    • >:>
    • ':'
    • ":"
    • 一共5个,每个实体引用都以&开头并且以分号结尾

XML标签的命名规则

  • Pascal命名法
  • 用单词表示,第一个字母大写
  • 大小写严格区分
  • 配对的标签必须一致

命名空间

  • 为了防止命名冲突

	YingYU
	23


	2018
	1-23-1

  • 假设把上述代码两个内容信息归并,name属性就会产生冲突

	YingYU
	23

	2018
	1-23-1

  • 为了避免冲突,需要给可能冲突元素添加命名空间
  • xmlns:xml name space 的缩写

	YingYU
	23

	2018
	1-23-1

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_name的节点
      • node.tag:node对应的tagename
      • node.text:node的文本值
      • node.attrib:是node的属性的字典类型的内容
    import xml.etree.ElementTree
    
    root = xml.etree.ElementTree.parse("student.xml")
    print("利用getiterator访问:")
    nodes = root.getiterator()
    for node in nodes:
    	print("{0}--{1}".format(node.tag,note.text))
    
    print("利用find和findall方法:")
    ele_teacher = root.find("Teacher")
    print("{0}--{1}".format(ele_teacher.tag,ele_teacher.text))
    
    ele_stus = root.findall("Teacher")
    for ele in ele_stus:
    	print("{0}--{1}".format(ele.tag,ele.text))
    	for sub in ele.getiterator():
    		if sub.tag == "Name":
    			if "Other" in sub.attrib.keys():
    				print(sub.attrib['Other'])
    
  • XML文件写入

    • 更改
      • ele.set:修改属性
      • ele.append:添加子元素
      • ele.remove:删除元素
    import xml.etree.ElementTree as et
    
    tree = et.parse(r'to_edit.xml')
    root = tree.getroot()
    for e in root.iter('Name'):
    	print(e.text)
    
    for stu in root.iter('Student'):
    	name = stu.find('Name')
    	if name != None:
    		name.set('test',name.text * 2)
    
    stu = root.find('Student')
    
    #生成一个新的元素
    e = et.Element('ADDer')
    e.attrib = {'a':'b'}
    e.text = '我添加的'
    
    stu.append(e)
    #一定要把修改好的内容写回文件,否则无效
    tree.write('to_edit.xml')
    
  • 生成创建

    • SubElement
    import xml.etree.ElementTree as et
    
    stu = et.Element("Student")
    
    name = et.SubElement( stu,'Name')
    name.attrib = {'lang','en'}
    name.text = 'tiantiandouxihuanni'
    
    age = et.SubElement(stu,'Age')
    age.text = 18
    
    et.dump(stu)
    
    • minidom写入
    • etree创建

JSON

  • 参考文档
    • https://www.sojson.com/
    • http://www.w3school.com.cn/json/
    • http://www.runoob.com/json/json-tutorial.html

JSON(JavaSciptObjectNotation)

  • 轻量级的数据交换格式,基于ECMAScript

  • json格式是一个键值对形式的数据集

    • key:字符串
    • value:字符串,数字,列表,json
    • json使用大括号包裹
    • 键值对直接用逗号隔开
    student={
    	"name":"wangda",
    	"age":19,
    	"mobile":"123345454",
    	}
    
  • 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
      import json
      
      # 此时student是一个dict格式内容,不是json
      student = {
      	"name":"yuyuyu",
      	"age":19
      	"mobile":"122398392"
      	}
      print(type(student))
      
      stu_json = json.dumps(student)
      print(type(stu_json))
      print("JSON对象:{0}".format(stu_json))
      
      stu_dict = json.loads(stu_json)
      print(type(stu_dict))
      ptint(stu_dict)
      
    • JSON文档的读取也跟python一样
      import json
      
      data = {"name":"haha","age":12}
      
      with open("t.json",'w') as f:
      	json.dump(data,f)
      
      with open("t.json",'r') as f:
      	d = json.load(f)
      	print(d)
      

正则表达式(RegularExpression,re)

  • 这里随便写一下正则表达式,更为详细的资料后期会继续整理
  • 正则表达式是一个计算机科学的概念
  • 用于使用单个字符串来描述,匹配符合某个规则的字符串
  • 用来检索、替换某些文本

正则的写法

  • .(点号):表示人一个字符,除了\n,比如查找所有的一个字符\.
  • []:匹配中括号中列举的任意字符,比如[L,Y,O]能被LLY,YO匹配,LIU(这个匹配不了)
  • \d:任意一个数字
  • \D:除了数字都可以
  • \s:表示空格,tab键
  • \S:除了空白符合(除了空格)
  • \w:单词字符,就是a-z,A-Z,0-9,_
  • \W:除了上面\w的内容
  • *:表示前面的内容重复零次或者多次
  • +:表示前面内容至少出现一次
  • ?:前面出现的内容零次或者一次
  • {m,n}:允许前面内容出现最少m次,最多n次
  • ^:匹配字符串的开始
  • &:匹配字符串的结尾
  • \b:匹配单词的边界
  • ():对正则表达式内容进行分组,从第一个括号开始,编号逐渐增大
  • \A:只匹配字符串开头
  • \Z:仅匹配字符串末尾
  • |:左右任意一个
  • (?P...):分组,除了原来的编号再制定一个别名
  • (?P=name):引用分组
验证一个数字:^\d$
必须有一个数字,最少一位:^\d+$
只能出现数字,且位数为5-10位:^\d{5,10}$
注册者输入年龄,要求16岁以上,99岁以下:^[16-99]$
只能输入英文字符和数字:^[A-Za-z0-9]$
验证qq号码:[0-9]{5,12}

RE练习

大致步骤

  • 使用compile将表示正则的字符串编译为一个pattern对象
  • 通过pattern对象提供一系列方法对文本进习查找匹配,获得匹配结果,一个Match对象
  • 最后使用Match对象提供的属性和方法获得信息,根据需要进行操作

Re常用函数

  • group():获得一个或者多个分组匹配的字符串,当要获得整个匹配的子串时,直接使用group或者group(0)

  • start:获取分组匹配的子串在整个字符串中的起始位置,参数默认为0

  • end:获取分组匹配的子串在整个字符串中的结束位置,默认为0

  • span:返回的结构技术(start(group),end(group))

    # 查找数字
    import re 
    
    # r表示字符串不转义
    p = re.compile(r'\d+')
    # 在字符串"one12twothree33434354five332"中查找,按照规则p指定的正则进行查找
    # 返回结果是None表示没有找到,否则会返回match对象
    m = p.match("one12twothree33434354five332",3,19)
    
    print(m)
    

    输出结果为:

    <_sre.SRE_Match object; span=(3, 5), match='12'>
    

    以上代码说明:match可以输入参数表示起始位置;查找到的结果只包含一个,表示第一次进行匹配成功的内容

    import re
    # l表示忽略大小写
    p = re.compile(r'([a-z]+) ([a-z)+',re.l)
    
    m = p.match("I am really love you")
    print(m)
    print(m.group(0))
    print(m.start(0))
    print(m.end(0))
    

查找

  • search(str,pos[,endpos]):在字符串中查找匹配,pos跟endpos表示起始和结尾位置

  • findall:查找所有

  • finditer:查找,返回一个iter结果

    import re
    p = re.compile(r'\d+')
    
    m = p.search("one12two34three476four")
    f = p.findall("one12two34three476four")
    
    print(type(f))
    print(f)
    print(m.group)
    

替换

  • sub(rep1,str[,count])

    import re
    p = re.compile(r'(\w+) (\w+)')
    
    s = "hello 123 wang 23213 xiao ,osa you"
    rst = p.sub(r'Hello world',s)
    
    print(rst)
    

匹配中文

  • 大部分中文内容表示范围是[u4e00-u9fa5],不包括全角标点

    import re
    title = u'世界 你哈皮, hello mo"
    p = re.compile(r'[\u4e00-\u9fa5]+')
    rst = p.findall(title)
    
    print(rst)
    

贪婪和非贪婪

  • 贪婪:尽可能多的匹配,(*)表示贪婪匹配

  • 非贪婪:找到符合条件的最小内容即可,(?)表示非贪婪

  • 正则默认使用贪婪匹配

    import re
    
    title = u'
    name
    age
    ' p1 = re.compile(r"
    .*
    ") p2 = re.compile(r"
    .*?
    ") m1 = p1.search(title) print(m1.group()) m2 = p2.search(title) print(m2.group())

    结果为:

    name
    age
    name

XPath

  • 在XML文件中查找信息的一套规则/语言,根据XML的元素或者属性进行遍历
  • http://www.w3school.com.cn/xpath/index.asp
  • 下述代码作为案例
    
    
       
       	Yull
       	18
       	458788978978
       
       
       	Zangz
       	14
       
       
       	Sans
       	16
       	5487878454
       
    
    

XPath开发工具

  • 开源的XPath表达式编辑工具:XMLQuire
  • Chrome插件:XPath Helper
  • Firefox插件:XPath Checker

选取节点

  • nodename:选取此节点的所有子节点

  • /:从根节点开始选取

    /Student:没有结果
    /School:选取School节点
    
  • //:选取节点,不考虑位置

    //age:选取出三个节点,一般组成列表返回
    
  • .:选取当前节点

  • …:选取当前节点的父亲节点

  • @:选取属性

  • XPath中查找一般按照路径方法查找,以下是路径表示方法:

    School/Teacher:返回Teacher节点
    School/Student:返回两个Student节点
    //Student:选取所有Student的节点,不考虑位置
    School//Age:选取School后代中所有Age节点
    //@Other:选取Other属性
    //Age[@detail):选取带有属性Detail的Age元素
    

谓语-Predicates

- /School/Student[1]:选取School下面的第一个Student节点
- /School/Student[last()]:选取School下面的最后一个Student节点
- /School/Student[last()-1]:选取School下面的倒数第二个Student节点
- /School/Student[position()<3]:选取School下面的前两个Student节点
- //Student[@score]:选取带有属性score的Student节点
- //Student[@score="99"]:选取带有属性score并且属性值是99的Student节点
- //Student[@score]/Age:选取带有属性score的Student节点的子节点Age

XPath的一些操作

  • |:或者

    //Student[@score] | //Teacher:选取带有属性score的Student节点和Teacher节点
    
  • 其余不常见XPath运算符号:+,-,*,div,<,>

你可能感兴趣的:(语法)