Управляемая строка не совпадает с символом char *. Что происходит под прикрытием, так это то, что код маршалинга на слое interop делает копию неуправляемой строки, чтобы преобразовать ее в управляемую строку, но она не может освободить эту память, поскольку она не знает, как она была выделена.
Однако вы можете попробовать выделить и вернуть BSTR вместо char *.
Причина, по которой это имеет значение, - это то, как выделяются char * и BSTR в памяти.
Символ * буферы распределяются в куче среды выполнения C ++ с использованием частных процедур распределения / освобождения, которые CLR ничего не знает, поэтому нет возможности удалить эту память. И чтобы еще хуже, буфер, который char * указывает, может быть выделен внутренней реализацией кучи DLL-кода или даже может указывать на переменную-член в частном классе.
BSTR on другая сторона выделяется с использованием WIndows API SysAllocString и освобождается SyFreeStirng, и поскольку уровень взаимодействия CLR об этих API Windows знает, как освободить BSTR от неуправляемого кода.
for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
for child in element:
print child.tag, child.text
element.clear()
окончательное очищение остановит вас от использования слишком большого количества памяти.
[update:], чтобы получить «все между ... как строку», я думаю, вы хотите один из:
for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
print etree.tostring(element)
element.close()
или
for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
print ''.join([etree.tostring(child) for child in element])
element.close()
или, возможно, даже:
for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
print ''.join([child.text for child in element])
element.close()
Для будущих поисковиков: главный ответ здесь предлагает очистить элемент на каждой итерации, но это все равно оставляет вас с постоянно увеличивающимся набором пустых элементов, которые будут медленно нарастать в памяти:
for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
for child in element:
print child.tag, child.text
element.clear()
^ Это не масштабируемое решение, тем более, что ваш исходный файл становится все больше и больше. Лучшее решение - получить элемент root и очистить , что каждый раз, когда вы загружаете полную запись. Это сохранит использование памяти довольно стабильно (суб-20MB, я бы сказал).
Вот решение, которое не требует поиска определенного тега. Эта функция возвращает генератор, который дает все узлы 1-го ребенка (например, <BlogPost>
) под корневым узлом (например, <Database>
). Это делается путем записи начала первого тега после корневого узла, затем ожидания соответствующего конечного тега, получения всего элемента, а затем очистки корневого узла.
from lxml import etree
xmlfile = '/path/to/xml/file.xml'
def iterate_xml(xmlfile):
doc = etree.iterparse(xmlfile, events=('start', 'end'))
_, root = next(doc)
start_tag = None
for event, element in doc:
if event == 'start' and start_tag is None:
start_tag = element.tag
if event == 'end' and element.tag == start_tag:
yield element
start_tag = None
root.clear()
source->jobs->job->...
, а в другом - jobs->job
. Я хочу получить только все job
. Как мне это сделать с этим решением?
– Ahsanul Haque
21 April 2018 в 12:02
Я предпочитаю XPath для таких вещей:
In [1]: from lxml.etree import parse
In [2]: tree = parse('/tmp/database.xml')
In [3]: for post in tree.xpath('/Database/BlogPost'):
...: print 'Author:', post.xpath('Author')[0].text
...: print 'Content:', post.xpath('Content')[0].text
...:
Author: Last Name, Name
Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dictum dictum vehicula.
Author: Last Name, Name
Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dictum dictum vehicula.
Author: Last Name, Name
Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dictum dictum vehicula.
Я не уверен, что он отличается от обработки больших файлов. Замечания об этом будут оценены.
Выполняйте свой путь,
for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
for info in element.iter():
if info.tag in ('Author', 'Content'):
print info.tag, ':', info.text
BlogPost
, вы также можете использовать for post in tree.xpath('//BlogPost'): ...
– Lev Levitsky
25 March 2012 в 00:58
iterparse
с clear()
потребляет много меньше памяти, чем просто XPath
.
– Lev Levitsky
9 April 2012 в 20:28
lxml.etree.tostring()
делает это. Вы можете вырезать ярлык открытия и закрытия с помощью нотации среза (см. в этой таблице ) – Lev Levitsky 25 March 2012 в 11:13element.close()
бытьelement.clear()
в последующих фрагментах? так как я написал это, я больше не помню, но это выглядит неправильно. – andrew cooke 10 December 2012 в 14:01