使用Python解析和处理iTunes音乐库的XML文件
1. 读取iTunes数据库
计算机使用XML(可扩展标记语言)来结构化和交换数据。如果你使用iTunes管理音乐,那么你会发现iTunes的音乐库是以XML格式存储的。这个文件通常位于iTunes目录下,名为
iTunes Music Library.xml
。这是一个文本文件,可以用简单的文本编辑器查看。文件的开头部分如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
这个文件的结构是典型的XML文档结构。第一行标识了用于编码信息的XML版本。第二行标识了文档类型,或者说是文档类型定义(DOCTYPE)。DOCTYPE提供的信息中包括对一个文件的引用,在这个文件中描述了各种标签的含义。
文件结构
文件的主要部分被描述为一个
plist
,这实际上是一个类似于Python中的列表数据类型。这个列表的第一个元素是一个字典,它是一系列键和值对的集合,类似于Python中的字典数据类型。接下来是一系列的键及其关联的值。每个键是一个字符串;然而,值有不同的类型:一些是整数,一些是字符串,还有一个,
tracks
字段,是另一个字典。
字典用于记录存储在数据库中每首歌曲(轨道)的信息。存储的信息包括歌曲的名字,艺术家的名字,作曲家,专辑和其他信息。
2. 解析XML
XML文件只是文本文件,所以你可以简单地使用标准文件命令逐行读取文件描述。然而,读取标签字段,将标签名称与其中包含的数据分开,并匹配每个打开标签与相应的关闭标签是复杂的操作,你可能希望避免,如果可能的话。幸运的是,已经设计了许多XML解析器来简化这个过程。XML文件的任务可以采用两种通用方法,且两种通用库也常被使用。一种方法是将整个XML文档读入一个巨大的结构中,然后将结构拆开来找到感兴趣的项。这里,解析器完成其工作,将值返回给程序员。然后程序员操作返回的值。这被称为文档对象模型(DOM)方法。如果文档很小或者必须与程序的许多部分共享,这种方法最为简单。
使用DOM模型解析XML文件
我们的第一个程序展示了如何使用Python的
xml.dom.minidom
库解析XML文件。在函数定义之外,程序自身是少于10行的代码。函数名为
parse
的函数正在做大部分工作。文件的实际工作如下:
import xml.dom.minidom
def parse(file_name):
itunesdb = xml.dom.minidom.parse(file_name)
print(itunesdb.documentElement)
示例输出
你可以通过在交互模式下尝试这个函数来开始实验。在你找到iTunes XML文件后,尝试输入以下三行:
import xml.dom.minidom
itunesdb = xml.dom.minidom.parse("iTunes Music Library.xml")
print(itunesdb.documentElement)
这个简短的实验说明了XML解析器的一个缺点。解析器不知道输入的哪部分是重要的,所以它保存了一切,包括换行和空格字符。在这种情况下,出现在前面的文本与字典标签之后的内容不重要。函数移除文本是一个简单的例程,移除这些多余的文本节点,留下元素的兴趣。
XML数据结构
如果你检查iTunes数据库的初始几行,你可以看到数据库的结构是一个包含有关数据库自身信息的字典。这个字典中的一个字段名为
Tracks
,它包括数据库中每一首歌曲的一个轨道。该字段本身持有一个字典,其中包含有关歌曲名字、艺术家、作曲家等信息的条目。
函数
readInfo
用于执行XML节点与等价Python表示之间的转换。整数使用函数
int
进行转换,字典通过递归调用
readKeys
处理,所有其他值(如字符串和日期)则保持原样。
将XML形式转换为Python结构后,访问名为
Tracks
的输入框以加载歌曲字典。使用循环访问每一首歌曲,并使用打印语句生成关于每首歌曲的一些信息。示例输出可能如下所示:
感觉相同的方式:诺拉·琼斯:2002年
随我一起离开:诺拉·琼斯:2002年
射月:诺拉·琼斯:2002年
你认为什么:塞琳娜:1992年
mermaid流程图
以下是DOM解析器的工作流程图:
graph TD;
A[开始解析] --> B[读取XML文件];
B --> C[创建DOM树];
C --> D[遍历DOM树];
D --> E[提取所需数据];
E --> F[返回解析结果];
3. 示例程序
接下来,我们提供一个完整的示例程序,该程序读取XML文件并将其中的歌曲信息打印出来。这个程序展示了如何使用Python的
xml.dom.minidom
库解析XML文件,并将其中的歌曲信息提取出来。
import xml.dom.minidom
def parse(file_name):
itunesdb = xml.dom.minidom.parse(file_name)
def remove_text(node_list):
return [node for node in node_list if not node.nodeType == node.TEXT_NODE]
tracks = itunesdb.getElementsByTagName("dict")[0]
tracks = remove_text(tracks.childNodes)
def read_keys(node_list):
result = {}
key = None
for node in node_list:
if node.nodeName == "key":
key = node.firstChild.nodeValue
else:
if key:
result[key] = node.firstChild.nodeValue if node.firstChild else None
key = None
return result
tracks_info = read_keys(tracks)
for track_id, track_info in tracks_info.items():
print(f"{track_info['Name']}: {track_info['Artist']} ({track_info['Year']})")
示例输出
感觉相同的方式:诺拉·琼斯:2002年
随我一起离开:诺拉·琼斯:2002年
射月:诺拉·琼斯:2002年
你认为什么:塞琳娜:1992年
4. SAX vs DOM模型
DOM模型的替代品是SAX,即XML的简单API。SAX模型围绕事件的概念构建,这些事件是程序员感兴趣的行动。对于每个事件,程序员可以定义将处理事件的代码。对于XML解析器,使用了三种主要类别的事件。第一个发生在已识别标签的开始时,第二个发生在已识别标签之间的文本时,第三个也是最后一个事件是处理结束标签。每一个都由类中的一个方法处理。
SAX解析器
为了制作一种专门类型的解析器,程序员只需构建一个继承自这个类的新类,并重写适当的方法。SAX解析器会忽略大多数数据字段,只处理那些感兴趣的字段——即与数据库中各个歌曲相关联的键。
from xml.sax import make_parser, handler
class iTunesHandler(handler.ContentHandler):
def __init__(self):
self.current_key = ""
self.current_track = {}
self.tracks = []
def startElement(self, name, attrs):
self.current_key = name
def characters(self, content):
if self.current_key and self.current_key != "dict":
self.current_track[self.current_key] = content.strip()
def endElement(self, name):
if name == "dict":
if self.current_track:
self.tracks.append(self.current_track)
self.current_track = {}
self.current_key = ""
def parse_sax(file_name):
parser = make_parser()
sax_handler = iTunesHandler()
parser.setContentHandler(sax_handler)
parser.parse(open(file_name))
return sax_handler.tracks
tracks = parse_sax("iTunes Music Library.xml")
for track in tracks:
print(f"{track['Name']}: {track['Artist']} ({track['Year']})")
mermaid流程图
以下是SAX解析器的工作流程图:
graph TD;
A[开始解析] --> B[初始化SAX解析器];
B --> C[设置内容处理器];
C --> D[解析XML文件];
D --> E[处理事件];
E --> F[提取所需数据];
F --> G[返回解析结果];
对比DOM和SAX模型
| 特性 | DOM模型 | SAX模型 |
|---|---|---|
| 内存占用 | 较高,因为需要构建整个文档树 | 较低,因为只处理当前节点 |
| 处理速度 | 较慢,因为需要构建整个文档树 | 较快,因为只处理当前节点 |
| 适用场景 | 文档较小或需要频繁访问多个节点时 | 文档较大或只需要处理部分内容时 |
通过这些内容,读者能够学习到如何有效地从XML文件中提取所需信息,并了解不同解析技术的选择依据。
5. 扩展练习
为了加深对XML解析的理解,并提高编程技能,以下是几个练习题,鼓励读者尝试使用这两种解析方法对XML文件进行不同方式的处理:
5.1 检查文档类型定义
检查iTunes数据库中DOCTYPE条目所描述的文档类型定义(DTD)文件。它描述了哪些XML标签?通过访问DTD文件(如
http://www.apple.com/DTDs/PropertyList-1.0.dtd
),你可以了解到每个标签的作用和结构。
5.2 使用文本编辑器发现信息
假设你有自己iTunes XML数据库文件的访问权限,你可以使用文本编辑器来发现数据库中每个轨道(歌曲)存储了哪些信息。具体步骤如下:
-
打开
iTunes Music Library.xml文件。 -
搜索
<key>标签,找到包含歌曲信息的部分。 -
观察每个
<key>标签后的值,如歌曲名、艺术家、专辑等。
5.3 编写DOM解析器程序
编写一个使用DOM解析器的Python程序来揭示这些信息。程序可以按照以下步骤进行:
-
使用
xml.dom.minidom库解析XML文件。 - 遍历DOM树,提取所有歌曲信息。
- 打印每首歌曲的详细信息,如歌曲名、艺术家、专辑、年份等。
示例代码
import xml.dom.minidom
def parse_dom(file_name):
itunesdb = xml.dom.minidom.parse(file_name)
def remove_text(node_list):
return [node for node in node_list if not node.nodeType == node.TEXT_NODE]
tracks = itunesdb.getElementsByTagName("dict")[0]
tracks = remove_text(tracks.childNodes)
def read_keys(node_list):
result = {}
key = None
for node in node_list:
if node.nodeName == "key":
key = node.firstChild.nodeValue
else:
if key:
result[key] = node.firstChild.nodeValue if node.firstChild else None
key = None
return result
tracks_info = read_keys(tracks)
for track_id, track_info in tracks_info.items():
print(f"{track_info['Name']}: {track_info['Artist']} - {track_info['Album']} ({track_info['Year']})")
parse_dom("iTunes Music Library.xml")
5.4 扩展DOM解析程序
我们的应用程序在移动到下一首歌曲之前,只输出每首歌曲的一小部分信息。你可以扩展程序,打印更多详细信息,如流派、持续时间、播放次数等。打印值的顺序将与数据库中的顺序相匹配。
5.5 生成摘要信息
大多数XML应用程序会收集大量信息,然后以不同的顺序生成摘要或摘要。你可以从DOM解析应用程序开始,重写程序以生成以下各项:
- 按字母顺序列出数据库中所有歌曲 ,并为每首歌曲列出作曲家和艺术家。
- 按字母顺序列出数据库中每个专辑 ,并为每个专辑生成按字母顺序排列的歌曲列表。
- 按字母顺序列出作曲家 ,并为每位作曲家列出包含其作品的所有歌曲、艺术家和专辑。
示例代码
import xml.dom.minidom
def generate_summary(file_name):
itunesdb = xml.dom.minidom.parse(file_name)
def remove_text(node_list):
return [node for node in node_list if not node.nodeType == node.TEXT_NODE]
tracks = itunesdb.getElementsByTagName("dict")[0]
tracks = remove_text(tracks.childNodes)
def read_keys(node_list):
result = {}
key = None
for node in node_list:
if node.nodeName == "key":
key = node.firstChild.nodeValue
else:
if key:
result[key] = node.firstChild.nodeValue if node.firstChild else None
key = None
return result
tracks_info = read_keys(tracks)
songs = []
albums = {}
composers = {}
for track_id, track_info in tracks_info.items():
song = {
'name': track_info.get('Name'),
'artist': track_info.get('Artist'),
'album': track_info.get('Album'),
'composer': track_info.get('Composer')
}
songs.append(song)
album = track_info.get('Album')
if album not in albums:
albums[album] = []
albums[album].append(song)
composer = track_info.get('Composer')
if composer not in composers:
composers[composer] = []
composers[composer].append(song)
# 按字母顺序列出所有歌曲
songs.sort(key=lambda x: x['name'])
print("按字母顺序列出所有歌曲:")
for song in songs:
print(f"{song['name']}: {song['composer']} - {song['artist']}")
# 按字母顺序列出每个专辑
albums = dict(sorted(albums.items()))
print("\n按字母顺序列出每个专辑:")
for album, songs in albums.items():
print(f"专辑: {album}")
songs.sort(key=lambda x: x['name'])
for song in songs:
print(f" - {song['name']}")
# 按字母顺序列出作曲家
composers = dict(sorted(composers.items()))
print("\n按字母顺序列出作曲家:")
for composer, songs in composers.items():
print(f"作曲家: {composer}")
for song in songs:
print(f" - {song['name']} - {song['artist']} - {song['album']}")
generate_summary("iTunes Music Library.xml")
6. 比较和对比DOM和SAX解析模型
相似之处
- 事件驱动 :SAX和DOM解析器都可以通过事件驱动的方式来处理XML文件。DOM解析器通过遍历DOM树来触发事件,而SAX解析器通过回调函数来处理事件。
-
支持标准库
:Python的标准库中都提供了这两种解析器的支持,分别是
xml.dom.minidom和xml.sax。
不同之处
| 特性 | DOM模型 | SAX模型 |
|---|---|---|
| 内存占用 | 较高,因为需要构建整个文档树 | 较低,因为只处理当前节点 |
| 处理速度 | 较慢,因为需要构建整个文档树 | 较快,因为只处理当前节点 |
| 适用场景 | 文档较小或需要频繁访问多个节点时 | 文档较大或只需要处理部分内容时 |
| 处理方式 | 构建整个文档树后进行处理 | 流式处理,逐节点解析 |
| 修改能力 | 可以方便地修改和查询整个文档树 | 不适合修改文档结构,主要用于读取 |
适用场景
- DOM模型 :适用于需要频繁访问多个节点的情况,如生成报告或进行复杂查询。
- SAX模型 :适用于处理大型XML文件或只需要处理部分内容的情况,如实时数据流处理。
XML文档描述信息的方式
XML文档描述信息的方式更倾向于DOM模型,因为DOM模型更适合处理结构化数据,尤其是在需要频繁访问和修改数据的情况下。然而,对于大型XML文件或实时数据流,SAX模型更为高效。
通过这些内容,读者能够更深入地理解XML解析的技术细节,并掌握如何根据具体需求选择合适的解析方法。
超级会员免费看
11

被折叠的 条评论
为什么被折叠?



