Hi all,

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ABC="">
<soapenv:Header>
<ABC:ABCSHeader>
<ID>xyz</ID>
<ConsumerTransactionId>5667</ConsumerTransactionId>
</ABC:ABCSHeader>
</soapenv:Header>
<soapenv:Body>
<ABC:ABCSPGMOperation>
<ABC:req>
<ABC:plastic_number>1234</ABC:plastic_number>
</ABC:req>
</ABC:ABCSPGMOperation>
</soapenv:Body>
</soapenv:Envelope>

The above is my input passed by the client. How can I extract the values within the tag 'ID','ConsumerTransactionId' and 'ABC:plastic_number' using simple xpath expressions.

I know that if we give

/*[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/' and local-name()='Envelope']/*[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/' and local-name()='Header']/*[namespace-uri()='' and local-name()='ABCSHeader']/ID
this will fetch me the value of automation id

However instead of the above long expression is there a way to generalize such that I can search for the first occurence of 'ID' and take the value

something like
//*[local-name() = 'ID']

Dani AI

Generated

Short answer: there are three practical patterns — bind the namespaces in your XPath context and use prefixed names (best for clarity and speed), use a namespace-agnostic selector when you cannot bind prefixes, or walk the DOM programmatically.

already explored the local-name() technique; and pointed out unprefixed and fully-qualified queries. The recommended approach is to register the document namespaces in whatever XPath engine you use and then query with those prefixes — that keeps expressions readable and fast. If you cannot register prefixes (or your evaluator is XPath 2.0+), use the namespace-wildcard form; if neither is available, fall back to local-name() filters.

Example of a small DOM-based alternative (no XPath required) for immediate use in Python/lxml — this avoids repeating XPath namespace fiddling by inspecting element tags directly:

from lxml import etree

doc = etree.fromstring(xml_string)
for el in doc.iter():
    # lxml represents namespaced tags as "{namespace}localname"
    if el.tag.endswith('}plastic_number') or el.tag == 'plastic_number':
        plastic_value = el.text
        break

Notes and pitfalls:

  • When you use prefix-based XPaths you must bind the same URI to that prefix in the XPath evaluation context; the prefix in the document and the prefix in the XPath do not have to be the same text, only the URI must match.
  • XPath 2.0/3.0 engines support a namespace wildcard syntax (match any namespace for a local name) which is concise and robust if your processor supports it.
  • The local-name() approach works everywhere but is less readable and slightly slower; use it only when namespace binding is impossible.

Prefer namespace-aware queries for production code; use the DOM-inspection trick or the XPath wildcard when you need a quick workaround.

Recommended Answers

All 3 Replies

It works with /*/*/*/ID for ID

Is there a method to get an expression like /*/*/*/ID for plastic-number as well. This has a namespace compared to others.

use //ID

why not just //ID for the first?

//ABC:plastic_number

there's nothing to stop from using the fully qualified name in the xpath.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.