Reputation: 1336
I have XML that looks like the below code. My end goal involves changing some nodes and stripping out others using nodes, exist, value, and then recreating this new XML using FOR XML PATH - which is all working fine.
However, I cannot figure out how to get back just the row/attributes for "Secondary", specifically the xmlns:xsi and xmlns:xsd).
For the below example, how do I just get the namespace attributes inside Secondary, so that I can combine it with the tweaked event/myfield/etc using FOR XML PATH? Or do I need to write a FLWOR to do this? (And if so, any advice on at least this part?)
What I want, at the end:
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
I can then combine it with the other fields I'm mucking with using FOR PATH XML and feed it downstream. If it's any easier, could you pull out the xmlns:xsi and xmlns:xsd with "value" and concatenate it so that it looks the same?
DECLARE @xml TABLE (id int IDENTITY, switch_xml XML)
INSERT INTO @xml (switch_xml)
VALUES ('<MAIN>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>a</myfield>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>a</myfield>
</Secondary>
</MAIN>
')
SELECT
--- ???? getting the Secondary here
Ev.Dat.query('event')
FROM @xml X OUTER APPLY switch_xml.nodes('/MAIN/Secondary') AS Ev(Dat)
More reproducible example:
<MAIN>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>
requested returned - because there's a event 53, strip out just myfield on the event 56. If there wasn't an event 53 node, you'd leave the 56 alone
<MAIN>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield></myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>
my example of that query, which doesn't handle the namespace: (writing it now - this gets the nodes, just need to properly wrapper it to combine the nodes into one MAIN)
SELECT
--- ???? getting the Secondary here
CONVERT(XML,(SELECT Ev.Dat.query('event') ,
CASE WHEN switch_xml.exist('/MAIN/EventData[event="56"]') = 1 AND ev.dat.value('(event)[1]','int') IN (53) THEN ev.dat.query('(myfield)[1]')
WHEN switch_xml.exist('/MAIN/EventData[event="56"]') = 0 AND ev.dat.value('(event)[1]','int') IN (53) THEN ev.dat.query('(myfield)[1]') else '' END
,Ev.Dat.query('myfield2') FOR XML PATH('Secondary'))) AS newxml
FROM @xml X OUTER APPLY switch_xml.nodes('/MAIN/Secondary') AS Ev(Dat)
Upvotes: 0
Views: 261
Reputation: 67311
Thanks for adding a sample to your XML.
Might be that this does not cover all your needs, but I think you might walk this route:
Attention: I'm assuming, that there is just one occurance of any event id per XML.
Your sample mockup table. I added two rows, one having event 53 and one not.
DECLARE @xml TABLE (id int IDENTITY, switch_xml XML)
INSERT INTO @xml (switch_xml)
VALUES
('<MAIN> <!-- event 53 exists -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>')
,(N'<MAIN> <!-- no event 53 here!!! -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>50</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>');
--using parameters makes life easier
DECLARE @SearchForEvent INT = 53;
DECLARE @ChangeThisEvent INT = 56;
DECLARE @ReplaceWith VARCHAR(100)='Some replacement';
--We can use .modify()
to update the needed value
UPDATE @xml SET switch_xml.modify('replace value of (/MAIN[Secondary[event=sql:variable("@SearchForEvent")]]
/Secondary[event=sql:variable("@ChangeThisEvent")]
/myfield
/text())[1] with sql:variable("@ReplaceWith")');
--Check the result
SELECT * FROM @xml;
The first XML looks like this:
<MAIN>
<!-- event 53 exists -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>Some replacement</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>
... and the second like this
<MAIN>
<!-- no event 53 here!!! -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>50</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>
The idea in short:
.modify()
via XPath what to change<MAIN>
if there is a <Secondary>
, which has a <event>
element with the value as given (=53)<Main>
into <Secondary>
, searching for an element where <event>
has the other given value (=56)Upvotes: 1