2017-02-02 39 views
0

Следующий xml-файл (lieferungen.xml) содержит несколько несоответствий. Некоторые из элементов более чем один идентификатор (например, пункт «Apfel» имеет 3 различных идентификаторы):Python SAX Parser программа, вычисляющая неверные результаты

<?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> 

Для того, чтобы найти все несоответствия в файле, я написал следующий саксофон-парсер в питоне:

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), этот вывод является неправильным двумя способами:

  1. Имеются только два разных идентификатора товара «Киршен», а не три.
  2. Несколько пунктов с более чем одним ID не упоминаются вообще (например, пункт «Коле» имеет два различных идентификаторов)

Однако, я не понимаю, что происходит не так в моем коде.

ответ

1

Если я никогда не понял, ошибка в том, что эта линия

   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". 

Сказав это, я не уверен, что ваш код будет обязательно делать то, что вы хотите все время. Попробуйте переместить элемент <artikel> с ID 7116 над всеми остальными <artikel> элементами, а затем запустите свой код. Затем ваш код скажет вам, что существует четыре разных идентификатора для Kirschen, когда, возможно, их всего два.

Причина этого в том, что количество идентификаторов, выводимых вашей программой для элемента, является одним для первого идентификатора, найденного для этого элемента, и для каждого последующего элемента <artikel> с таким именем, но идентификатор которого отличается от первого.

Если вы действительно хотите подсчитать количество идентификаторов, используемых для каждого продукта, лучшим способом было бы использовать наборы для хранения идентификаторов, используемых для каждого продукта во время прохождения, а затем печатать длины любых наборов, которые содержат больше чем один элемент. Вот что ваш метод 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. Хорошая вещь о наборе заключается в том, что если вы добавите идентификатор, который уже находится в наборе, ничего не происходит.Набор не содержит дубликатов идентификаторов. Обратите также внимание, что я больше не использую self.items2, так как self.items имеет всю необходимую мне информацию.

Вы даже можете пойти на один шаг дальше этого. Мы должны проверить, item находится в self.items и создать набор для этого элемента, если это не так. Если мы используем defaultdict, тогда это позаботится о создании набора для нас, если он еще не существует. Добавьте линию from collections import defaultdict выше вашего класса C_Handler и замените линию self.items = {} на self.items = defaultdict(set). После этого ваш метод characters должен быть следующим:

def characters(self, content): 
     if self.read == 1: 
      item = content 
      self.items[item].add(self.id) 
+0

спасибо! – Tommy