Why is an empty XML node xml datatype not being recognized in this query?
In (td//text())[1] the predicate [1] will return the first node returned by the XQuery (td//text()).

You are saying that you want the first text() node. But in the first td element there are no text nodes present so you get the text node for the second td element which is the first text node returned.

You need to specify the position predicate on the td node instead.

This will give you null in col1

select
     x.c.value('td[1]/text()[1]', 'varchar(1024)') as col1
    ,x.c.value('td[2]/text()[1]', 'varchar(1024)') as col2
    ,x.c.value('td[3]/text()[1]', 'varchar(1024)') as col3
from @x.nodes('/root/tr') x(c)


And not specifying the text() node will give you an empty string in col1.

select
     x.c.value('td[1]', 'varchar(1024)') as col1
    ,x.c.value('td[2]', 'varchar(1024)') as col2
    ,x.c.value('td[3]', 'varchar(1024)') as col3
from @x.nodes('/root/tr') x(c)