Моя функция Python для получения значения атрибута элемента
import lxml.etree as ET
def xml_get_attrib_value(filepath, xpath, attribute):
it = ET.iterparse(filepath)
for _, el in it:
_, _, el.tag = el.tag.rpartition('}')
root = it.root
element = root.find(xpath)
value = element.attrib[attribute]
return value
Фрагмент XML:
<outboundRelationship typeCode = "SPRT">
<priorityNumber value = "1" />
<relatedInvestigation classCode = "INVSTG" moodCode = "EVN">
<code code = "2" codeSystem = "2.16.840.1.113883.3.989.2.1.1.22" codeSystemVersion = "2.0" />
Я хочу получить значение атрибута «value» в <priorityNumber value="1" />
Если я отправлю простой xpath, он сработает.
xpath: .//outboundRelationship[@typeCode='SPRT']/priorityNumber
Однако, если я хочу проверить атрибут PriorityNumber с условием, что он должен быть родственным по отношению к «связанному расследованию», который, в свою очередь, имеет дочерний узел, «код» с определенным атрибутом. Я получаю ошибку «SyntaxError: invalid predicate»
xpath: .//outboundRelationship[@typeCode='SPRT'][relatedInvestigation/code[@code='2'][@codeSystem='2.16.840.1.113883.3.989.2.1.1.22']]/priorityNumber
Я пробовал использовать previous:sibling в xpath, но это тоже не работает.
Как отправить такой xpath? Есть ли другой способ сделать это?





Выражение xpath OP правильное, но метод find() имеет ограниченную поддержку xpath . Смотрите также Часто задаваемые вопросы.
Использование xpath() вместо find() с тем же выражением:
from lxml import etree
xtree = etree.parse('tmp.xml')
p = xtree.xpath(".//outboundRelationship[@typeCode='SPRT'][relatedInvestigation/code[@code='2'][@codeSystem='2.16.840.1.113883.3.989.2.1.1.22']]/priorityNumber")
print(p[0].attrib['value'])
Результат
'1'
lxml-версия
etree.__version__
'4.9.3'
Если необходимы пространства имен
ns = {'ns' : 'urn:hl7-org:v3'}
p = xtree.xpath(".//ns:outboundRelationship[@typeCode='SPRT'][ns:relatedInvestigation/ns:code[@code='2'][@codeSystem='2.16.840.1.113883.3.989.2.1.1.22']]/ns:priorityNumber",namespaces=ns)
Да, это может быть связано с пространствами имен. Вам не нужно публиковать весь XML, только соответствующую структуру. Вы можете попробовать //namespace::* перечислить все пространства имен в файле. Если вы используете Linux, эта команда может вывести список пространств имен: xmllint --xpath '//namespace::*' file.xml | sort | uniq
//namespace::* дает очень длинный список. Вот первые несколько строк в XML-файле: <?xml version = "1.0"coding = "utf-8"?> <MCCI_IN200100UV01 xmlns:fo = "w3.org/1999/XSL/Format " xmlns:mif = "urn:hl7-org:v3/mif" xmlns:xsi = " w3.org/2001/XMLSchema-instance " ITSVersion = "XML_1.0" xsi:schemaLocation = "urn:hl7-org:v3 ️ 🔁 eudravigilance.ema.europa.eu/XSD/multicacheschemas/…" xmlns = "urn:hl7-org:v3"> <!--N.1.2: Номер партии--> <id Extension = "US-DialogSolutions- Demo-PI011000-C1-20240223-184227" root = "2.16.840.1.113883.3.989.2.1.3.22" />
Обновил ответ. Это пространство имен, скорее всего, вам подходит: xmlns = "urn:hl7-org:v3"
Большое спасибо! Ценю вашу помощь. Просто интересно, есть ли способ игнорировать пространства имен?
вы можете использовать локальное имя, делая это для каждого элемента *[local-name() = "outboundRelationship"], но это даст вам длинное и некрасивое выражение. Вы также можете принять ответ, если хотите.
Спасибо! Это работает для примера XML-файла, в котором есть только упомянутый мной фрагмент. Однако если я использую весь большой XML-файл (с пространством имен и многими другими узлами вместе с этим фрагментом), он не идентифицирует элемент. 'P' возвращает пустой список. Может ли это быть связано с пространством имен? Какие еще вещи мне следует принять во внимание? Есть ли способ поделиться фактическим XML-файлом целиком?