A bit simpler might be this:
SELECT x.n.value('.', 'nvarchar(20)') as 'Name'
FROM @result.nodes('/A
/B
/*[local-name() =sql:variable("@NodePath")]
/@*[local-name()=sql:variable("@NodeVariable")]') x(n)
The idea in short:
- Dive down below
<B> (or use the deep search with // if you can be sure, that there will be no <C> in any other place)
- Find any element with the given name
- pick the attribute with the given name (attributes are singleton per element per definition)
- use
value() on the current node to return the content.
What might disturb this: Multiple occurences of <C> below <B>
UPDATE Some additions to XPath and local-name()
Just try this:
declare @result xml =
N'<A>
<B>
<C name="Name01"/>
</B>
<TheSecondInA />
<B>
<C name = "Name02"/>
</B>
<OneMore someAttr="x" oneMoreAttr="y" theLastAttr="z" >SomeText</OneMore>
</A>';
SELECT @result.value('local-name((//TheSecondInA)[1])','varchar(100)')
,@result.value('local-name((/A/*[2])[1])','varchar(100)')
,@result.value('local-name(/A[1]/*[2])','varchar(100)')
,@result.value('local-name((//*[@someAttr]/@*[2])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/@*[3])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/@*[last()])[1])','varchar(100)')
,@result.value('local-name((/A/OneMore/text())[1])','varchar(100)')
,@result.value('local-name((/DoesNotExist)[1])','varchar(100)')
As you can see, the function local-name() must get a singleton XPath.
- The deep search dives to the first occurance of a named node
- The same is returned by the second element below
<A>
- We do not need this
(SomeXpath)[1] if the path itself guarantees to return a singleton.
- Here we dive to the first element where there is an attribute called
someAttr and pick the second attribute by its position.
- Similiarly we can pick the third attribute on a given path
- To get the very last attribute (or element) we can use
last()
- If the current node is a
text() node, or if the element does not exist, we get an empty string back.
Hint: With similiar XPath expressions you can use .value() to retrieve local content, .exist() to test for existance (or the lack of it) and to modify a given location...