2

I refer to How to get a particular attribute from XML element in SQL Server.

I do not have a particular attribute with the value of the node in it, but rather the I am looking for the value of the node depending on which attribute I am looking for.

I am selecting from an XML column in a table in SQL, but for simplicity sake, I can provide the following example:

DECLARE @xml xml = CONVERT(XML, '<?xml version="1.0" encoding="UTF-8"?>
<alert>
   <hits>
      <elem name="hit">
         <elem name="scoreFactors">
            <elem name="scoreFactors">
               <elem name="factorId">FactorID 1</elem>
               <elem name="factorDesc">FactorDesc 1</elem>
               <elem name="factorValue">FactorValue 1</elem>
               <elem name="factorScore">FactorScore 1</elem>
               <elem name="factorImpact">FactorImpact 1</elem>
            </elem>
            <elem name="scoreFactors">
               <elem name="factorId">FactorID 2</elem>
               <elem name="factorDesc">FactorDesc 2</elem>
               <elem name="factorValue">FactorValue 2</elem>
               <elem name="factorScore">FactorScore 2</elem>
               <elem name="factorImpact">FactorImpact 2</elem>
            </elem>
         </elem>
       </elem>
   </hits>
</alert>')

SELECT @xml.value('(/alert/hits/elem/elem[@name="factorDesc"])[1]', 'nvarchar(max)')

All I am getting back is a NULL value, but I am expecting 2 rows with FactorDesc 1 and FactorDesc 2 as values, respectively.

What am I doing wrong?

2
  • 1
    Just a quick note: you don't need that CONVERT. You can assign a string constant directly to a variable of type xml: DECLARE @xml xml = '<?xml version="1.0" encoding="UTF-8"?><alert></alert>' Commented Aug 11, 2015 at 9:44
  • cool thanks! I did not know that Commented Aug 11, 2015 at 14:48

2 Answers 2

3

That attribute you're looking for is on the fourth level of <elem> - so you need to use this XPath:

SELECT @xml.value('(/alert/hits/elem/elem/elem/elem[@name="factorDesc"])[1]', 'nvarchar(max)')

or alternatively use this XPath (but beware: this can be a killer of performance, if your XML has a lot of <elem> nodes! You've been warned!)

SELECT @xml.value('(/alert/hits//elem[@name="factorDesc"])[1]', 'nvarchar(max)')

Update: if you want all the nodes with the factorDesc name, you could use something like:

;WITH Shredded AS
(
    SELECT 
        ElemName = xc.value('@name', 'varchar(50)'),
        ElemValue = xc.value('.', 'varchar(50)') 
    FROM
        @xml.nodes('/alert/hits//elem') AS XT(XC)
)
SELECT *
FROM Shredded
WHERE Shredded.ElemName = 'factorDesc'
Sign up to request clarification or add additional context in comments.

3 Comments

thanks for pointing out that I need to specify all the levels down - or use //. Your second example is almost what I need, except that it only returns the first elem where the name attribute is factorDesc. Why isn't it returning a list of all elems where the name attribute is factorDesc?
@MrThursday: it's returning just the first one - because you tell it to by specifying that [1] ...
@MrThursday: updated my response to handle all nodes, too
1

Search in all elem's:

SELECT
    t.value('.','nvarchar(max)')
FROM @xml.nodes('(alert/hits//elem[@name="factorDesc"])') AS t(t)

5 Comments

Great, thanks! This is exactly what I am looking for except for one thing: If I had to change that query to be able to select all elem's out of an xml column, what would it look like?
@MrThursday out of xml column? can you give an example? i'm afaid, i don't understand
I guess it would be a nested select, where I would replace @xml with the column name? For the purpouses of my question, I supplied the example xml as variable. but in a more practical sense the xml would come from a a column in a table and would not be hard coded.
a query could look like this : SELECT t1.xmlColum FROM table1 t1
@MrThursday, oh, it will look the same, just replace @xml with column name

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.