Python SAX 解析器程序计算出错误的结果
Python SAX Parser program calculating wrong results
以下 xml 文件 (lieferungen.xml) 包含多个不一致之处。一些项目有多个 ID(例如项目 "apfel" 有 3 个不同的 ID):
<?xml version="1.0" encoding="UTF-8"?>
<lieferungen xmlns="urn:myspace:lieferungen" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:myspace:lieferungen C:\xml\lieferungen.xsd">
<artikel id="3526">
<name>apfel</name>
<preis stueckpreis="true">8.97</preis>
<lieferant>Fa. Krause</lieferant>
</artikel>
<artikel id="7866">
<name>Kirschen</name>
<preis stueckpreis="false">10.45</preis>
<lieferant>Fa. Helbig</lieferant>
</artikel>
<artikel id="4444"> <!--DIFFERENT ID FOR apfel!! -->
<name>apfel</name>
<preis stueckpreis="true">12.67</preis>
<lieferant>Fa. Liebig</lieferant>
</artikel>
<artikel id="7866">
<name>Kirschen</name>
<preis stueckpreis="false">17.67</preis>
<lieferant>Fa. Krause</lieferant>
</artikel>
<artikel id="2345"> <!--DIFFERENT ID FOR apfel!! -->
<name>apfel</name>
<preis stueckpreis="true">9.54</preis>
<lieferant>Fa. Mertes</lieferant>
</artikel>
<artikel id="7116"> <!--DIFFERENT ID FOR Kirschen!! -->
<name>Kirschen</name>
<preis stueckpreis="false">16.45</preis>
<lieferant>Fa. Hoeller</lieferant>
</artikel>
<artikel id="7868">
<name>Kohl</name>
<preis stueckpreis="false">3.20</preis>
<lieferant>Fa. Hoeller</lieferant>
</artikel>
<artikel id="7866">
<name>Kirschen</name>
<preis stueckpreis="false">12.45</preis>
<lieferant>Fa. Richard</lieferant>
</artikel>
<artikel id="3245">
<name>Bananen</name>
<preis stueckpreis="false">15.67</preis>
<lieferant>Fa. Hoeller</lieferant>
</artikel>
<artikel id="6745"> <!--DIFFERENT ID FOR Kohl!! -->
<name>Kohl</name>
<preis stueckpreis="false">3.10</preis>
<lieferant>Fa. Reinhardt</lieferant>
</artikel>
<artikel id="7789">
<name>Ananas</name>
<preis stueckpreis="true">8.60</preis>
<lieferant>Fa. Richard</lieferant>
</artikel>
</lieferungen>
为了找出文件中所有不一致的地方,我在python中写了下面的sax-parser:
import xml.sax
import sys
class C_Handler(xml.sax.ContentHandler):
def __init__(self):
self.items = {}
self.items2 = {}
self.read = 0
self.id = 0
def startDocument(self):
print("Inconsistencies:\n")
def startElement(self, tag, attributes):
if tag=="name":
self.read = 1
if tag=="artikel":
self.id = attributes["id"]
def endElement(self, tag):
if tag=="name":
self.read = 0
def characters(self, content):
if self.read == 1:
item = content
#check whether the item is not yet part of the dictionaries
if item not in self.items:
#add item (e.g. "apfel") to both dictionary "items" and
#dictionary "items2". The value for the item is the id in the
#case of dictionary "items" and "0" in the case of dictionary
#"items2". The second dictionary contains the number of
#inconsistencies for each product. At the beginning, the
#number of inconsistencies for the product is zero.
self.items[item] = self.id
self.items2[item] = 0
else:
if self.items[item] == self.id:
#increase number of inconsistencies by 1:
self.items2[item] = self.items2[item] + 1
def endDocument(self):
for prod in self.items2:
if self.items2[prod]>0:
print("There are {} different IDs for item \"
{}\".".format(self.items2[prod] + 1, prod))
if ( __name__ == "__main__"):
c = C_Handler()
xml.sax.parse("lieferungen.xml", c)
这个程序的输出如下:
Inconsistencies:
There are 3 different IDs for item "Kirschen".
如您所见,从文件中(注意标记出现多个 ID 的注释),此输出在两个方面是错误的:
- 项目 "Kirschen" 只有两个不同的 ID,而不是三个。
- 一些具有多个 ID 的项目根本没有被提及(例如项目 "Kohl" 有两个不同的 ID)
但是,我不明白,我的代码出了什么问题。
除非我误解了,否则错误是这一行
if self.items[item] == self.id:
应该是
if self.items[item] != self.id:
就目前而言,您的程序似乎在计算一致性而不是不一致性:Kirschen
使用 ID 7866
三次,没有其他程序多次使用相同的 ID,因此您的输出。
进行上述更改后,我得到以下输出:
Inconsistencies:
There are 3 different IDs for item "apfel".
There are 2 different IDs for item "Kirschen".
There are 2 different IDs for item "Kohl".
话虽如此,我不确定您的代码是否一定会一直执行您想要的操作。尝试将 ID 为 7116 的 <artikel>
元素移动到所有其他 <artikel>
元素之上,然后是 运行 您的代码。然后您的代码会告诉您 Kirschen
有四个不同的 ID,而实际上只有两个。
这是因为您的程序为某个项目输出的 ID 数量是一个用于为该项目找到的第一个 ID,另一个用于每个具有该名称但 ID 不同的 <artikel>
元素从第一个开始。
如果您真的想计算每个产品使用的 ID 数量,更好的方法是使用集合来存储您遍历每个产品使用的 ID,然后打印包含的任何集合的长度不止一个元素。这是进行此更改后您的 characters
方法的样子 - 我将留给您对 endDocument
方法进行必要的修改:
def characters(self, content):
if self.read == 1:
item = content
#check whether the item is not yet part of the dictionary
if item not in self.items:
self.items[item] = set([self.id])
else:
self.items[item].add(self.id)
请注意,在最后一行中,我不需要检查 self.items[item]
中的集合是否已包含 self.id
。集合的好处在于,如果您添加集合中已有的 ID,则不会发生任何事情。该集合不会以重复的 ID 结尾。另请注意,我不再使用 self.items2
,因为 self.items
拥有我需要的所有信息。
你甚至可以比这更进一步。我们必须检查 item
是否在 self.items
中,如果不在,则为该项目创建一个集合。如果我们使用 defaultdict
,那么它将负责为我们创建集合(如果它尚不存在)。在 C_Handler
class 上方添加 from collections import defaultdict
行,并将 self.items = {}
行替换为 self.items = defaultdict(set)
。完成此操作后,您的 characters
方法只需如下所示:
def characters(self, content):
if self.read == 1:
item = content
self.items[item].add(self.id)
以下 xml 文件 (lieferungen.xml) 包含多个不一致之处。一些项目有多个 ID(例如项目 "apfel" 有 3 个不同的 ID):
<?xml version="1.0" encoding="UTF-8"?>
<lieferungen xmlns="urn:myspace:lieferungen" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:myspace:lieferungen C:\xml\lieferungen.xsd">
<artikel id="3526">
<name>apfel</name>
<preis stueckpreis="true">8.97</preis>
<lieferant>Fa. Krause</lieferant>
</artikel>
<artikel id="7866">
<name>Kirschen</name>
<preis stueckpreis="false">10.45</preis>
<lieferant>Fa. Helbig</lieferant>
</artikel>
<artikel id="4444"> <!--DIFFERENT ID FOR apfel!! -->
<name>apfel</name>
<preis stueckpreis="true">12.67</preis>
<lieferant>Fa. Liebig</lieferant>
</artikel>
<artikel id="7866">
<name>Kirschen</name>
<preis stueckpreis="false">17.67</preis>
<lieferant>Fa. Krause</lieferant>
</artikel>
<artikel id="2345"> <!--DIFFERENT ID FOR apfel!! -->
<name>apfel</name>
<preis stueckpreis="true">9.54</preis>
<lieferant>Fa. Mertes</lieferant>
</artikel>
<artikel id="7116"> <!--DIFFERENT ID FOR Kirschen!! -->
<name>Kirschen</name>
<preis stueckpreis="false">16.45</preis>
<lieferant>Fa. Hoeller</lieferant>
</artikel>
<artikel id="7868">
<name>Kohl</name>
<preis stueckpreis="false">3.20</preis>
<lieferant>Fa. Hoeller</lieferant>
</artikel>
<artikel id="7866">
<name>Kirschen</name>
<preis stueckpreis="false">12.45</preis>
<lieferant>Fa. Richard</lieferant>
</artikel>
<artikel id="3245">
<name>Bananen</name>
<preis stueckpreis="false">15.67</preis>
<lieferant>Fa. Hoeller</lieferant>
</artikel>
<artikel id="6745"> <!--DIFFERENT ID FOR Kohl!! -->
<name>Kohl</name>
<preis stueckpreis="false">3.10</preis>
<lieferant>Fa. Reinhardt</lieferant>
</artikel>
<artikel id="7789">
<name>Ananas</name>
<preis stueckpreis="true">8.60</preis>
<lieferant>Fa. Richard</lieferant>
</artikel>
</lieferungen>
为了找出文件中所有不一致的地方,我在python中写了下面的sax-parser:
import xml.sax
import sys
class C_Handler(xml.sax.ContentHandler):
def __init__(self):
self.items = {}
self.items2 = {}
self.read = 0
self.id = 0
def startDocument(self):
print("Inconsistencies:\n")
def startElement(self, tag, attributes):
if tag=="name":
self.read = 1
if tag=="artikel":
self.id = attributes["id"]
def endElement(self, tag):
if tag=="name":
self.read = 0
def characters(self, content):
if self.read == 1:
item = content
#check whether the item is not yet part of the dictionaries
if item not in self.items:
#add item (e.g. "apfel") to both dictionary "items" and
#dictionary "items2". The value for the item is the id in the
#case of dictionary "items" and "0" in the case of dictionary
#"items2". The second dictionary contains the number of
#inconsistencies for each product. At the beginning, the
#number of inconsistencies for the product is zero.
self.items[item] = self.id
self.items2[item] = 0
else:
if self.items[item] == self.id:
#increase number of inconsistencies by 1:
self.items2[item] = self.items2[item] + 1
def endDocument(self):
for prod in self.items2:
if self.items2[prod]>0:
print("There are {} different IDs for item \"
{}\".".format(self.items2[prod] + 1, prod))
if ( __name__ == "__main__"):
c = C_Handler()
xml.sax.parse("lieferungen.xml", c)
这个程序的输出如下:
Inconsistencies:
There are 3 different IDs for item "Kirschen".
如您所见,从文件中(注意标记出现多个 ID 的注释),此输出在两个方面是错误的:
- 项目 "Kirschen" 只有两个不同的 ID,而不是三个。
- 一些具有多个 ID 的项目根本没有被提及(例如项目 "Kohl" 有两个不同的 ID)
但是,我不明白,我的代码出了什么问题。
除非我误解了,否则错误是这一行
if self.items[item] == self.id:
应该是
if self.items[item] != self.id:
就目前而言,您的程序似乎在计算一致性而不是不一致性:Kirschen
使用 ID 7866
三次,没有其他程序多次使用相同的 ID,因此您的输出。
进行上述更改后,我得到以下输出:
Inconsistencies:
There are 3 different IDs for item "apfel".
There are 2 different IDs for item "Kirschen".
There are 2 different IDs for item "Kohl".
话虽如此,我不确定您的代码是否一定会一直执行您想要的操作。尝试将 ID 为 7116 的 <artikel>
元素移动到所有其他 <artikel>
元素之上,然后是 运行 您的代码。然后您的代码会告诉您 Kirschen
有四个不同的 ID,而实际上只有两个。
这是因为您的程序为某个项目输出的 ID 数量是一个用于为该项目找到的第一个 ID,另一个用于每个具有该名称但 ID 不同的 <artikel>
元素从第一个开始。
如果您真的想计算每个产品使用的 ID 数量,更好的方法是使用集合来存储您遍历每个产品使用的 ID,然后打印包含的任何集合的长度不止一个元素。这是进行此更改后您的 characters
方法的样子 - 我将留给您对 endDocument
方法进行必要的修改:
def characters(self, content):
if self.read == 1:
item = content
#check whether the item is not yet part of the dictionary
if item not in self.items:
self.items[item] = set([self.id])
else:
self.items[item].add(self.id)
请注意,在最后一行中,我不需要检查 self.items[item]
中的集合是否已包含 self.id
。集合的好处在于,如果您添加集合中已有的 ID,则不会发生任何事情。该集合不会以重复的 ID 结尾。另请注意,我不再使用 self.items2
,因为 self.items
拥有我需要的所有信息。
你甚至可以比这更进一步。我们必须检查 item
是否在 self.items
中,如果不在,则为该项目创建一个集合。如果我们使用 defaultdict
,那么它将负责为我们创建集合(如果它尚不存在)。在 C_Handler
class 上方添加 from collections import defaultdict
行,并将 self.items = {}
行替换为 self.items = defaultdict(set)
。完成此操作后,您的 characters
方法只需如下所示:
def characters(self, content):
if self.read == 1:
item = content
self.items[item].add(self.id)