Вопрос

The task i have to grab the elements of a given XML , generate xpath for each element and then retrieve the values of each element:

I am able to create step one and two but when an element has attributes the XPATH doesn't work:

so if i had the following XPATH:

/Envelope[1]/Body[1]/sVerify[1]/verifyPost[1]/Message[1]/Error[1]
/Envelope[1]/Body[1]/sVerify[1]/verifyPost[1]/scope[1]/machine[1]/space[1]
/Envelope[1]/Body[1]/sVerify[1]/verifyPost[1]/scope[1]/Date[1]

It works for Below XML and am able to get elements value correctly:

-- Works: I can retrieve the Elements values using XPATH
<Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <sVerify>
            <verifyPost>
                <scope>
                    <machine>
                        <name>test</name>
                        <space>test2</space>
                    </machine>
                    <Sys>internal</Sys>
                    <Date>2013-02-28</Date>
                </scope>
                <Message>
                    <Error>11111111111</Error>
                    <Descrip>222222222</Descrip>
                </Message>
                <Final>true</Final> 
                <Receipt>33333</Receipt>
            </verifyPost>
        </sVerify>
    </Body>
</Envelope>

Notice that i had to manually remove all the attirbutes in order for XPATH to work. It doesn't work if the XML was as below:

-- Doesn't work: can't get the elements value
<Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <sVerify xmlns="http://www.myCompany.com/Location/2014">
            <verifyPost>
                <scope>
                    <machine xmlns:i="http://www.myCompany.com/Location/2014">
                        <name>test</name>
                        <space>test2</space>
                    </machine>
                    <Sys>internal</Sys>
                    <Date>2013-02-28</Date>
                </scope>
                <Message xmlns="http://www.myCompany.com/Location/2014">
                    <Error>11111111111</Error>
                    <Descrip>222222222</Descrip>
                </Message>
                <Final xmlns="http://www.myCompany.com/Location/2014">true</Final>  
                <Receipt>33333</Receipt>
            </verifyPost>
        </sVerify>
    </Body>
</Envelope>

There can be any number of attributes so i never know in advance what the attirbutes are going to be. What is the correct way to ensure an XPATH will always find the value of the given element regardless of if it has attributes or not.

Below is how i execute it in TSQL:

DECLARE @generatedXPATH nvarchar(500),
    @elementVal nvarchar(50),
    @xml xml,
    @query nvarchar(max)

-- it works with this payload
-- because attributes aren't there replacing it with xml
-- where element attributes are present fails the element value extraction using xpath 
SET @xml = '<Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <Body> <sVerify> <verifyPost> <scope> <machine> <name>test</name> <space>test2</space> </machine> <Sys>internal</Sys> <Date>2013-02-28</Date> </scope> <Message> <Error>11111111111</Error> <Descrip>222222222</Descrip> </Message> <Final>true</Final> <Receipt>33333</Receipt> </verifyPost> </sVerify> </Body> </Envelope>'

SET @generatedXPATH = '/Envelope[1]/Body[1]/sVerify[1]/verifyPost[1]/scope[1]/machine[1]/space[1]'
SET @elementVal = ''
SET @query = N'SELECT @elementVal=    Nodes.node.value(''(' + @generatedXPATH
                           + ')[1]'', ''varchar(50)'')  FROM   @xml.nodes(''.'') AS Nodes(node)'; 

exec sp_ExecuteSql 
@query, 
N' @xml xml,@elementVal nvarchar(max) output', 
@xml = @xml, 
@elementVal = @elementVal output

select @elementVal 

Update:

Seems like only the attributes where attribute is without prefix is causing the issue. for example if attribute is xlmns="..........." then i am not able to grab its value using XPATH, if attribute was xlmns:i=".........." then it seems to work. Not sure what's going on.

Это было полезно?

Решение

If you have a XML with a custom namespace, you need to define it and use it as an affix for every element that is defined under that namespace using WITH XMLNAMESPACES (http://technet.microsoft.com/en-us/library/ms177607.aspx) In your case, try this:

SET @generatedXPATH = '/Envelope[1]/Body[1]/ns:sVerify[1]/ns:verifyPost[1]/ns:scope[1]/ns:machine[1]/ns:space[1]'
SET @elementVal = ''
SET @query = N'WITH XMLNAMESPACES (''http://www.myCompany.com/Location/2014'' AS ns) 
    SELECT @elementVal=    Nodes.node.value(''(' + @generatedXPATH
                           + ')[1]'', ''varchar(50)'')  FROM   @xml.nodes(''.'') AS Nodes(node)'; 

Edit: If you do not know the namespace, using * instead of ns should work for getting the element regardless of namespace:

SET @generatedXPATH = '/Envelope[1]/Body[1]/*:sVerify[1]/*:verifyPost[1]/*:scope[1]/*:machine[1]/*:space[1]'
SET @elementVal = ''
SET @query = N'SELECT @elementVal=    Nodes.node.value(''(' + @generatedXPATH
                           + ')[1]'', ''varchar(50)'')  FROM   @xml.nodes(''.'') AS Nodes(node)'; 
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top