Parsing pom.xml file with pythin doesn't work in older python versions

Viewed 160

Let me begin with the obvious fact I am not a python developer - I write code mainly in other languages, thus please excuse me if there is an "obvious" answer to this question.

I've written a very simple PomParser class which is supposed to be used as a wrapper around the ElementTree and will return some values from a pom.xml file as a string. The code below works fine in Python 3.8, but does not work in Python >= 3 && < 3.8.

import xml.etree.ElementTree as ET
import sys
from pathlib import Path


class PomParser:
    data = """<project xmlns="http://maven.apache.org/POM/4.0.0"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <groupId>org.example</groupId>
      <scm><connection>scm:git:git://github.com</connection></scm>
    </project>
    """

    tree = None

    namespaces = {'': 'http://maven.apache.org/POM/4.0.0'}

    def __init__(self):
        self.tree = ET.fromstring(self.data)

    def getTree(self):
        return self.tree

    def getGroupId(self):
        return self.findTextByXpath("./groupId")

    def findTextByXpath(self, xpath: str):
        element = self.findByXpath(xpath)
        return element.text if element is not None else None

    def findByXpath(self, xpath: str):
        return self.tree.find(xpath, self.namespaces)

parser = PomParser()
print("Python: ", sys.version)
print("Without defining namespace: ", parser.findTextByXpath("./groupId"))
print("Explicitly defining namespace: ", parser.getTree().findtext("./{http://maven.apache.org/POM/4.0.0}groupId"))

If you run this code through rept.it (example, which uses Python 3.8 it will print:

Python:  3.8.3 (default, May 14 2020, 20:11:43) 
[GCC 7.5.0]
Without defining namespace:  org.example
Explicitly defining namespace:  org.example

However, if you run the same code in https://www.onlinegdb.com/online_python_compiler, which seems to be using Python 3.4 - it will print:

Python:  3.4.3 (default, Nov 12 2018, 22:25:49)                                                                                                                                                                                                   
[GCC 4.8.4]                                                                                                                                                                                                                                       
Without defining namespace:  None                                                                                                                                                                                                                 
Explicitly defining namespace:  org.example   

I used onlinegdb simply because it reproduces an issue I am having with the same code in Netlify where the latest version is Python 3.7 (and is actually my targeted version to add support for)

I'm wondering what am I missing here? Do I really need to explicitly define the namespace inside the xpath filter? If that's the case - then what's the purpose of being able to define namespaces as an argument when it does nothing ??

1 Answers

This is related to changes in Python 3.8. In that version, it is possible to have an empty string as the prefix in a namespace mapping. That does not work in earlier versions.

If you change

namespaces = {'': 'http://maven.apache.org/POM/4.0.0'}

to

namespaces = {'p': 'http://maven.apache.org/POM/4.0.0'}

and change

./groupId

to

./p:groupId

it should work in all versions of Python 3.

Related