Okay, I know why it is not finding anything. This is related to how the XML parser works. Notice that you use the namespace prefix gte, but it is defined nowhere in your XML. When the XML parser finds this prefix but sees that it is not defined, it throws it away. You are left with a tag name of name but no namespace prefix of gte. This means you can only find the tag name with name, because gte is dropped.
from bs4 import BeautifulSoup XML1 = """ <?xml version="1.0" encoding="UTF-8"?> <gpx version="1.1"> <extensions> <gte:name>Some name</gte:name> </extensions> </gpx> """ soup = BeautifulSoup(XML1, "xml") name = soup.select_one('name') print(f"prefix: {getattr(name, 'prefix', '')}, name: {name.name}") # Find namespace: will fail print(soup.select_one("gte|*")) # Results # prefix: None, name: name # NoneNow, lets define gte as a proper namespace. Now we will see that since the namespace is defined, the XML parser will properly process gte and keep it as a prefix for the name tag. Now that element will have a name of name and a namespace prefix of prefix.
from bs4 import BeautifulSoup XML2 = """ <?xml version="1.0" encoding="UTF-8"?> <gpx version="1.1"> <extensions xmlns:gte="http://me.com/namespaces/gte"> <gte:name>Some name</gte:name> </extensions> </gpx> """ soup = BeautifulSoup(XML2, "xml") name = soup.select_one('name') print(f"prefix: {getattr(name, 'prefix', '')}, name: {name.name}") # Find namespace: will succeed print(soup.select_one("gte|*")) # Results prefix: gte, name: name <gte:name>Some name</gte:name>The escape doesn’t work because the name is stripped of gte in XML mode. So why did we suggest that? Well, if we use LXML in HTML mode, it will leave the prefix for abnormal, unsupported namespaces.
This time, we take the same example, but we use lxml to put it in LXML’s HTML mode. Now the element will have the name gte:name because there is no associated namespace. Using CSS escapes, we can target the name.
from bs4 import BeautifulSoup XML1 = """ <?xml version="1.0" encoding="UTF-8"?> <gpx version="1.1"> <extensions> <gte:name>Some name</gte:name> </extensions> </gpx> """ soup = BeautifulSoup(XML1, "lxml") name = soup.select_one(r'gte\:name') print(f"prefix: {getattr(name, 'prefix', '')}, name: {name.name}") print(name) # Results # prefix: None, name: gte:name # <gte:name>Some name</gte:name>Looking over the code, it seems we use `f"'{pseudo}' pseudo-class is not implemented at this time"` for invalid pseudo-class names in general. It is impossible for us to know if a pseudo-class is a real one or not because this can change. We could keep a list of currently known pseudo classes that we have not implemented (that would be a fairly small list), but that can become invalid at any time.I think a more practical solution is to simply change the message to something like `f"'{pseudo}' is not a valid pseudo-class"`. This implies a couple of things. One is that the syntax is recognized as an attempt to specify a pseudo-class, and the second is that Soup Sieve does not recognize the pseudo-class. This is better because it makes no claim that the pseudo-class is a real, unsupported pseudo-class or simply a bad pseudo-class name. This keeps it generic without implying anything about the specified pseudo-class name.