整体文章目录
一、 当前章节目录
二、XML介绍
2.1 XML的演进历史
- 由于HTML扩展性不强,引入SGML发展成XML
- XML定义:可扩展标记语言(XML)是标准通用标记语言(SGML)的一个子集。
- 定义XML目的:使得在Web上能以现有超文本标记语言(HTML)的使用方式,接收和处理通用的SGML的方式成为可能。
- XML设计需要考虑:现实的方便性,也要注意到不同语音之间的互操作性。
2.2 XML的优点和限制
优点:
- 可以作为一个很好的数据交换方法,使得其成为很多配置文件的首选
- 具有简单性。
- 是自描述的,可供计算机处理,同时数据也可以重用。
- 是一种结构化的语义标记语言,而不是一种数据表示语言。
- 对于允许的元素方面非常灵活。
限制:
- 但是本身并不具备数据处理的能力。
- 保持着非常严格的语法检查。
2.3 XML技术的Python支持
-
SAX:
- 事件驱动方式来处理XML文档:遇到特定标签调用指定方法,实现对特殊标签的处理。
- 流数据方式来处理XML文档:读取部分数据后就进行处理,满足条件后终止对于XML文档解析。提高了处理速度。
-
DOM:
- 通过树结构和数据来表示的信息集合。使得容易访问各个元素,添加、修改和删除特定的元素也是比较容易的。会消耗大量的内存和处理器时间。
三、XML文档概览和验证
3.1 XML文档的基础概念
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<goods>
<shirt>
<name>Helen</name>
<size>170</size>
<quantity>10</quantity>
<color>black</color>
</shirt>
<shirt>
<name>First</name>
<size>175</size>
<quantity>9</quantity>
<color>white</color>
</shirt>
</goods>
3.2 XML文档的结构良好性验证
为使得XML文档成为一个结构良好的文档,需要遵守以下规则:
- 所有的开始标签必须有对应的结束标签。
- 元素可以嵌套,但是不能交叠。
- 有且只能有一个根元素。
- 属性值必须使用引号包含起来。
- 一个元素不能包含两个同名属性。
- 注释不能出现在标签内部。
- 没有转义的“<”或者“&”不能出现在元素和属性的字符中。
import xml.etree.ElementTree as ET
try:
ET.parse(r"C:\Users\86155\8first.xml")
print("这是一个良构的XML文档")
except Exceptionas as e:
print("这可能是一个非良构文档")
print("出错信息:", e)
<!--8first.xml-->
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<goods>
<shirt>
<name>Helen</name>
<size>170</size>
<quantity>10</quantity>
<color>black</color>
</shirt>
<shirt>
<name>First</name>
<size>175</size>
<quantity>9</quantity>
<color>white</color>
</shirt>
</goods>
运行结果:
这是一个良构的XML文档
<!--将</goods>改为<goods>-->
<goods>
<!--省略部分代码-->
<goods>
运行结果:
这是一个非良构的XML文档
<!--省略部分代码-->
</goods>
</shirt>
运行结果:
这是一个非良构的XML文档
<!--省略部分代码-->
</goods>
</shirt>
运行结果:
这是一个非良构的XML文档
<!--省略部分代码-->
</goods>
<goods></goods>
运行结果:
这是一个非良构的XML文档
<?xml version=1.0 encoding='utf-8' standalone='no' ?>
<!--省略部分代码-->
运行结果:
这是一个非良构的XML文档
# lxml可以通过异常的类别区分是不是非良构文档
import lxml.etree as ET # 需要安装第三方库lxml
try:
ET.parse(r"C:\Users\86155\8first.xml")
print("这是一个良构的XML文档")
except SyntaxError as e:
print("这可能是一个非良构文档")
print("出错信息:", e)
3.3 XML文档的有效性验证
- 为了规范XML文档中的元素及其使用方式,XML规范中通过使用DTD文件与XML Schema文件来对其进行描述。
- XML Schema与DTD区别:
- Schema本身也是XML文档,DTD定义跟XML没有什么关系,Schema在理解和实际应用有很多的好处。
- DTD文档的结构是“平铺型”的,如果定义复杂的XML文档,很难把握各元素之间的嵌套关系;Schema文档结构性强,各元素之间的嵌套关系非常直观。
- DTD只能指定元素含有文本,不能定义元素文本的具体类型,如字符型、整型、日期型、自定义类型等。Schema在这方面比DTD强大。
- Schema支持元素节点顺序的描述,DTD没有提供无序情况的描述,要定义无序必需穷举排列的所有情况。Schema可以利用xs:all来表示无序的情况,继承了XML的自描述性和可扩展性。
- 对命名空间的支持。DTD无法利用XML的命名空间,Schema很好满足命名空间。并且,Schema还提供了include和import两种引用命名空间的方法。
- XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD。
- XML DTD本身的合法性却缺少较好的验证机制,必需独立处理。XML Schema则不同,它与XML有着同样的合法性验证机制。
# DTD验证文档有效性
import lxml.etree as ET
dtd = ET.DTD('dtd_file.dtd')
f = open('xml_file.xml')
xml = ET.XML(f.read())
dtd.validate(xml)
In [1]: import lxml.etree as ET
In [2]: from io import StringIO
In [3]: f = StringIO("<!ELEMENT empty EMPTY>")
In [4]: dtd = ET.DTD(f)
In [5]: xml = ET.XML("<empty/>")
In [6]: dtd.validate(xml)
Out[6]: True
In [7]: xml = ET.XML("<empty>content</empty>")
In [8]: dtd.validate(xml)
Out[8]: False
In [9]: dtd.error_log.filter_from_errors()[0]
<string>:1:0:ERROR:VALID:DTD_NOT_EMPTY: Element empty was declared EMPTY this one has content
# XML Schema文档有效性验证
In [1]: import lxml.etree as ET
In [2]: from io import StringIO
In [3]: f = StringIO('''
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="a" type="AType"/>
<xsd:complexType name="AType">
<xsd:sequence>
<xsd:element name="b" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
''')
In [4]: xmlschema_doc = ET.parse(f)
In [5]: xmlschema = ET.XMLSchema(xmlschema_doc)
In [6]: valid_str = StringIO('<a><b></b></a>')
In [7]: xml1 = ET.parse(valid_str)
In [8]: xmlschema.validate(xml1)
Out[8]: True
In [9]: invalid_str = StringIO('<a><c></c></a>')
In [10]: xml2 = ET.parse(invalid_str)
In [11]:xmlschema.validate(xml2)
Out[11]: False
In [12]: print(xmlschema.error_log)
<string>:1:0:ERROR:SCHEMASV:SCHEMAV_ELEMENT_CONTENT: Element 'c': This element is not expected. Expected is ( b ).
四、分析XML文档结构
4.1 XML的元素和标签
In [1]: import xml.etree.ElementTree as ET
In [2]: root = ET.Element("color") # color为标签名
In [3]: root.text = "black" # black为内容
In [4]: tree = ET.ElementTree(root) #
In [5]: tree.write('D:/xml1.xml', encoding = 'UTF-8')
In [6]: ET.ElementTree(ET.Element("br")).write('D:/xml2.xml', encoding='UTF-8')
In [7]: color = ET.Element("color")
In [8]: COLOR = ET.Element("COLOR")
In [9]: color.tag == COLOR.tag
Out[9]: False
In [10]: color_clone = ET.Element("color")
In [11]: color.tag == color_clone.tag
Out[11]: True
- goods是根元素。
- shirt是goods的子元素。
- shirt是name、size、quantity、color的父元素。
- name、size、quantity、color之间互为兄弟元素。
# 演示如何构建子元素
In [12]: root = ET.Element("goods")
In [13]: shirt = ET.SubElement(root,"shirt")
In [14]: name = ET.SubElement(shirt,"name")
In [15]: size = ET.SubElement(shirt,"size")
In [16]: tree = ET.ElementTree(root)
In [17]: tree.write('D:/xml3.xml', encoding='UTF-8')
In [18]: name.text = "Helen"
In [19]: size.text ="170"
In [20]: ET.dump(tree)
<goods><shirt><name>Helen</name><size>170</size></shirt></goods>
4.2 元素的属性
<!--xml3.xml-->
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<goods>
<shirt quality="A">
<name>Helen</name>
<size>170</size>
<quantity>10</quantity>
<color>black</color>
</shirt>
<shirt quality='B'>
<name>First</name>
<size>175</size>
<quantity>9</quantity>
<color>white</color>
</shirt>
</goods>
In [21]: shirt = ET.Element("shirt")
In [22]: shirt.attrib["quality"] = "A"
In [23]: ET.dump(shirt)
<shirt quality="A" />
In [24]: shirt = ET.Element("shirt", quality="A")
In [25]: ET.dump(shirt)
<shirt quality="A" />
<!--运行之后获得-->
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<goods>
<shirt quality="A" size="170">
<name>Helen</name>
<size>170</size>
<quantity>10</quantity>
<color>black</color>
</shirt>
<shirt quality='B' size='175'>
<name>First</name>
<size>175</size>
<quantity>9</quantity>
<color>white</color>
</shirt>
</goods>
4.3 XML的名字
对于使用Unicode字符的元素,可以在原来的文件中加入一个元素,其组成如下。
<牛仔裤 质量 = '一等品'>
<品牌>西部传奇</品牌>
<大小>175</大小>
<数量>20</数量>
<颜色>棕蓝色</颜色>
</牛仔裤>
# 非法字符解析将提示错误
In [27]: invalid = ET.Element("%my name")
In [28]: invalid.text = "content"
In [29]: ET.dump(invalid)
<%my name>content</%my name>
In [30]: from io import StringIO
In [31]: ET.parse(StringIO(ET.dump(invalid)))
<%my name>content</%my name>
Traceback (most recent call last):
# 省略部分输出
ParseError: no element found: line 1, column 0
4.4 字符实体
In [32]: entity_ref = ET.XML("<a><</a>")
In [33]: ET.dump(entity_ref)
<a><</a>
In [34]: entity_ref.text
'<'
In [35]: entity_ref = ET.XML("<a>&entity;</a>")
Traceback (most recent call last):
# 省略部分代码
ParseError: undefined entity: line 1, column
4.5 CDATA段
CDATA段用来声明不应被解析为标签的文本。(其中可以使用特殊字符,包括小于号、大于号和双引号等,而不必使用其字符实体。)
<?xml version="1.0" encoding="utf-8" standalone='no' ?>
<source>
<function>
<min>
def min(x, y):
if x < y: return x
else: return y
</min>
</function>
</source>
<?xml version="1.0" encoding="utf-8" standalone='no' ?>
<source>
<function>
<min>
def min(x, y):
if x < y: return x
else: return y
</min>
</function>
</source>
<?xml version="1.0" encoding="utf-8" standalone='no' ?>
<source>
<function>
<min>
<![CDATA[
def min(x, y):
if x < y: return x
else: return y
]]>
</min>
</function>
</source>
4.6 注释
<!--这些货物信息还需要进一步核实-->
In [36]: xml_str="""<test>
<!-- Comment -->
content
</test>
"""
In [37]: tree = ET.XML(xml_str)
In [38]: ET.dump(tree)
<test>
content
</test>
4.7 处理指令
- XML文档可以通过处理指令允许其包括用于特定应用的指令。
- 一个处理指令通过"<?"和"?>"来界定。
- 紧接在"<?"后面的是处理指令名,接着是属性值对。
- 例如:<?robots index="yes" follow="no"?>
4.8 XML定义
<?xml version="1.0" encoding="ASCII" standalone="yes"?>
<name>
Alice
</name>
- encoding
- 在XML定义中是可选的,如果省略的话,则默认采用了Unicode字符集。
- 如果元信息和编码定义冲突的话,则会优先采用元信息。
- standalone
- 属性用来定义外部定义的DTD的存在性,取值可为yes或no,默认情况下为no。
- 当为no的时候表示此XML文档不是独立的,而是取决于外部定义的DTD;
- 而为yes则表示此XML文档是自包含的。这也是个可选的属性。
五、使用SAX处理XML文档
5.1 SAX介绍
SAX是一种流行的解析和处理XML文档的接口。
5.2 SAX处理的组成部分
- ContentHandler接口
from xml.sax import *
from io import StringIO
class MyHandler(ContentHandler):
def startDocument(self): # 开始处理文档的时候调用
print("开始处理XML文档")
print("================")
print("name\tquality")
print("================")
def endDocument(self): # 结束处理文档的时候调用
print("================")
print("结束处理XML文档")
def startElement(self, name, attrs): # 处理元素
if name == "shirt":
print("%s\t%s"%(attrs['name'], attrs['quality']))
parser = make_parser() # 生成解析对象
parser.setContentHandler(MyHandler())
# 需要分析的XML数据
data = """<goods>
<shirt name="Helen" quality="A" />
<shirt name="Fayer" quality="A+" />
<shirt name="Dayie" quality="B+" />
<shirt name="CaC" quality="A-" />
</goods>
"""
parser.parse(StringIO(data))
运行结果:
开始处理XML文档
================
name quality
================
Helen A
Fayer A+
Dayie B+
CaC A-================
结束处理XML文档
- DTDHandler接口
class MyHandler(DTDHandler):
pass
parser = make_parser()
parser.setDTDHandler(MyHandler())
- EntityResolver接口
class MyHandler(EntityResolver):
pass
parser = make_parser()
parser.setEntityResolver(MyHandler())
- ErrorHandler接口
class MyHandler(EntityResolver):
pass
parser = make_parser()
parser.setErrorHandler(MyHandler())
- XMLReader接口
class MyHandler(EntityResolver):
pass
parser = make_parser()
handler = parser.getErrorHandler()
六、使用DOM处理XML文档
6.1 DOM介绍
DOM是另外一种流行的解析和处理XML文档的接口规范,可以用来访问XML文档中的数据。
6.2 xml.dom模块中的接口操作
- DOMImplemetation接口
In [1]: from xml.dom.minidom import DOMImplementation
In [2]: implementation = DOMImplementation()
In [3]: implementation.hasFeature("Core", "2.0")
Out[3]: True
In [4]: implementation.hasFeature("Events", "2.0")
Out[4]: False
In [5]: implementation._features
Out[5]: [('core', '1.0'),
('core', '2.0'),
('core', None),
('xml', '1.0'),
('xml', '2.0'),
('xml', None),
('ls-load', '3.0'),
('ls-load', None)]
In [6]: doctype = implementation.createDocumentType("Goods", "", "Goods.dtd")
In [7]: document = implementation.createDocument("", "goods", doctype)
In [8]: document
Out[8]: <xml.dom.minidom.Document at 0x18aaf8e0f40>
- Document接口
In [1]: from xml.dom.minidom import parse,parseString
In [2]: dom1 = parse(r"C:/Users/86155/8first.xml")
In [3]: dom1
Out[3]: <xml.dom.minidom.Document at 0x1e25dbcfa00>
In [4]: fp = open(r"C:/Users/86155/8first.xml", "r", encoding='utf8')
In [5]: dom2 = parse(fp)
In [6]: dom2
Out[6]: <xml.dom.minidom.Document at 0x1e25dbe47c0>
In [7]: fp.close()
In [8]: data = """
<goods>
<shirt quality="A">
<size>170</size>
</shirt>
</goods>
"""
In [9]: dom3 = parseString(data)
In [10]: dom3
Out[10]: <xml.dom.minidom.Document at 0x1e25dbe4760>
In [11]: dom3.toxml()
Out[11]: '<?xml version="1.0" ?><goods>\n <shirt quality="A">\n <size>170</size>\n </shirt>\n </goods>'
In [12]: print(dom3.toxml())
Out[12]: <?xml version="1.0" ?><goods>
<shirt quality="A">
<size>170</size>
</shirt>
</goods>
In [13]: elem = dom3.createElement("element")
In [14]: elem.toxml()
Out[14]: '<element/>'
In [15]: text = dom3.createTextNode("Text date")
In [16]: text.toxml()
Out[16]: 'Text date'
In [17]: attrib = dom3.createAttribute("quality")
In [18]: attrib.name
Out[18]: 'quality'
- Node接口
In [1]: from xml.dom.minidom import *
In [2]: dom1 = parse(r"C:/Users/86155/8first.xml")
In [3]: root = dom1.documentElement
In [4]: root
Out[4]: <DOM Element: goods at 0x2978c9c0160>
In [5]: root.nodeType
Out[5]: 1
In [6]: root.ELEMENT_NODE
Out[6]: 1
In [7]: childs = root.childNodes
In [8]: childs
Out[8]: [<DOM Text node "'\n '">,
<DOM Element: shirt at 0x2978c9c0ca0>,
<DOM Text node "'\n '">,
<DOM Element: shirt at 0x2978c9ffa60>,
<DOM Text node "'\n'">]
In [9]: shirt = root.childNodes[1]
In [10]: shirt
Out[10]: <DOM Element: shirt at 0x2978c9c0ca0>
In [11]: shirt.parentNode
Out[11]: <DOM Element: goods at 0x2978c9c0160>
In [12]: parent = shirt.parentNode
In [13]: parent == root
Out[13]: True
In [14]: root.firstChild
Out[14]: <DOM Text node "'\n '">
In [15]: root.lastChild
Out[15]: <DOM Text node "'\n'">
In [16]: shirt.previousSibling
Out[16]: <DOM Text node "'\n '">
In [17]: shirt.nextSibling
Out[17]: <DOM Text node "'\n '">
In [18]: attrib = shirt.attributes
In [19]: attrib.items()
Out[19]: [('quality', 'A')]
- Element接口
In [20]: shirt.tagName
Out[20]: 'shirt'
In [21]: shirt.getAttribute("quality")
Out[21]: ''
In [22]: print(shirt.toxml())
Out[22]: <shirt>
<name>Helen</name>
<size>170</size>
<quantity>10</quantity>
<color>black</color>
</shirt>
In [23]: shirt.setAttribute("quality", "B")
In [24]: print(shirt.toxml())
Out[24]: <shirt quality="B">
<name>Helen</name>
<size>170</size>
<quantity>10</quantity>
<color>black</color>
</shirt>
- Text接口
In [25]: name = shirt.childNodes[1]
In [26]: name.childNodes
Out[26]: [<DOM Text node "'Helen'">]
In [27]: name_text = name.childNodes[0]
In [28]: name_text.data
Out[28]: 'Helen'
6.3 对XML文档的操作
- 对XML文档的遍历
In [29]: def traversal(node):
if not node.childNodes: # 递归结束条件
return
for child in node.childNodes:
print(child)
traversal(child) # 递归调用
In [30]: traversal(root)
<DOM Text node "'\n '">
<DOM Element: shirt at 0x20adeb81dc0>
<DOM Text node "'\n '">
<DOM Element: name at 0x20adebbe940>
<DOM Text node "'Helen'">
<DOM Text node "'\n '">
<DOM Element: size at 0x20adebbe9d0>
<DOM Text node "'170'">
<DOM Text node "'\n '">
<DOM Element: quantity at 0x20adebbea60>
<DOM Text node "'10'">
<DOM Text node "'\n '">
<DOM Element: color at 0x20adebbeaf0>
<DOM Text node "'black'">
<DOM Text node "'\n '">
<DOM Text node "'\n '">
<DOM Element: shirt at 0x20adebbeb80>
<DOM Text node "'\n '">
<DOM Element: name at 0x20adebbec10>
<DOM Text node "'First'">
<DOM Text node "'\n '">
<DOM Element: size at 0x20adebbeca0>
<DOM Text node "'175'">
<DOM Text node "'\n '">
<DOM Element: quantity at 0x20adebbed30>
<DOM Text node "'9'">
<DOM Text node "'\n '">
<DOM Element: color at 0x20adebbedc0>
<DOM Text node "'white'">
<DOM Text node "'\n '">
<DOM Text node "'\n'">
from xml.dom.minidom import *
dom1 = parse(r"C:/Users/86155/8first.xml")
root = dom1.documentElement
def another_traversal(node):
if not node.childNodes:
return
firstChild = node.firstChild
next = firstChild
while next:
print(next)
another_traversal(next)
next = next.nextSibling
if __name__=="__main__":
another_traversal(root)
运行结果:
<DOM Text node “’\n '”>
<DOM Element: shirt at 0x1aff6e7dd30>
<DOM Text node “’\n '”>
<DOM Element: name at 0x1aff6e978b0>
<DOM Text node “‘Helen’”>
<DOM Text node “’\n '”>
<DOM Element: size at 0x1aff6e97940>
<DOM Text node “‘170’”>
<DOM Text node “’\n '”>
<DOM Element: quantity at 0x1aff6e979d0>
<DOM Text node “‘10’”>
<DOM Text node “’\n '”>
<DOM Element: color at 0x1aff6e97a60>
<DOM Text node “‘black’”>
<DOM Text node “’\n '”>
<DOM Text node “’\n '”>
<DOM Element: shirt at 0x1aff6e97af0>
<DOM Text node “’\n '”>
<DOM Element: name at 0x1aff6e97b80>
<DOM Text node “‘First’”>
<DOM Text node “’\n '”>
<DOM Element: size at 0x1aff6e97c10>
<DOM Text node “‘175’”>
<DOM Text node “’\n '”>
<DOM Element: quantity at 0x1aff6e97ca0>
<DOM Text node “‘9’”>
<DOM Text node “’\n '”>
<DOM Element: color at 0x1aff6e97d30>
<DOM Text node “‘white’”>
<DOM Text node “’\n '”>
<DOM Text node “’\n’”>
- 对XML文档的查询
from xml.dom.minidom import *
dom1 = parse(r"C:/Users/86155/8first.xml")
root = dom1.documentElement
def search_by_traversal(node, name):
if not node.childNodes:
return
for child in node.childNodes:
if child.nodeType == Node.ELEMENT_NODE and child.tagName == name:
print(child.toxml())
traversal(child)
if __name__ == "__main__":
search_by_traversal(root, "color")
运行结果:
black
white
In [31]: root.getElementsByTagName("color")
Out[31]: [<DOM Element: color at 0x20adebbeaf0>, <DOM Element: color at 0x20adebbedc0>]
In [32]: colors = root.getElementsByTagName("color")
In [33]: for color in colors:
print(color.toxml())
<color>black</color>
<color>white</color>
In [34]: shirts = root.getElementsByTagName("shirt")
In [35]: shirt1 = shirts[0]
In [36]: color1 = shirt1.getElementsByTagName("color")[0]
In [37]: color1.toxml()
Out[37]: '<color>black</color>'
In [38]: shirt2 = shirts[1]
In [39]: color2 = shirt2.getElementsByTagName("color")[0]
In [40]: color2.toxml()
Out[40]: '<color>white</color>'
- 对XML文档的增删改
In [41]: goods = dom1.createElement("goods")
In [42]: goods.toxml()
Out[42]: '<goods/>'
In [43]: test = dom1.createElement("test")
In [44]: text = dom1.createTextNode("This is a text node")
In [45]: text
Out[45]: <DOM Text node "'This is a '...">
In [46]: test.appendChild(text)
Out[46]: <DOM Text node "'This is a '...">
In [47]: goods.appendChild(test)
Out[47]: <DOM Element: test at 0x20adebcfee0>
In [48]: goods
Out[48]: <DOM Element: goods at 0x20adebcfb80>
In [49]: goods.toxml()
Out[49]: '<goods><test>This is a text node</test></goods>'
In [50]: goods.removeChild(test)
Out[50]: <DOM Element: test at 0x20adebcfee0>
In [51]: goods
Out[51]: <DOM Element: goods at 0x20adebcfb80>
In [52]: goods.toxml()
Out[52]: '<goods/>'
In [53]: goods.appendChild(test)
Out[53]: <DOM Element: test at 0x20adebcfee0>
In [54]: goods.toxml()
Out[54]: '<goods><test>This is a text node</test></goods>'
In [55]: test2 = dom1.createElement("test2")
In [56]: goods.replaceChild(test2,test)
Out[56]: <DOM Element: test at 0x20adebcfee0>
In [57]: goods.toxml()
Out[57]: '<goods><test2/></goods>'
In [58]: goods.removeChild(test2)
Out[58]: <DOM Element: test2 at 0x20adebcfd30>
In [59]: shirt = dom1.createElement("shirt")
In [60]: goods.appendChild(shirt)
Out[60]: <DOM Element: shirt at 0x20adebcfca0>
In [61]: shirt.setAttribute("quality", "A")
In [62]: name = dom1.createElement("name")
In [63]: text = dom1.createTextNode("Helen")
In [64]: name.appendChild(text)
Out[64]: <DOM Text node "'Helen'">
In [65]: shirt.appendChild(name)
Out[65]: <DOM Element: name at 0x20adebcfaf0>
In [66]: size = dom1.createElement("size")
In [67]: text = dom1.createTextNode("170")
In [68]: size.appendChild(text)
Out[68]: <DOM Text node "'170'">
In [69]: shirt.appendChild(size)
Out[69]: <DOM Element: size at 0x20adebcfc10>
In [70]: goods.toxml()
Out[70]: '<goods><shirt quality="A"><name>Helen</name><size>170</size></shirt></goods>'
七、习题
习题:
- XML文档分为哪两个部分?
- 在DTD中使用什么标记声明元素类型?
- 使用Python验证下面XML文档,并进行解析,获取每个员工的数据。
<employees>
<employee id="1">
<name>张三</name>
<age>32</age>
<sex>男</sex>
<address>上海</address>
</employee>
<employee id="2">
<name>李四</name>
<age>22</age>
<sex>男</sex>
<address>北京</address>
</employee>
</employees>
答案:
- 第一部分是XML文档声明,第二部分是处理指令(可省略),第三部分是元素和属性定义。
- 使用StringIO生成了一个文件对象。其字符串为一个DTD定义,这里的含义指明了empty元素的类型,这里值必须为空。元素的类型包括4类,EMPTY(空元素)、ANY(任意)、Mixed(混合元素)和Children(子元素)。
- 代码如下。
<!--one.dtd-->
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT employees (employee+)>
<!ELEMENT employee (name,age,sex,address)>
<!ELEMENT name ANY>
<!ELEMENT age ANY>
<!ELEMENT sex ANY>
<!ELEMENT address ANY>
# -*- coding: UTF-8 -*-
import xml.dom.minidom
import xml.etree.ElementTree as ET
from lxml import etree, objectify
from io import StringIO
from xml.dom.minidom import parse
# 使用minidom解析器打开 XML 文档
DOMTree = xml.dom.minidom.parse(r"C:/Users/86155/one.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
print("Root element : %s" % collection.getAttribute("shelf"))
# 在集合中获取所有人员信息
employees = collection.getElementsByTagName("employee")
# 打印每个人的详细信息
for employee in employees:
print("*****Employee*****")
if employee.hasAttribute("id"):
print("Id: %s" % employee.getAttribute("id"))
name = employee.getElementsByTagName('name')[0]
print("Name: %s" % name.childNodes[0].data)
age = employee.getElementsByTagName('age')[0]
print("Age: %s" % age.childNodes[0].data)
sex = employee.getElementsByTagName('sex')[0]
print("Sex: %s" % sex.childNodes[0].data)
address = employee.getElementsByTagName('address')[0]
print("Address: %s" % address.childNodes[0].data)
# 文档结构良好性验证
try:
ET.parse(r"C:/Users/86155/one.xml")
print("这是一个良构的XML文档")
except Exceptionas as e:
print("这可能是一个非良构文档")
print("出错信息:", e)
# 文档的有效性验证
dtd = etree.DTD(open(r"C:/Users/86155/one.dtd"))
xml = objectify.parse(open(r"C:/Users/86155/one.xml", 'rb'))
print(dtd.validate(xml))
运行结果: