结构化文件存储-XML

学习XML

XML文件

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

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

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

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

  • XML文件以.xml结尾

XML文档的构成

  • 处理指令(可以认为一个文件内只有一个处理指令)
    • 最多只有一行,且位于第一行;内容是与xml相关的一些声明或指令
  • 根元素(一个文件内只有一个根元素)
  • 子元素
  • 属性
  • 内容
  • 注释
    • 注释不能嵌套在标签里

例如

<?xml version='1.0' encoding='utf-8' ?>
<Class>
    <Student1>
        <name>xiaoming</name>
        <age>15</age>
    </Student1>

    <Student2>
        <name>xiaohong</name>
        <age>13</age>
    </Student2>
</Class>

第一行为处理指令,根元素为Class,Class的子元素为Student

可以双击xml文件在浏览器运行:

若想有多个Class,由于只能有一个根元素,那么此时Class不再是根元素,需后要在最外面增加一个根元素,否则运行会报错


添加属性

<?xml version='1.0' encoding='utf-8' ?>
<School>
    <Class type='online' location='Zhengzhou'>
        <Student>
            <name>xiaoming</name>
            <age>15</age>
        </Student>

        <Student>
            <name>xiaohong</name>
            <age>13</age>
        </Student>
    </Class>

    <Class type='normal' location='Beijing'>
        <Student>
            <name>xiaoming</name>
            <age>15</age>
        </Student>

        <Student>
            <name>xiaohong</name>
            <age>13</age>
        </Student>
    </Class>
</School>

使用注释

<!-- This is a zhushi -->
<!-- This-is-a-zhushi -->  注释内容可以有一个短横线
<!---This-is-a-zhushi-->   三短横线只能出现在开头

保留字符的处理

XML中使用的符号可能跟保留字符相冲突

1.可以使用实体引用(EntityReference)表示来保留字符(转义)

<score> score>80 </score>  出错
<score> score &gt; 80 </score>  使用实体引用

2.可以把含有保留字符的部分放在CDATA块内部(不会被解析器解析)

<![CDATA[<><>><<<]]>

3.与CDATA功能相反的,PCDATA可以包含被解析的字符数据

XML标签命名规则

  • 用英文表示,首字母大写
  • 大小写严格区分
  • 标签要配对、一致

空标签:没有值,所以可以不提供结束标签,但是要必须关闭

如:

<Name />

命名空间

如果将多个内容合并,可能会产生冲突

<Room>
    <Name> bedroom </Name>
    <Location> there </Location>
</Room>

<Person>
    <Name> xiaoming </Name>
    <Age> 15 </Age>
</Person>

合并:

<Info>
    <Name> bedroom </Name>
    <Location> there </Location>

    <Name> xiaoming </Name>
    <Age> 15 </Age>
</Info>

上述就产生了冲突

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

<Infor xmlns:Room="http://my_room" xmlns:Person="http://my_person">
    <Room:Name> bedroom </Room:Name>
    <Location> there </Location>

    <Name> xiaoming </Name>
    <Age> 15 </Age>
</Infor>

XML DOM

XML DOM 定义了访问和处理 XML 文档的标准方法。

根据 DOM,XML 文档中的每个成分都是一个节点。

DOM 是这样规定的:

  • 整个文档是一个文档节点
  • 每个 XML 标签是一个元素节点
  • 包含在 XML 元素中的文本是文本节点
  • 每一个 XML 属性是一个属性节点
  • 注释属于注释节点

使用python进行解析或增改xml时,要以节点进行操作

解析xml

python中的minidom模块

  • minidom.parse():加载读取的xml文件,也可以是xml代码
  • doc.documentElement:获取xml文档对象(根节点)
  • node.getAttribute():获取xml节点的属性值
  • node.getElementsByTagName():得到一个节点对象集合
  • node.childNodes:得到所有孩子节点
  • node.childNodes[index].nodeValue:获得单个节点值

例如,xml文件内容:

<?xml version='1.0' encoding='utf-8' ?>
<Infor>
    <Student1>
        <Location> there </Location>
        <Name> xiaoming </Name>
        <Age> 15 </Age>
    </Student1>

    <Student2>
        <Location> here </Location>
        <Name> xiaohong </Name>
        <Age> 18 </Age>
    </Student2>
</Infor>

使用minidom来解析这个xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import xml.dom.minidom
from xml.dom.minidom import parse

DomTree = xml.dom.minidom.parse('C:/Users/腾飞/Desktop/a.xml') # 获取dom对象

doc = DomTree.documentElement # 获取根节点
print(doc) # Infor

childNodes = doc.childNodes # 得到所有孩子节点列表
print(childNodes) # Student1、Student2

t = doc.getElementsByTagName('Student1') # 得到Student1节点对象列表
print(t)

t1 = t[0] # 取出Student1元素节点
t1_name = t1.childNodes # 得到该节点下的所有孩子节点
print(t1_name) # Location、Name、Age

t1_location = t1.getElementsByTagName('Location')[0] # 得到Student1的location元素节点
t1_location_text = t1_location.childNodes[0] # 得到location文本节点
print(t1_location_text.data) # 使用data方法获得文本

打印结果:

<DOM Element: Infor at 0x155cd50>
[<DOM Text node "'\n\t'">, <DOM Element: Student1 at 0x1589760>, <DOM Text node "'\n\n\t'">, <DOM Element: Student2 at 0x1589850>, <DOM Text node "'\n'">]
[<DOM Element: Student1 at 0x1589760>]
[<DOM Text node "'\n\t\t'">, <DOM Element: Location at 0x15897b0>, <DOM Text node "'\n\t\t'">, <DOM Element: Name at 0x1589710>, <DOM Text node "'\n\t\t'">, <DOM Element: Age at 0x1589800>, <DOM Text node "'\n\t'">]
 there 
写入xml
  • minidom.Document():创建dom树对象
  • dom.createElement():创建根/子节点
  • dom.appendChild():添加节点
  • node.setAttribute():设置节点属性
  • dom.createTextNode():创建文本节点
  • dom.writexml():写入xml

使用minidom生成一个xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#导入minidom
from xml.dom import minidom

# 创建DOM树对象
dom = minidom.Document()

# 创建根节点。每次都要用DOM对象来创建任何节点。
root_node=dom.createElement('root')

# 用DOM对象添加根节点
dom.appendChild(root_node)

# 用DOM对象创建元素子节点
book_node=dom.createElement('Book')

# 设置该节点的属性
book_node.setAttribute('Price','199')

# 用父节点对象添加元素子节点
root_node.appendChild(book_node)

name_node = dom.createElement('Name')
root_node.appendChild(name_node)

# 用DOM创建文本节点,把文本节点(文字内容)看成子节点
name_text=dom.createTextNode('计算机程序设计语言 第1版')

# 用添加了文本的节点对象(看成文本节点的父节点)添加文本节点
name_node.appendChild(name_text)

# 每一个结点对象(包括dom对象本身)都有输出XML内容的方法,如:toxml()--字符串, toprettyxml()--美化树形格式。

try:
with open('C:/Users/腾飞/Desktop/dom_write.xml','w',encoding='UTF-8') as fh:
# 4.writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式,
# 第四个参数制定了换行格式,第五个参数制定了xml内容的编码。
dom.writexml(fh,indent='',addindent='\t',newl='\n',encoding='UTF-8')
print('写入xml OK!')
except Exception as err:
print('错误信息:{0}'.format(err))

打印结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <Book Price="199"/>
    <Name>计算机程序设计语言 第1版</Name>
</root>