Is there a way to use two @* in an xpath selector to select an element?

Viewed 61

I have an HTML element I would like to select that looks like this:

<button data-button-id="close" class="modal__cross modal__cross-web"></button>

Now clearly I can use this XPath selector:

//button[(contains(@data-button-id,'close')) and (contains(@class,'modal'))]

to select the element. However, I would really like to select buttons that have both close and modal contained in any attributes. So I can generalize the selector and say:

//button[(contains(@*,'close')) and (contains(@class,'modal'))] 

and that works. What I'd love to do is extend it to this:

//button[(contains(@*,'close')) and (contains(@*,'modal'))]

but that doesn't return any results. So clearly that doesn't mean what I'd like it to mean. Is there a way to do it correctly?

Thanks, Craig

3 Answers

It looks like you're using XPath 1.0: in 1.0, if you supply a node-set as the first argument to contains(), it takes the first node in the node-set. The order of attributes is completely unpredictable, so there's no way of knowing whether contains(@*, 'close') will succeed or not. In 2.0+, this gives you an error.

In both 1.0 and 2.0, @*[contains(., 'close')] returns true if any attribute contains "close" as a substring.

This expression works:
//button[attribute::*[contains(.,"close")] and attribute::*[contains(.,"modal")]]

Given this html

<button data-button-id="close" class="modal__cross modal__cross-web"></button>
<button key="close" last="xyz_modal"></button>

Testing with xmllint

echo -e 'cat //button[attribute::*[contains(.,"close")] and attribute::*[contains(.,"modal")]]\nbye' | xmllint --html --shell test.html 
/ > cat //button[attribute::*[contains(.,"close")] and attribute::*[contains(.,"modal")]]
 -------
<button data-button-id="close" class="modal__cross modal__cross-web"></button>
 -------
<button key="close" last="xyz_modal"></button>
/ > bye

Try this one to select required element:

//button[@*[contains(., 'close')] and @*[contains(., 'modal')]]
Related