XPath (XML Path Language) selects nodes in an XML document using path expressions — similar to filesystem paths. XPath 1.0 is universally supported; XPath 2.0/3.x adds types, functions, and sequences.
| Item | Syntax / Value | Description |
|---|---|---|
| /root | Absolute path from root | Select root element |
| //element | Select anywhere in document | Descendant-or-self shortcut |
| . | Current node | Context node |
| .. | Parent node | Parent axis |
| @attr | Attribute node | Select attribute |
| * | Any element | Wildcard element |
| @* | Any attribute | Wildcard attribute |
| node() | Any node | Element, text, comment, PI |
| text() | Text node children | Select text content |
| element[n] | Position predicate | nth element (1-indexed) |
| element[last()] | Last element | Select last sibling |
| [condition] | Predicate filter | Filter nodes by condition |
| [@attr='val'] | Attribute value filter | Select by attribute value |
| [text()='val'] | Text content filter | Select by text content |
| [contains(@a,'v')] | contains() function | Substring in attribute |
| [starts-with(@a,'v')] | starts-with() function | Attribute starts with value |
| [not(condition)] | not() function | Negate predicate |
| and / or | Boolean operators | Combine predicates |
| count(nodes) | count() function | Count selected nodes |
| sum(nodes) | sum() function | Sum numeric values |
| string(node) | string() function | Convert to string |
| normalize-space() | normalize-space() function | Trim and collapse whitespace |
| child:: | child axis (default) | Direct children |
| descendant:: | descendant axis | All descendants |
| ancestor:: | ancestor axis | All ancestors |
| following-sibling:: | following-sibling axis | All following siblings |
| preceding-sibling:: | preceding-sibling axis | All preceding siblings |
| parent:: | parent axis | Parent element |
<!-- XML file: students.xml (see XML Syntax section) -->
<!-- XPath expressions and what they select -->
/university <!-- root element -->
/university/department <!-- department elements -->
/university/department/@name <!-- name attributes of departments -->
/university//student <!-- all students anywhere in doc -->
/university//student[@status='active'] <!-- active students only -->
/university//student[1] <!-- first student -->
/university//student[last()] <!-- last student -->
/university//student/name/first <!-- all first names -->
/university//course/@grade <!-- all grade attributes -->
/university//course[@grade='A+'] <!-- courses with A+ grade -->
/university//course[@credits > 3] <!-- courses with > 3 credits -->
<!-- XPath in Python with lxml -->
from lxml import etree
tree = etree.parse("students.xml")
ns = {"u": "https://www.mywebuniversity.com/schema"}
# Find all active students
students = tree.xpath("//u:student[@status='active']", namespaces=ns)
for s in students:
sid = s.get("id")
name = s.findtext("u:name/u:first", namespaces=ns)
gpa = s.findtext("u:gpa", namespaces=ns)
print(f" ID={sid} Name={name} GPA={gpa}")
# Count courses per student
for s in students:
courses = s.xpath("u:courses/u:course", namespaces=ns)
print(f" {s.findtext('u:name/u:first',namespaces=ns)}: {len(courses)} courses")
# Sum all credits
total = tree.xpath("sum(//u:course/@credits)", namespaces=ns)
print(f"Total credits: {total}")
# Find A+ grades
top = tree.xpath("//u:course[@grade='A+']/u:title/text()", namespaces=ns)
print("A+ courses:", top)
# Using ElementPath (no lxml needed)
import xml.etree.ElementTree as ET
tree2 = ET.parse("students.xml")
root = tree2.getroot()
ns2 = {"u": "https://www.mywebuniversity.com/schema"}
for course in root.findall(".//u:course", ns2):
print(f" {course.findtext('u:title',namespaces=ns2)} — {course.get('grade')}")
# python3 xpath_demo.py (pip install lxml)