Я работаю над утилитой python для поиска и представления полного пути к записи в очень большом файле конфигурации, хранящемся в виде XML-файла. Размер файла может быть 12M и может содержать 294460 строк и может вырасти до гораздо большего размера.python xml поиск по значению атрибута
Вот пример (упрощенно):
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<root version="1.1.1">
<record path="">
<record path="path1">
<field name="some_name1" value="1234"/>
<record path="path2">
<field name="0" value="abcd0"/>
<field name="1" value="abcd1"/>
<field name="2" value="abcd2"/>
<field name="28" value="abcd28"/>
<field name="29" value="abcd29"/>
</record>
</record>
<record path="pathx">
<record path="pathy">
<record path="pathz">
</record>
<record path="pathv">
<record path="pathw">
<field name="some_name1" value="yes"/>
<field name="some_name2" value="2084"/>
<field name="some_buffer_name" value="14"/>
<record path="cache_value">
<field name="some_name7000" value="12"/>
</record>
</record>
<record path="path_something">
<field name="key_word1" value="8"/>
<field name="key_word2" value="9"/>
<field name="key_word3" value="10"/>
<field name="key5" value="1"/>
<field name="key6" value="1"/>
<field name="key7" value="yes"/>
</record>
</record>
</root>
Я заинтересован, чтобы запустить файл и файл все узлы, которые держат строку поиска в пути или поля атрибута узла. Потому что «тип» узла (или имя узла) может быть или записывать или поле, и, таким образом, имя атрибута может меняться от пути к имени.
Я использовал minidom для разбора и поиска в xml, но мой код берет слишком много ресурсов и слишком много времени.
Это то, что я писал: xml_file_location является расположение файла string_to_search является строка, я искать в файле XML и путь к этому узлу, который я нашел хранится в узле типа: запись , в атрибуте named: path, и это то, что я печатаю пользователю.
with open(xml_file_location, 'r') as inF:
# search the xml file for lines with the string for search
for line in inF:
if string_to_search in line:
found_counter = found_counter + 1
node_type = line.strip(" ").split(" ")[0]
node_type = re.sub('[^A-Za-z0-9]+', '', node_type)
node_attr = line.strip(" ").split(" ")[1]
node_value = re.sub('[^A-Za-z0-9_]+', '', node_attr.split("=")[1])
node_attr = re.sub('[^A-Za-z0-9]+', '', node_attr.split("=")[0])
#print node_type
#print node_attr
#print node_value
if node_type in lines_dict:
if not node_attr in lines_dict[node_type]:
lines_dict[node_type][node_attr] = [nome_value]
elif not node_value in lines_dict[node_type][node_attr]:
lines_dict[node_type][node_attr].append(node_value)
else:
lines_dict[node_type] = {}
lines_dict[node_type][node_attr] = [node_value]
print "Found: %s strings in the xml file" %found_counter
#pp = pprint.PrettyPrinter(indent=4)
#pp.pprint(lines_dict)
print "Parsing the xml file"
dom = parse(xml_file_location)
print "Locating the full path"
for node_type in lines_dict:
# for all types of node
elements = dom.getElementsByTagName(node_type)
# create the elements for those nodes
for node in elements:
# go over all nodes in the elements
if node.hasAttribute(node_attr):
if node.getAttribute(node_attr) in lines_dict[node_type][node_attr]:
# check if the attribute appears in the lines dict
result = node.getAttribute(node_attr) # holds the path
parent = node.parentNode # create a pointer to point on the parent node
while parent.getAttribute("path") != "":
# while didn't reach the root of the conf - a record that has an empty path attribute
result = parent.getAttribute("path") + "." + result # add the path of the parent to the full path
parent = parent.parentNode # advance the parent pointer
print
print "Found: %s" %node.toprettyxml().split("\n")[0]
print "Path: %s" %result
, например: я буду искать: abcd1 утилита напечатает полный путь: path1.path2 или я буду искать: pathw и утилита будет возвращать: pathx.pathy.pathv
Я понимаю, что это очень неэффективно, я просматриваю все узлы в конфиге и сравниваю их с тем, что я помещал в list_dic в простой поиск строки.
Я пытался использовать внешние модули, чтобы сделать это, но без успеха
Я ищу более эффективный способ сделать этот вид поиска, и я очень ценю помощь.
Вы * действительно * не хотите использовать minidom для этого; вместо этого используйте API ElementTree, который поддерживает итеративный синтаксический анализ. Извлеките только то, что вам нужно, когда будете разбираться. –
Читайте здесь: http: // effbot.орг/зона/элемент-iterparse.htm; ElementTree является частью стандартной библиотеки Python: http://docs.python.org/2/library/xml.etree.elementtree.html –
Спасибо Martijn, Моя первая попытка заключалась в использовании xml.etree.ElemntTree, , но Я запутался в этом, так как я ищу значение атрибута, и я не знаю, каким будет тип атрибута - будет ли это атрибут с именем «путь» или «имя», и, кроме того, я не знаю, каков уровень узла - это может быть дочерний корень или дочерний элемент дочернего элемента дочернего элемента root. Поэтому я попытался изменить Xpath: http://docs.python.org/2/library/xml.etree.elementtree.html#xpath-support , но не смог изменить выражение xpath Element.findall(). – Elia