2016-07-13 7 views
0

Я пытаюсь написать программу Python, которая сканирует конкретный XML Document для данных и записывает эти данные в таблицы в базе данных SQLite. Мой код:Python + SQL + XML: NoneType объект не имеет атрибута '__getitem__'

import xml.etree.ElementTree as ET 
import sqlite3 

conn = sqlite3.connect('Wk03_Assign01.sqlite') 
cur = conn.cursor() 

cur.executescript(''' 
DROP TABLE IF EXISTS Artist; 
DROP TABLE IF EXISTS Album; 
DROP TABLE IF EXISTS Track; 
DROP TABLE IF EXISTS Genre; 

CREATE TABLE Artist (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 
    name TEXT UNIQUE 
); 

CREATE TABLE Genre (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 
    name TEXT UNIQUE 
); 

CREATE TABLE Album (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 
    artist_id INTEGER, 
    title TEXT UNIQUE 
); 

CREATE TABLE Track (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 
    title TEXT UNIQUE, 
    album_id INTEGER, 
    genre_id INTEGER, 
    len INTEGER, 
    rating INTEGER, 
    count INTEGER 
); 

''') 


fname = raw_input('Enter file name: ') 
if (len(fname) < 1) : 
    fname = 'Library.xml' 

def lookup(d, key): 
    found = False 
    for child in d: 
     if found : return child.text 
     if child.tag == 'key' and child.text == key : 
      found = True 
    return None 

stuff = ET.parse(fname) 
all = stuff.findall('dict/dict/dict') 
for entry in all: 
    if (lookup(entry, 'Track ID') is None) : 
     continue 
    name = lookup(entry, 'Name') 
    artist = lookup(entry, 'Artist') 
    album = lookup(entry, 'Album') 
    genre = lookup(entry, 'Genre') 
    count = lookup(entry, 'Play Count') 
    rating = lookup(entry, 'Rating') 
    length = lookup(entry, 'Total Time') 

    if name is None or artist is None or album is None : 
     continue 

cur.execute('''INSERT OR IGNORE INTO Artist (name) 
    VALUES (?)''', (artist,)) 
cur.execute('SELECT id FROM Artist WHERE name = ? ', (artist,)) 
artist_id = cur.fetchone()[0] 

cur.execute('''INSERT OR IGNORE INTO Album (artist_id, title) 
    VALUES (?, ?)''', (artist_id, album )) 
cur.execute('SELECT id FROM Album WHERE title = ? ', (album,)) 
album_id = cur.fetchone()[0] 

cur.execute('''INSERT OR IGNORE INTO Genre (name) 
    VALUES (?)''', (genre,)) 
cur.execute('SELECT id FROM Genre WHERE name = ? ', (genre,)) 
genre_id = cur.fetchone()[0] 

cur.execute('''INSERT OR REPLACE INTO Track 
    (title, album_id, genre_id, len, rating, count) 
    VALUES (?, ?, ?, ?, ?, ?)''', 
    (name, album_id, genre_id, length, rating, count)) 

conn.commit() 
conn.close() 

В то время как остальная часть моего кода работает прекрасно, сегмент:

cur.execute('''INSERT OR IGNORE INTO Genre (name) 
    VALUES (?)''', (genre,)) 
cur.execute('SELECT id FROM Genre WHERE name = ? ', (genre,)) 
genre_id = cur.fetchone()[0] 

вызывает следующий отслеживающий:

Traceback (most recent call last): 
    File "C:\Python27\Scripts\Course 04\Wk03_Ass01.py", line 83, in <module> 
    genre_id = cur.fetchone()[0] 
TypeError: 'NoneType' object has no attribute '__getitem__' 

Я совершенно сбит с толку о том, почему это происходит. Сегмент кода, вызывающий трассировку, идентичен (за исключением имен переменных) над разделами над ним, которые работают отлично. Я думал, что ошибка могла произойти, потому что некоторые записи в базе данных «Жанр» имеют NULL, но я положил оператор cur.fetchone() в оператор if, который также не работал.

cur.execute('''INSERT OR IGNORE INTO Genre (name) 
    VALUES (?)''', (genre,)) 
sqlstr = 'SELECT id FROM Genre WHERE name = ? ', (genre,) 
if cur.execute(sqlstr) is None: 
    continue 
else: 
    genre_id = cur.fetchone()[0] 

Я бы очень признателен за понимание того, что здесь не так. Благодаря!

ответ

0

Сначала проверьте, есть ли что-то, чтобы извлечь, а затем получить его ... if cur.rowcount == 1: - это то, что вы можете использовать для проверки наличия единственного результата строки. Вы также можете использовать fetchall() и проверить возвращенный список. Разница в том, что если результат большой - вы получите его все, так что rowcount - лучший вариант.

EDIT

Попробуйте передать точную строку. Если это сработает, проблема связана с тем, как вы передаете запрос на execute. Согласно docs, который вы наверняка знает:

# Do this instead 
t = ('RHAT',) 
c.execute('SELECT * FROM stocks WHERE symbol=?', t) 
print c.fetchone() 
+0

cur.fetchall() возвращает длинный список результатов, поэтому операторы SQL INSERT и SELECT определенно работают по назначению. – thevioletsaber

+0

Выполнение 'genre_id = cur.fetchone()' вместо 'genre_id = cur.fetchone() [0]' возвращает результаты, но вместо этого я получаю другую трассировку. Я попытался передать запрос, чтобы выполнить так, как вы предложили, но это не повлияло на результаты. – thevioletsaber

+0

Хорошо, я исправил ошибку! Спасибо за вашу помощь. :) – thevioletsaber

1

Ладно, я нашел исправить. По-видимому, данные «Жанр» в некоторых случаях были NULL, и это зависело от данных. Я исправил его с помощью условного оператора IF следующим образом:

cur.execute('''INSERT OR IGNORE INTO Genre (name) 
    VALUES (?)''', (genre,)) 
cur.execute('SELECT id FROM Genre WHERE name = ? ', t) 
genre_id_val = cur.fetchone() 
if genre_id_val is None: 
    continue 
else: 
    genre_id = genre_id_val[0] 

Операция if/else работала!

Смежные вопросы