XML Tutorial · XML in the Real World · Lesson 26 of 28

XML Configuration Files

Reading and editing XML configuration found in real projects: Maven pom.xml, Android manifests, .NET project files and more.

Create a free account to save this page, take notes and track your progress. Sign in

Where you'll meet XML configuration

File Ecosystem
pom.xml Java (Maven) builds and dependencies
AndroidManifest.xml, res/layout/*.xml Android apps
*.csproj, web.config, app.config .NET
phpunit.xml, phpcs.xml PHP tooling
log4j2.xml, logback.xml Java logging
.idea/*.xml JetBrains IDE settings

Reading a Maven POM

POM files are namespaced, a frequent source of "my XPath returns nothing" bugs:

List Maven dependenciesTry it yourself
from lxml import etree

pom = etree.fromstring(b"""<project xmlns="http://maven.apache.org/POM/4.0.0">
  <groupId>com.readycamel</groupId>
  <artifactId>shop</artifactId>
  <version>1.4.0</version>
  <dependencies>
    <dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>42.7.4</version></dependency>
    <dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.11.3</version><scope>test</scope></dependency>
  </dependencies>
</project>""")
ns = {"m": "http://maven.apache.org/POM/4.0.0"}
print(pom.findtext("m:artifactId", namespaces=ns), pom.findtext("m:version", namespaces=ns))
for dep in pom.iterfind("m:dependencies/m:dependency", ns):
    scope = dep.findtext("m:scope", default="compile", namespaces=ns)
    print(f"- {dep.findtext('m:groupId', namespaces=ns)}:{dep.findtext('m:artifactId', namespaces=ns)}:"
          f"{dep.findtext('m:version', namespaces=ns)} ({scope})")

Output

shop 1.4.0
- org.postgresql:postgresql:42.7.4 (compile)
- org.junit.jupiter:junit-jupiter:5.11.3 (test)

Editing configuration safely

Tools that rewrite config files should change only what they must, keeping comments and formatting. lxml keeps comments and, with remove_blank_text=False (the default), the original whitespace:

Change values, keep commentsTry it yourself
from lxml import etree

source = b"""<configuration>
  <!-- connection pool: tuned for production -->
  <pool size="10" timeout="30"/>
  <logging level="info"/>
</configuration>"""

config = etree.fromstring(source)
config.find("pool").set("size", "25")
config.find("logging").set("level", "warn")
print(etree.tostring(config).decode())

Output

<configuration>
  <!-- connection pool: tuned for production -->
  <pool size="25" timeout="30"/>
  <logging level="warn"/>
</configuration>

Test yourself

Why does //dependency return nothing on a Maven pom.xml?

  1. The POM uses a default namespace
  2. Maven files aren't XML
  3. XPath can't read attributes
  4. Dependencies are in a separate file
Show answer

Answer: The POM uses a default namespace

POM elements are in http://maven.apache.org/POM/4.0.0; map a prefix to it in your query.

Was this page helpful?