Search code examples
python-3.xxmlxpath

How to pass XML path to check for sibling relation in lxml - python


My python function to get the attribute value of an element

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

Snippet of 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" />

I want to get the value of attribute, 'value' in <priorityNumber value="1" />

If I send an xpath that is straightforward, it works.
xpath: .//outboundRelationship[@typeCode='SPRT']/priorityNumber

However, if I want to check for the attribute of PriorityNumber with a condition that it should be a sibling of ‘relatedInvestigation’ which in turn has a child node, ‘code’ with specific attribute. I get error ‘SyntaxError: invalid predicate

xpath: .//outboundRelationship[@typeCode='SPRT'][relatedInvestigation/code[@code='2'][@codeSystem='2.16.840.1.113883.3.989.2.1.1.22']]/priorityNumber

I tried using preceding:sibling in the xpath but that’s also not working.

How to send such xpath? Is there any other way of doing this?


Solution

  • OP's xpath expression is correct but find() method has limited xpath support. See also FAQ. Using xpath() instead of find() with same expression:

    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'])
    

    Result

    '1'
    

    lxml version

    etree.__version__
    '4.9.3'
    

    If namespaces are needed

    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)