2013-05-14 4 views
0

в некотором коде, который я поддерживаю, разбор XML, используя библиотеку minidom.Python XML XPath частичное сообщение об ошибке

Для структуры XML, аналогично описанному ниже:

<a val="a1"> 
    <b val="b1"> 
    <c val="c1"> 
     Data 
    </c> 
    </b> 
</a> 

код выглядит следующим образом:

for a in doc.getElementsByTagName("a"): 
    aId = a.getAttribute("val").encode('ascii') 
    if aId == aExpected: 
     aFound = a 
     break 
else: # not found 
    raise Exception("No A '%s' found" % aExpected) 
for b in aFound.getElementsByTagName("b"): 
    bId = b.getAttribute("val").encode('ascii') 
    if bId == bExpected: 
     bFound = b 
     break 
else: # not found 
    raise Exception("No B '%s' found" % bExpected) 
# similar for c 

Я хотел использовать XPath для поиска данных. я могу сделать это с (ElementTree):

root.findall(".//a[@val=%s]/b[@val=%s]/c[@val=%s]" % (aExpected, bExpected, cExpected)) 

код выглядит намного лучше прямо сейчас. Но когда данные не найдены в XML, findall() возвращает None, и мне приходится вручную анализировать файл для первого несогласованного элемента.

Есть ли возможность в ElementTree (или другом XML API) использовать XPath и вернуть XPath первую точку сбойного сбоя (аналогично предложениям else в исходном коде)?

Как указано в одном ответе, код может быть замещен:

aFound = root.find(".//a[@val=%r]" % (aExpected,)) 
if not aFound: 
    raise("A not present") 
bFound = aFound.find("b[@val=%r]" % (bExpected,)) 
if not bFound: 
    raise("B not present") 
cFound = bFound.find("c[@val=%r]" % (cExpected,)) 
if not cFound: 
    raise("C not present") 

Да, это, безусловно, чище, чем оригинал, но я искал библиотеку, которое дало бы эту информацию мне.

ответ

0
aFound = root.findall(".//a[@val=%r]" % (aExpected,))[0] 
bFound = aFound.findall("b[@val=%r]" % (bExpected,))[0] 
cFound = bFound.findall("c[@val=%r]" % (cExpected,))[0] 

IndexError будет поднимать на первой строке, которая не находит элементов.


Или, чтобы избежать обнаружения всех элементов, когда вы хотите только один, использовать find:

aFound = root.find(".//a[@val=%r]" % (aExpected,)) 
bFound = aFound.find("b[@val=%r]" % (bExpected,)) 
cFound = bFound.find("c[@val=%r]" % (cExpected,)) 

теперь AttributeErrorNoneType не find метод) будет поднят на линии после тот, где не было найдено элемента.

0

Для следующих XML

<a val="a1"> 
    <b val="b1"> 
    <c val="c1"> 
     Data 
    </c> 
    </b> 
</a> 

Работает этот код

import xml.etree.ElementTree as ET 

file = "sample.xml" 
aExpected = "a1" 
bExpected = "b1" 
cExpected = "c1" 

tree = ET.parse(file) 
root = tree.getroot() 

bFound = root.find("./b[@val='" + bExpected + "']") 
cFound = root.find(".//c[@val='" + cExpected + "']") 

print(root) 
print(bFound) 
print(cFound) 

Выход есть:

<Element 'a' at 0x02919B10> 
<Element 'b' at 0x02919BD0> 
<Element 'c' at 0x02919C30> 

xml.etree.ElementTree не находят ничего в XPath becouse а является корневым элементом

Если вы хотите найти элемент изменить XML следующим способом

<root> 
<a val="a1"> 
    <b val="b1"> 
    <c val="c1"> 
     Data 
    </c> 
    </b> 
</a> 
</root> 

и код

import xml.etree.ElementTree as ET 

file = "sample.xml" 
aExpected = "a1" 
bExpected = "b1" 
cExpected = "c1" 

tree = ET.parse(file) 
root = tree.getroot() 

aFound = root.find("./a[@val='" + aExpected + "']") 
bFound = root.find(".//b[@val='" + bExpected + "']") 
cFound = root.find(".//c[@val='" + cExpected + "']") 

print(aFound) 
print(bFound) 
print(cFound) 

Результат будет

<Element 'a' at 0x02919B10> 
<Element 'b' at 0x02919BD0> 
<Element 'c' at 0x02919C30> 

С уважением

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