Использование Python 3.6 для анализа XML, как я могу определить, не содержит ли тег XML данных

Я пытаюсь изучить Python, написав скрипт, который будет извлекать данные из нескольких записей в файле XML. Мне удалось найти ответы на большинство моих вопросов с помощью поиска в Интернете, но я не нашел способа определить, содержит ли тег XML данные перед вызовом getElementsByTagName("tagname"). Используется метод [0].firstChild.data, и при отсутствии данных выдается ошибка AttributeError. Я понимаю, что мог бы написать свой код с попыткой обработать AttributeError, но я бы предпочел знать, что тег пуст, прежде чем пытаться извлечь данные, а не обрабатывать исключение. Вот пример файла XML, который содержит две записи: одну с данными в тегах и одну с пустым тегом.

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<records>
  <rec>
    <name>ZYSRQPO</name>
    <state>Washington</state>
    <country>United States</country>
  </rec>
  <rec>
    <name>ZYXWVUT</name>
    <state></state>
    <country>Mexico</country>
  </rec>
</records>

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

from xml.dom import minidom
import sys

mydoc  = minidom.parse('mydataFile.xml')
records = mydoc.getElementsByTagName("rec")

for rec in records:
    try:
        name = rec.getElementsByTagName("name")[0].firstChild.data
        state = rec.getElementsByTagName("state")[0].firstChild.data
        country = rec.getElementsByTagName("country")[0].firstChild.data
        print('{}\t{}\t{}'.format(name, state, country))

    except (AttributeError):
        print('AttributeError encountered in record {}'.format(name), file=sys.stderr)
        continue

При обработке этого файла никакая информация для записи с именем ZYXWVUT не будет напечатана, за исключением того, что возникло исключение. Я хотел бы иметь нулевое значение для используемого имени состояния и остальной информации, напечатанной об этой записи. Есть ли метод, который можно использовать для выполнения того, что я хочу, чтобы я мог использовать оператор if, чтобы определить, не содержит ли тег данных, прежде чем использовать getElementsByTagName и столкнуться с ошибкой, когда данные не найдены?


person JCB    schedule 09.02.2017    source источник


Ответы (2)


from xml.dom import minidom
import sys

mydoc  = minidom.parse('mydataFile.xml')
records = mydoc.getElementsByTagName("rec")

for rec in records:
    name = rec.getElementsByTagName("name")[0].firstChild.data
    state = None if len(rec.getElementsByTagName("state")[0].childNodes) == 0 else rec.getElementsByTagName("state")[0].firstChild.data
    country = rec.getElementsByTagName("country")[0].firstChild.data
    print('{}\t{}\t{}'.format(name, state, country))

Или, если есть шанс, это имя и страна тоже пусты:

from xml.dom import minidom
import sys


def get_node_data(node):
    if len(node.childNodes) == 0:
        result = None
    else:
        result = node.firstChild.data
    return result


mydoc  = minidom.parse('mydataFile.xml')
records = mydoc.getElementsByTagName("rec")

for rec in records:
    name = get_node_data(rec.getElementsByTagName("name")[0])
    state = get_node_data(rec.getElementsByTagName("state")[0])
    country = get_node_data(rec.getElementsByTagName("country")[0])
    print('{}\t{}\t{}'.format(name, state, country))
person reedcourty    schedule 09.02.2017
comment
Спасибо, я ценю ваш ответ. Мне особенно нравится второе предложение, хотя маловероятно, что имя или страна когда-либо будут пустыми, это делает структуру более элегантной. У меня есть другое место, где мне нужно быть прямо сейчас, поэтому я не пробовал это, но попробую, как только смогу. - person JCB; 09.02.2017

Я попробовал второе предложение Ридкорти и обнаружил, что оно отлично работает. Но я решил, что очень не хочу, чтобы none возвращался, если элемент был пустым. Вот что я придумал:

from xml.dom import minidom
import sys

def get_node_data(node):
    if len(node.childNodes) == 0:
        result = '*->No ' + node.nodeName + '<-*'
    else:
        result = node.firstChild.data
    return result

mydoc  = minidom.parse(dataFileSpec)
records = mydoc.getElementsByTagName("rec")

for rec in records:
    name = get_node_data(rec.getElementsByTagName("name")[0])
    state = get_node_data(rec.getElementsByTagName("state")[0])
    country = get_node_data(rec.getElementsByTagName("country")[0])
    print('{}\t{}\t{}'.format(name, state, country))

Когда это выполняется для этого XML:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<records>
  <rec>
    <name>ZYSRQPO</name>
    <country>United States</country>
    <state>Washington</state>
  </rec>
  <rec>
    <name></name>
    <country>United States</country>
    <state>Washington</state>
  </rec>
  <rec>
    <name>ZYXWVUT</name>
    <country>Mexico</country>
    <state></state>
  </rec>
  <rec>
    <name>ZYNMLKJ</name>
    <country></country>
    <state>Washington</state>
  </rec>
</records>

Он производит этот вывод:

ZYSRQPO Washington      United States
*->No name<-*   Washington      United States
ZYXWVUT *->No state<-*  Mexico
ZYNMLKJ Washington      *->No country<-*
person JCB    schedule 11.02.2017