Repository: yt-dlp/yt-dlp
File: yt_dlp/utils/traversal.py (Python)

Code before:
            has_specials = special.startswith('@') or special == 'text()'
            if not has_specials:
                xpath = f'{xpath}{sep}{special}'

            # Allow abbreviations of relative paths, absolute paths error
            if xpath.startswith('/'):
                xpath = f'.{xpath}'
            elif xpath and not xpath.startswith('./'):
                xpath = f'./{xpath}'

            findings = obj.iterfind(xpath) if xpath else [obj]
            if has_specials:
                result = [
                    element.attrib if special == '@'
                    else try_call(element.attrib.get, args=(special[1:],)) if special.startswith('@')
                    else element.text if special == 'text()'
                    else None
                    for element in findings
                ]
            else:
                result = list(findings)

        return branching, result if branching else (result,)

    def lazy_last(iterable):
        iterator = iter(iterable)
        prev = next(iterator, NO_DEFAULT)
        if prev is NO_DEFAULT:
            return

        for item in iterator:
            yield False, prev
            prev = item

        yield True, prev

    def apply_path(start_obj, path, test_type):
        objs = (start_obj,)
        has_branched = False

        key = None
        for last, key in lazy_last(variadic(path, (str, bytes, dict, set))):
            if not casesense and isinstance(key, str):
                key = key.casefold()

            if __debug__ and callable(key):
                # Verify function signature
                inspect.signature(key).bind(None, None)

            new_objs = []
            for obj in objs:

Review comment (suggestion):
I would be for only returning the value instead of a list, when `@attr` ot `text()` are used without a leading xpath.
Pretty much in every case that you pass a sole `@attr` you would want to retrieve the actual value and not a list with the value. Currently, you need to do this:
```python
traverse_obj(etree, ('@name', 0)) # string 
traverse_obj(etree, ('text()', 0)) # string
```

Code after:
            if not special.startswith('@') and special != 'text()':
                xpath = key
                special = None

            # Allow abbreviations of relative paths, absolute paths error
            if xpath.startswith('/'):
                xpath = f'.{xpath}'
            elif xpath and not xpath.startswith('./'):
                xpath = f'./{xpath}'

            def apply_specials(element):
                if special is None:
                    return element
                if special == '@':
                    return element.attrib
                if special.startswith('@'):
                    return try_call(element.attrib.get, args=(special[1:],))
                if special == 'text()':
                    return element.text
                assert False, f'apply_specials is missing case for {special!r}'

            if xpath:
                result = list(map(apply_specials, obj.iterfind(xpath)))
            else:
                result = apply_specials(obj)

        return branching, result if branching else (result,)

    def lazy_last(iterable):
        iterator = iter(iterable)
        prev = next(iterator, NO_DEFAULT)
        if prev is NO_DEFAULT:
            return

        for item in iterator:
            yield False, prev
            prev = item

        yield True, prev

    def apply_path(start_obj, path, test_type):
        objs = (start_obj,)
        has_branched = False

        key = None
        for last, key in lazy_last(variadic(path, (str, bytes, dict, set))):
            if not casesense and isinstance(key, str):
                key = key.casefold()

            if __debug__ and callable(key):
                # Verify function signature