how to get the normalize-space() xpath function to

2020-01-29 10:06发布

I am currently trying the following xpath

//tr[normalize-space(td/text())='User Name']

to get all the tr that contains a td that contain 'User Name' or 'User Name' or ' User Name ' but its not working and I don't know what is wrong with the query :(
the data i want to find is in the following format

<tr><td>User Name</td></tr>
<tr><td>User     Name</td></tr>
<tr><td>  User Name   </td></tr>

So what is the right format to write this xpath query?

Edit: it seem not work if the data is in the following format

<tr><td>x</td><td>User Name</td></tr>
<tr><td>x</td><td>y</td><td>User     Name</td></tr>
<tr><td>x</td><td>y</td><td>z</td><td>  User Name   </td></tr>

so now how can i write the xpath query?
note: "//tr[normalize-space(td/text()) = 'User Name']" wont work
but "//tr/td[normalize-space(text()) = 'User Name']" will work (but i want to get the tr and not the td element)

标签: c# xpath
2条回答
疯言疯语
2楼-- · 2020-01-29 10:37

Now that you've edited the question, it makes sense. Let's consider this input:

<tr><td>x</td><td>User Name</td></tr>

and your non-working query:

//tr[normalize-space(td/text()) = 'User Name']

Now, td/text() means "select all child text nodes of all child td nodes of current node". In this case this will yield a node-set consisting two text nodes, x and User Name.

Now you call normalize-space() on that node-set. The type of the sole argument of normalize-space() is string?. Since a node-set is not a string, conversions kick in, per section 3.2 of XPath 1.0 recommendation:

An argument is converted to type string as if by calling the string() function.

Now let's look at the definition of string() in section 4.2:

A node-set is converted to a string by returning the string-value of the node in the node-set that is first in document order. If the node-set is empty, an empty string is returned.

In our example, the first node "in document order" is the text node x, so it is the one which will be used; the second node is ignored. Thus, you end up calling normalize-space('x'). Naturally, this won't compare equal to 'User Name'. To make this work, use:

//tr[td[normalize-space(text()) = 'User Name']]

This can be transcribed as "select all tr nodes that have child td nodes, the first child text() node of which has a normalized string value of User Name" - which is what you want. Furthermore, you can simplify this to:

//tr[td[normalize-space() = 'User Name']]

Since a no-argument normalize-space() will apply to the current node (which will be td), and process all text nodes within.

查看更多
我欲成王,谁敢阻挡
3楼-- · 2020-01-29 10:49

This works fine here:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(@"
    <table>
        <tr><td>User Name</td></tr>
        <tr><td> User   Name </td></tr>
        <tr><td>   User Name   </td></tr>
    </table>");

Console.WriteLine(
    xmlDoc.SelectNodes(
        "//tr[td[normalize-space(.) = 'User Name']]").Count); // shows "3"

Can you please update your question with a actual XML sample?

查看更多
登录 后发表回答