Как проанализировать XML-файл с различными элементами, используя xml.sax python? - PullRequest
0 голосов
/ 17 сентября 2018

Я ищу, чтобы разобрать большой XML-файл, используя Python Файл содержит несколько разных элементов. Вот пример файлов, над которыми я работаю:

<movie title="Searching">
   <type>War, Thriller</type>
   <format>DVD</format>
   <year>2018</year>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Missing girl</description>
</movie>
<song title="Need You Now">
   <type>Pop, Country</type>
   <format>MP4</format>
   <year>2010</year>
   <singer>Lady Antebellum</rating>
   <stars>8</stars>
</song>
   <movie title="Sidewalk of New York">
   <type>Romantic comedy</type>
   <format>DVD</format>
   <rating>PG</rating>
   <stars>7</stars>
   <description>Stories of people's perspective of love in NY</description>
</movie>

Из приведенных выше файлов я хочу проанализировать и сохранить в списке всю информацию, относящуюся к элементу фильма и песни. Я использую библиотеку xml.sax, и я столкнулся с проблемой, как дифференцировать элемент. Например, если я проанализирую теги типа, формата и года, он не сможет определить, принадлежит ли он фильму или песне. Это фрагмент кода, который я использую до сих пор:

import psycopg2
import xml.sax
from xml.sax.handler import ContentHandler

class MovieHandler( xml.sax.ContentHandler ):
   def __init__(self):
      self.CurrentData = ""
      self.type = ""
      self.format = ""
      self.year = ""
      self.data = {} #dict
      self.list = [] #list to store information
      self.list2 = []
      self.list3 = []
      self.list4 = []
      self.list5 = []

   # Call when an element starts
   def startElement(self, tag, attributes):
      self.CurrentData = tag
      if tag == "movie":
         title = attributes["title"]
         self.list.append(title)
         self.data['title'] = self.list
      elif tag == "song":
         title = attributes ["title"]
         self.list2.append(title)
         self.data['song_title'] = self.list2

   # Call when an elements ends
   def endElement(self, tag):
      if self.CurrentData == "type":
         type = self.type
         self.list3.append(type)
         self.data['type'] = self.list3
      elif self.CurrentData == "format":
         format = self.format
         self.list4.append(format)
         self.data['format'] = self.list4
      elif self.CurrentData == "year":
         year = int(self.year)
         self.list5.append(year)
         self.data['year'] = self.list5
      self.CurrentData = ""

   # Call when a character is read
   def characters(self, content):
      if self.CurrentData == "type":
         self.type = content
      elif self.CurrentData == "format":
         self.format = content
      elif self.CurrentData == "year":
         self.year = content

Результатом вышеприведенного кода является то, что тип, формат и год будут учитываться дважды. Вот пример вывода:

{'format': ['DVD', 'MP4', 'DVD'],
 'title': ['Searching', 'Need You Now', 'Sidewalk of New York'],
 'type': ['War, Thriller',
  'Pop, Country',
  'Romantic Comedy'],
 'year': [2018, 2010]}

Есть идеи как это исправить? Спасибо!

1 Ответ

0 голосов
/ 17 сентября 2018

Вы можете сохранить текущий тип в startElement, а затем вы можете сохранить данные соответственно в endElement()

def startElement(self, tag, attributes):
    if tag == "movie":
        self.currentEntryType = "movie"
    elif tag == "song":
        self.currentEntryType = "song"
    ...

def endElement(self, tag):
    if self.currentEntryType == "movie":
        ... # store as movie data

(я не совсем уверен, как должен выглядеть ваш список вывода, возможно, вымог бы опубликовать идеальный список вывода для примера xml)

Редактировать: было бы лучше иметь 2 дикта, один для фильмов и один для песен?Это зависит от того, как выглядит ваша база данных.

Я не уверен, зачем вам вообще нужны списки, не лучше ли использовать список диктов вместо диктата списков?

Использование 2 диктов, например, вот так:

{   
'format': ['DVD', 'DVD'],
'title': ['Searching', 'Sidewalk of New York'],
'type': ['War, Thriller', 'Romantic Comedy'],
'year': [2018]
}
{   
'format': ['MP4'],
'title': ['Need You Now'],
'type': ['Pop, Country'],
'year': [2010]
}

Дело в том, что вы не можете решить, принадлежит ли 2018 год Поискам или Тротуару Нью-Йорка .Будет ли это проблемой, когда вы фиксируете список в своей базе данных?

Вот решение с двумя диктовками: один для фильмов, другой для песен.В основном он использует 8 списков вместо 5, чтобы хранить все по отдельности.

class MovieHandler( xml.sax.ContentHandler ):
   def __init__(self):
      self.CurrentData = ""
      self.type = ""
      self.format = ""
      self.year = ""
      self.dataMovies = {} #dict
      self.dataSongs = {}
      self.list = [] # movie title
      self.list2 = [] # song title
      self.list3 = [] # movie type
      self.list4 = [] # movie format
      self.list5 = [] # movie year
      self.list6 = [] # song type
      self.list7 = [] # song format
      self.list8 = [] # song year

      self.currentEntryType = None

   # Call when an element starts
   def startElement(self, tag, attributes):
      self.CurrentData = tag
      if tag == "movie":
         title = attributes["title"]
         self.list.append(title)
         self.dataMovies['title'] = self.list
         self.currentEntryType = "movie"
      elif tag == "song":
         title = attributes ["title"]
         self.list2.append(title)
         self.dataSongs['song_title'] = self.list2
         self.currentEntryType = "song"

   # Call when an elements ends
   def endElement(self, tag):

      if tag == "movie":
         # Make movie lists the same length
         self.list3.extend([None]*(len(self.list)-len(self.list3)))
         self.list4.extend([None]*(len(self.list)-len(self.list4)))
         self.list5.extend([None]*(len(self.list)-len(self.list5)))   
      elif tag == "song":
         # Make movie lists the same length
         self.list6.extend([None]*(len(self.list2)-len(self.list6)))
         self.list7.extend([None]*(len(self.list2)-len(self.list7)))
         self.list8.extend([None]*(len(self.list2)-len(self.list8))) 

      if self.currentEntryType == "movie":
         if self.CurrentData == "type":
            type = self.type
            self.list3.append(type)
            self.dataMovies['type'] = self.list3
         elif self.CurrentData == "format":
            format = self.format
            self.list4.append(format)
            self.dataMovies['format'] = self.list4
         elif self.CurrentData == "year":
            year = int(self.year)
            self.list5.append(year)
            self.dataMovies['year'] = self.list5
         self.CurrentData = ""
      elif self.currentEntryType == "song":
         if self.CurrentData == "type":
            type = self.type
            self.list6.append(type)
            self.dataSongs['type'] = self.list6
         elif self.CurrentData == "format":
            format = self.format
            self.list7.append(format)
            self.dataSongs['format'] = self.list7
         elif self.CurrentData == "year":
            year = int(self.year)
            self.list8.append(year)
            self.dataSongs['year'] = self.list8
         self.CurrentData = ""

   # Call when a character is read
   def characters(self, content):
      if self.CurrentData == "type":
         self.type = content
      elif self.CurrentData == "format":
         self.format = content
      elif self.CurrentData == "year":
         self.year = content
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...