Reading xml Structure in sql server 2012 - sql

Sample Xml Structure
<?xml version="1.0" encoding="UTF-8"?>
<XmlSerializableHashtable xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Entries>
<Entry>
<key xsi:type="xsd:string">col1</key>
<value xsi:type="xsd:string">500</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col2</key>
<value xsi:type="xsd:string">0/60,1/1000</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col3</key>
<value xsi:type="xsd:string">localhost</value>
</Entry>
</Entries>
</XmlSerializableHashtable>
No i am trying to get value where key is col3
I am trying with the Xquery
Declare #x xml;
Set #x = (Select valuefrom sometable)
Select #x.query('/Entries/Entry/')

This Query will be helpful.
DECLARE #xmlData AS XML
DECLARE #sRawData AS VARCHAR(2000)
SET #sRawData = '<?xml version="1.0" encoding="UTF-8"?>
<XmlSerializableHashtable xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Entries>
<Entry>
<key xsi:type="xsd:string">col1</key>
<value xsi:type="xsd:string">500</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col2</key>
<value xsi:type="xsd:string">0/60,1/1000</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col3</key>
<value xsi:type="xsd:string">localhost</value>
</Entry>
</Entries>
</XmlSerializableHashtable>'
SET #xmlData = CAST(#sRawData AS XML)
SELECT MainDataCenter.Col.value('(key)[1]','varchar(max)') AS [key]
,MainDataCenter.Col.value('(value)[1]','varchar(max)') AS Value
FROM #xmlData.nodes('/XmlSerializableHashtable/Entries/Entry') AS MainDataCenter(Col)
WHERE MainDataCenter.Col.value('(key)[1]','varchar(max)') = 'col3'

Related

can anyone please assist how to add Array resource in the XML (CLOB ) using the SQL?

<?xml version="1.0" encoding="UTF-8"?>
<Values version="2.0">
<record name="header" javaclass="com.wm.util.Values">
<value name="legalEntity">27</value>
<value name="globalId">a8a49f5d-70bb-421e-99f2-bb4065a46538</value>
<value name="priority">5</value>
<value name="requestor">COP</value>
</record>
<record name="body" javaclass="com.wm.util.Values">
<array name="orderItem" type="record" depth="1">
<record javaclass="com.wm.util.Values">
<value name="orderItemId">OS-1229460</value>
<array name="childOrderItem" type="record" depth="1">
<record javaclass="com.wm.util.Values">
<value name="orderItemId">280973171</value>
<array name="relatedOrderItem" type="record" depth="1">
<record javaclass="com.wm.util.Values">
<value name="orderType">CUSTOMER_ORDER</value>
<value name="orderItemId">280973171</value>
<value name="orderItemDataOwner">Clarify</value>
</record>
</array>
<value name="operationType">CANCEL</value>
<value name="operationSubType">DEFAULT</value>
<value name="status"> </value>
<value name="subStatus"> </value>
<value name="orderItemDateTime">2020-12-08T17:00:52</value>
<value name="articleNumber">STANDAARDSIMKAART</value>
<array name="childOrderItem" type="record" depth="1">
<record javaclass="com.wm.util.Values">
<value name="orderItemId">280973179</value>
<value name="operationType">CANCEL</value>
<value name="operationSubType">DEFAULT</value>
<value name="status"> </value>
<value name="subStatus"> </value>
<record name="product" javaclass="com.wm.util.Values">
<value name="productInstanceId">280973179</value>
<value name="productSpecificationId">SE555</value>
<value name="productSpecificationName">PRIVATE_APN</value>
<value name="productDescription">PRIVATE_APN</value>
<value name="productType">PRIVATE_APN</value>
<value name="manualOverride">false</value>
</record>
</record>
</array>
</record>
</array>
</record>
</array>
</record>
</Values>
To be more precise i have to add this Array resource After the manual override line
<array name="productInstanceCharacterstic" type="record" depth="1">
<record javaclass="com.wm.util.Values">
<value name="name">APNProductInstanceID</value>
<value name="value">281606343</value>
</record>
<record javaclass="com.wm.util.Values">
<value name="name">UseStaticIP</value>
<value name="value">No</value>
</record>
</array>
My code :
UPDATE SD2_95.ORDER_DATA sgo SET sgo.ORDER_CONTENT =
(XMLSERIALIZE
(
Document
(
XMLQuery
(
'copy $tmp := . modify
(for $i in $tmp//record[#name="body"]/value[#name=]/text()
return $tmp'
PASSING XMLTYPE(sgo.ORDER_CONTENT) RETURNING CONTENT
)
) AS CLOB INDENT SIZE = 2
)
)
WHERE sgo.ORDER_ID IN
(
'OS-1151955',
)
I am not sure how to implement the for loop... please help

XSLT 1.0 grouping on one or multiple levels

Today's challenge was grouping in XSLT 1.0. Found out there are something called keys and the Muenchian grouping.
Input XML:
<Items>
<Item>
<ID>1</ID>
<Name>A</Name>
<Country>Sweden</Country>
<Region>Småland</Region>
</Item>
<Item>
<ID>2</ID>
<Name>B</Name>
<Country>Sweden</Country>
<Region>Norrland</Region>
</Item>
<Item>
<ID>3</ID>
<Name>C</Name>
<Country>USA</Country>
<Region>Alaska</Region>
</Item>
<Item>
<ID>4</ID>
<Name>D</Name>
<Country>USA</Country>
<Region>Texas</Region>
</Item>
<Item>
<ID>5</ID>
<Name>E</Name>
<Country>Sweden</Country>
<Region>Norrland</Region>
</Item>
</Items>
I need to make thins XML into a better structure, and from this sample XML I't like to get items structured by country and region. Below is wanted result where country and region gets sorted as well:
<Items>
<Country Name="Sweden">
<Region Name="Norrland">
<Item>
<ID>2</ID>
<Name>B</Name>
</Item>
<Item>
<ID>5</ID>
<Name>E</Name>
</Item>
</Region>
<Region Name="Småland">
<Item>
<ID>1</ID>
<Name>A</Name>
</Item>
</Region>
</Country>
<Country Name="USA">
<Region Name="Alaska">
<Item>
<ID>3</ID>
<Name>C</Name>
</Item>
</Region>
<Region Name="Texas">
<Item>
<ID>4</ID>
<Name>D</Name>
</Item>
</Region>
</Country>
</Items>
EDIT:
I also want to make sure regions end up in their own country, even if there are duplicates. I edited the answer accordingly.
Also, I'd like to hint about xsltfiddle.liberty-development.net as an easy way of doing trial-and-error XSLT development...
Inspired by this article, I found a neat solution to this problem:
I have included comments for using it for single or double grouping, see comments in the code. Notice how I use first key (index) as input to the secon for-each loop:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="country" match="Item" use="Country" />
<xsl:key name="region" match="Item" use="concat(Region, '|', Country)" />
<xsl:template match="/Items">
<Items>
<xsl:for-each select="Item[generate-id(.) = generate-id(key('country', Country))]">
<xsl:sort select="Country" />
<xsl:variable name="_country" select="Country" />
<xsl:element name="Country">
<xsl:attribute name="Name"><xsl:value-of select="$_country" /></xsl:attribute>
<!-- single level grouping -->
<!--<xsl:apply-templates select="key('country', Country)" />-->
<!-- double grouping -->
<!-- START -->
<xsl:for-each select="key('country', Country)[generate-id(.) = generate-id(key('region', concat(Region, '|', Country)))]">
<xsl:sort select="Region" />
<xsl:variable name="_region" select="Region" />
<xsl:element name="Region">
<xsl:attribute name="Name"><xsl:value-of select="$_region" /></xsl:attribute>
<xsl:apply-templates select="key('region', concat(Region, '|', Country))" />
</xsl:element>
</xsl:for-each>
<!-- END -->
</xsl:element>
</xsl:for-each>
</Items>
</xsl:template>
<xsl:template match="Item">
<xsl:element name="Item">
<xsl:element name="ID"><xsl:value-of select="ID" /></xsl:element>
<xsl:element name="Name"><xsl:value-of select="Name" /></xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

replace XML variable in sql [duplicate]

This question already has answers here:
Updating SQL Server XML node
(2 answers)
Closed 4 years ago.
How do I replace the variable value of xml in sql? I need to change the values of ID and Text.
Sample XML
<Values>
<ValueList>
<Entry key="Num" type="Values">
<value ID="1" Text="One" />
</Entry>
<Entry key="Name" type="Values">
<value ID="2" Text="two" />
</Entry>
</ValueList>
</Values>
You can modified the ID value like following. Here I am updating ID="1" to "111", similarly you can change the text for a specific text using modify.
DECLARE #XML XML
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq ("1")]/#ID)[1] with ("1111")')
select #XML
If you want to use variables, it can be achieved like following.
DECLARE #XML XML
Declare #IDTOReplace VARCHAR(5)='1'
DECLARE #IDWithReplace VARCHAR(5) = '111'
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq sql:variable("#IDTOReplace")]/#ID)[1] with sql:variable("#IDWithReplace")')
select #XML
If you want to change the Text based on some Id, it can be achieved like following.
DECLARE #XML XML
Declare #IDTOReplace VARCHAR(5)='1'
DECLARE #TextToReplace VARCHAR(100) = 'NewText'
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq sql:variable("#IDTOReplace")]/#Text)[1] with sql:variable("#TextToReplace")')
select #XML

How to get SOAP response data?

This is the XML response back from webservice.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="urn:OrientalServices1">
<SOAP-ENV:Body>
<ns1:Get_CategoryResponse xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/">
<return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:responseGetCategoryByID[11]">
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">1</id>
<name xsi:type="xsd:string">國內</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">2</id>
<name xsi:type="xsd:string">財經</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">3</id>
<name xsi:type="xsd:string">社會</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">4</id>
<name xsi:type="xsd:string">國際</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">10</id>
<name xsi:type="xsd:string">龍門陣</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">11</id>
<name xsi:type="xsd:string">言論</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">6</id>
<name xsi:type="xsd:string">名家</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">8</id>
<name xsi:type="xsd:string">娛樂</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">5</id>
<name xsi:type="xsd:string">體育</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">7</id>
<name xsi:type="xsd:string">專題</name>
</item>
<item xsi:type="tns:responseGetCategoryByID">
<id xsi:type="xsd:int">9</id>
<name xsi:type="xsd:string">特輯</name>
</item>
</return>
</ns1:Get_CategoryResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In this XML, I got 11 items in an array. How can I deserialize it and get the item one by one?
You could use an XML parser.
There is support for a couple of methods in Cocoa - but since you've asked such a general question, all I can do is provide a general answer.
There is an Introduction to Event Driven XML Programming on the Apple Developer site

Extracting data from XML using OpenXML in SQL Server

I have a xml which I want it to be extracted using OpenXML within SQL Server
Here is the sample XML
<row>
<student_token>7</student_token>
<student_ssn>552</student_ssn>
<alternate_id>20</alternate_id>
<old_ssn xsi:nil="true" />
<alien_num xsi:nil="true" />
<last_name>A</last_name>
<first_name>B</first_name>
<middle_init xsi:nil="true" />
<drivers_license_num xsi:nil="true" />
<gpa_highschool xsi:nil="true" />
<created_dt>2006-07-13T11:15:08.320</created_dt>
<created_how>4</created_how>
<modified_dt>2008-02-14T00:00:00</modified_dt>
<modified_by>4</modified_by>
<primary_street2 xsi:nil="true" />
<primary_street3 xsi:nil="true" />
<primary_country xsi:nil="true" />
<email_address xsi:nil="true" />
<address_start_dt xsi:nil="true" />
<address_end_dt xsi:nil="true" />
<entrance_iv_dt xsi:nil="true" />
<entrance_iv_by xsi:nil="true" />
<exit_iv_dt>2006-11-02T00:00:00</exit_iv_dt>
<exit_iv_by>156</exit_iv_by>
<foreign_address_indicator>N</foreign_address_indicator>
<foreign_postal_code xsi:nil="true" />
<pin>J27841</pin>
<web_id>J08614 </web_id>
<prior_name xsi:nil="true" />
<orig_eps xsi:nil="true" />
<web_role>STU1</web_role>
<heal_limit_flag>N</heal_limit_flag>
<email_address_2>test#test.com</email_address_2>
<cellular_telephone>415</cellular_telephone>
<alt_loan_debt xsi:nil="true" />
<web_last_login xsi:nil="true" />
<foreign_country_code xsi:nil="true" />
<entrance_iv_dt_grad_plus xsi:nil="true" />
<entrance_iv_by_grad_plus xsi:nil="true" />
<failed_logins>0</failed_logins>
<hispanic xsi:nil="true" />
<race xsi:nil="true" />
<primary_phone_number_intl xsi:nil="true" />
<security_version>0</security_version>
<failed_challenge_response>0</failed_challenge_response>
<require_pin_reset xsi:nil="true" />
</row>
The query should extract into 3 fields for each row
FieldName
FieldValue
IsNull
For example the first row should be
FieldName = student_token - The node name would be the field name
FieldValue = 7
IsNull = false - IsNull is based on the attribute xsi:nil="true"
How can I do this?
Sample data with namespace added.
declare #xml xml
set #xml =
'<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<student_token>7</student_token>
<student_ssn>552</student_ssn>
<alternate_id>20</alternate_id>
<old_ssn xsi:nil="true" />
<alien_num xsi:nil="true" />
<last_name>A</last_name>
<first_name>B</first_name>
<middle_init xsi:nil="true" />
<drivers_license_num xsi:nil="true" />
<gpa_highschool xsi:nil="true" />
<created_dt>2006-07-13T11:15:08.320</created_dt>
<created_how>4</created_how>
<modified_dt>2008-02-14T00:00:00</modified_dt>
<modified_by>4</modified_by>
<primary_street2 xsi:nil="true" />
<primary_street3 xsi:nil="true" />
<primary_country xsi:nil="true" />
<email_address xsi:nil="true" />
<address_start_dt xsi:nil="true" />
<address_end_dt xsi:nil="true" />
<entrance_iv_dt xsi:nil="true" />
<entrance_iv_by xsi:nil="true" />
<exit_iv_dt>2006-11-02T00:00:00</exit_iv_dt>
<exit_iv_by>156</exit_iv_by>
<foreign_address_indicator>N</foreign_address_indicator>
<foreign_postal_code xsi:nil="true" />
<pin>J27841</pin>
<web_id>J08614 </web_id>
<prior_name xsi:nil="true" />
<orig_eps xsi:nil="true" />
<web_role>STU1</web_role>
<heal_limit_flag>N</heal_limit_flag>
<email_address_2>test#test.com</email_address_2>
<cellular_telephone>415</cellular_telephone>
<alt_loan_debt xsi:nil="true" />
<web_last_login xsi:nil="true" />
<foreign_country_code xsi:nil="true" />
<entrance_iv_dt_grad_plus xsi:nil="true" />
<entrance_iv_by_grad_plus xsi:nil="true" />
<failed_logins>0</failed_logins>
<hispanic xsi:nil="true" />
<race xsi:nil="true" />
<primary_phone_number_intl xsi:nil="true" />
<security_version>0</security_version>
<failed_challenge_response>0</failed_challenge_response>
<require_pin_reset xsi:nil="true" />
</row>'
Using openxml.
declare #idoc int
exec sp_xml_preparedocument #idoc out, #xml, '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>'
select FieldName,
FieldValue,
isnull([IsNull], 0)
from openxml(#idoc, '/row/*',1)
with (
FieldName varchar(50) '#mp:localname',
FieldValue varchar(50) '.',
[IsNull] bit '#xsi:nil'
)
exec sp_xml_removedocument #idoc
Using the XML data type:
;with xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' as ns)
select T.N.value('local-name(.)', 'varchar(50)') as FieldName,
T.N.value('.', 'varchar(50)') as FieldValue,
isnull(T.N.value('#ns:nil', 'bit'), 0) as [IsNull]
from #xml.nodes('/row/*') as T(N)
Not sure if you have that XML as a SQL variable or inside a table - question is very unclear .....
If you have it as an SQL variable, then try something like this (note: you must declare the xsi prefix somehow - otherwise SQL Server's XML processor won't even look at your XML document):
DECLARE #input XML = '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<student_token>7</student_token>
<student_ssn>552</student_ssn>
<alternate_id>20</alternate_id>
<old_ssn xsi:nil="true" />
.........
</row>'
;WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT
FieldName = T.C.value('local-name(.)', 'varchar(50)'),
FieldValue = T.C.value('(.)[1]', 'varchar(500)'),
IsNIL = ISNULL(T.C.value('(#xsi:nil)[1]', 'bit'), 0)
FROM
#Input.nodes('/row/*') AS T(C)
This gives me an output something like:
FieldName FieldValue IsNIL
student_token 7 0
student_ssn 552 0
alternate_id 20 0
old_ssn 1
.....
Of course, all output is going to be of type varchar(500) now in the FieldValue column....
Updated my answer, based on Mikael Eriksson's answer, to include the IsNIL handling, too. Thanks Mikael for the inspiration! You deserve the nod and the accept vote!
You can convert your xml file to json and then use OPENJSON instead. Take a look at openjson : SELECT star on how to use OPENJSON without having to list column names.
To convert an xml file to json you can use sp_execute_external_script and the xmltodict python module.
Take a look at Importing Python Libraries to SQL Server to import the python module and deal with YAPI (Yet Another Python Install) issues.