The XML parse error in MSSQL 2008R2 - sql-server

This is xml file:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.fleettracker.de/api/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:GetPositionsResponse>
<body>
<result>Found 1 vessels.</result>
<success>true</success>
<shipsWithPositions xsi:type="ns1:FleettrackerShip">
<ns1:imono>9456159</ns1:imono>
<ns1:sid>780</ns1:sid>
<ns1:name>Trenta</ns1:name>
<ns1:charterShipName>Trenta</ns1:charterShipName>
<ns1:pasttrack>
<lat>1832900</lat>
<lon>7570400</lon>
<timestamp>2014-01-14T08:28:45Z</timestamp>
<orderNumber>0</orderNumber>
<sog>9.5</sog>
<cog>22</cog>
<hdg>22</hdg>
<eta>2014-01-15T12:00:00</eta>
<nextport>KWANGYANG</nextport>
</ns1:pasttrack>
<ns1:pasttrack>
<lat>1224000</lat>
<lon>7188500</lon>
<timestamp>2014-01-11T08:07:45Z</timestamp>
<orderNumber>9</orderNumber>
<sog>7</sog>
<cog>39</cog>
<hdg>39</hdg>
<eta>2014-01-15T08:00:00</eta>
<nextport>KWANGYANG</nextport>
</ns1:pasttrack>
</shipsWithPositions>
</body>
</ns1:GetPositionsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And this is MsSql query:
EXEC sp_xml_preparedocument #idoc OUTPUT, #XML,'<root xmlns:ns1="http://www.fleettracker.de/api/1.0">'
--select #idoc
insert into Position (ImoNo, sid, VesselName, time, lat, lon, sog, cog, hdg, eta, NextPort)
SELECT *
FROM OPENXML (#idoc, '/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:GetPositionsResponse/body/shipsWithPositions', 2)
WITH (ImoNo numeric(8, 0) 'ns1:imono',
sid numeric(5, 0) 'ns1:sid',
VesselName nvarchar(20) 'ns1:name',
time datetime 'ns1:pasttrack/timestamp',
lat numeric(9, 2) 'ns1:pasttrack/lat',
lon numeric(9, 2) 'ns1:pasttrack/lon',
sog numeric(9, 2) 'ns1:pasttrack/sog',
cog numeric(9, 2) 'ns1:pasttrack/cog',
hdg numeric(9, 2) 'ns1:pasttrack/hdg',
eta datetime 'ns1:pasttrack/eta',
NextPort nvarchar(20) 'ns1:pasttrack/nextport'
);
EXEC sp_xml_removedocument #idoc
Does somebody knows why I am getting the XML parse error?!
-------------------------------------------------------------
-------------------------------------------------------------

The problem is the type of the #XML variable.
As the file header decalres 'UTF-8' coding, the document must be inside a varchar() variable:
declare #XML varchar(max) = 'your UTF-8 document'
If you decalre it as nvarchar(max) 'UTF-8' coding is not valid.
declare #XML nvarchar(max) = 'your UTF-8 document' -- This cannot be parsed!

Related

Apple Health XML to SQL Server

I want to process XML data I've imported from exported Apple Health XML file.
The XML data is stored in an import table and I'm trying to use sp_xml_preparedocument to prepare the document and query the data.
The approach described below worked for another part of the XML file, specifically activity summary. Now I receive the following error:
Msg 6603, Level 16, State 2, Line 23
XML parsing error: NodeTest expected here.
#-->[<--type]
The examples given by Microsoft in their documentation seems to be working on a differently structured data, so not sure how or if I could adapt one of their examples to my needs.
I have tried the following:
DECLARE #XML AS XML;
DECLARE #hDoc AS INT;
SELECT #XML = XMLData FROM [Data].AppleImport;
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT [type],
sourceName,
sourceVersion,
unit,
creationDate,
startDate,
endDate,
[value]
FROM OPENXML(#hDoc, 'HealthData/Record')
WITH
(
[type] NVARCHAR(50) '#[type]',
sourceName NVARCHAR(50) '#sourceName',
sourceVersion NVARCHAR(50) '#sourceVersion',
unit NVARCHAR(50) '#unit',
creationDate NVARCHAR(50) '#creationDate',
startDate NVARCHAR(50) '#startDate',
endDate NVARCHAR(50) '#endDate',
[value] NVARCHAR(50) '#[value]'
)
EXEC sp_xml_removedocument #hDoc;
The XML Data structure (extracted parts for brewity):
<HealthData locale="nb_NO">
<ExportDate value="2020-09-03 12:10:19 +0200"/>
<Me HKCharacteristicTypeIdentifierDateOfBirth="1988-01-01" HKCharacteristicTypeIdentifierBiologicalSex="HKBiologicalSexMale" HKCharacteristicTypeIdentifierBloodType="HKBloodTypeNotSet" HKCharacteristicTypeIdentifierFitzpatrickSkinType="HKFitzpatrickSkinTypeNotSet"/>
<Record type="HKQuantityTypeIdentifierHeight" sourceName="amsten sin iPhone" sourceVersion="13.0" unit="cm" creationDate="2019-09-23 15:19:48 +0200" startDate="2019-09-23 15:19:48 +0200" endDate="2019-09-23 15:19:48 +0200" value="188"/>
<Record type="HKQuantityTypeIdentifierHeight" sourceName="Helse" sourceVersion="11.4.1" unit="cm" creationDate="2018-07-31 21:42:50 +0200" startDate="2018-07-31 21:42:50 +0200" endDate="2018-07-31 21:42:50 +0200" value="188"/>
<MetadataEntry key="HKWasUserEntered" value="1"/>
</Record>
<Record type="HKQuantityTypeIdentifierHeartRate" sourceName="amsten sin Apple Watch" sourceVersion="5.3.1" device="<<HKDevice: 0x2834d03c0>, name:Apple Watch, manufacturer:Apple Inc., model:Watch, hardware:Watch4,4, software:5.3.1>" unit="count/min" creationDate="2019-09-15 06:38:32 +0200" startDate="2019-09-15 06:30:08 +0200" endDate="2019-09-15 06:30:08 +0200" value="49">
<MetadataEntry key="HKMetadataKeyHeartRateMotionContext" value="1"/>
</Record>
</HealthData>
Any input on how to proceede or good reading materials are most appreciated.
When using valid XML also try using the following OPENXML statement:
SELECT [type],
sourceName,
sourceVersion,
unit,
creationDate,
startDate,
endDate,
[value]
FROM OPENXML(#hDoc, 'HealthData/Record')
WITH
(
[type] NVARCHAR(50) '#type',
sourceName NVARCHAR(50) '#sourceName',
sourceVersion NVARCHAR(50) '#sourceVersion',
unit NVARCHAR(50) '#unit',
creationDate NVARCHAR(50) '#creationDate',
startDate NVARCHAR(50) '#startDate',
endDate NVARCHAR(50) '#endDate',
[value] NVARCHAR(50) '#value'
)
Note that '#[type]' and '#[value]' have changed to '#type' and '#value'.

T-SQL parse XML data into single line

I have XML saved into a column in a table as type nvarchar. Now I need to parse data from that xml. I do
SELECT
CONVERT(XML, columnX).value('(chatTranscript/message/msgText/text())[1]', 'nvarchar(max)')
as chat but I get only first value. How do I extract all into single line? XML can be long, depends on chat length.
I need to get userNick and then msgText and loop it till the end. Something like this:
userX:Hello<>userY:How are you;
XML:
<?xml version="1.0"?>
<chatTranscript startAt="2020-07-30T11:00:12Z" sessionId="......">
<newParty userId="......" timeShift="0" visibility="ALL" eventId="1">
<userInfo personId="" userNick="userX"/>
</newParty>
<message userId="..." timeShift="12" visibility="ALL" eventId="9">
<msgText msgType="text">Hello</msgText>
</message>
<newParty userId="..." timeShift="15" visibility="ALL" eventId="10">
<userInfo userNick="userY"/>
</newParty>
<message userId="..." timeShift="29" visibility="ALL" eventId="12">
<msgText treatAs="NORMAL">how are you?</msgText>
</message>
<partyLeft userId="..." timeShift="36" visibility="ALL" eventId="13" askerId="...">
<reason code="1">left with request to close if no agents</reason>
</partyLeft>
<partyLeft userId="..." timeShift="36" visibility="ALL" eventId="14" askerId="...">
<reason code="4">removed by other party</reason>
</partyLeft>
</chatTranscript>
You need code to do this cleanly. Trying to do what you are asking will be super messy T-SQL. I'd recommend parsing the xml in code to generate what you want based on that xml. You could also create a CLR function using code so that you can create a SQL function to do this. You can do some amazing things with XQuery and T-SQL, but sometimes it just gets to messy. For xml manipulation all within the database, CLR functions are perfect.
Here is my solution:
ALTER FUNCTION [dbo].[fn_parse_chat_xml] (#xml XML)
RETURNS NVARCHAR(MAX)
BEGIN
DECLARE #n INT, #content NVARCHAR(MAX), #userId NVARCHAR(200), #userNick1 NVARCHAR(200), #userNick2 NVARCHAR(200), #userNickX NVARCHAR(200)
SET #n = 1
SET #userId = #xml.value('(chatTranscript/newParty/#userId)[1]', 'nvarchar(max)')
SET #userNick1 = #xml.value('(chatTranscript/newParty/userInfo/#userNick)[1]', 'nvarchar(max)')
SET #userNick2 = #xml.value('(chatTranscript/newParty/userInfo/#userNick)[2]', 'nvarchar(max)')
WHILE DATALENGTH(#xml.value('(chatTranscript/message/msgText/text())[sql:variable("#n")][1]', 'nvarchar(max)'))>0
BEGIN
IF #userId = #xml.value('(chatTranscript/message/#userId)[sql:variable("#n")][1]', 'nvarchar(max)')
SET #userNickX = #userNick1
else
SET #userNickX = #userNick2
SET #content = concat(#content, ' <> ', #userNickX, ': ', #xml.value('(chatTranscript/message/msgText/text())[sql:variable("#n")][1]', 'nvarchar(max)'))
SET #n = #n + 1
END
RETURN #content
END

SQL Server and XML Utilization

I'm trying to utilize XML with SQL Server. All I'm trying to do is print out all three guests. When I run my code, it only shows the prints the first guest's information, and I need all three guest's information to be printed. What am I doing wrong?
SELECT Guest.GuestID, GuestFirst, GuestLast, CheckinDate, Nights
FROM GUEST
JOIN FOLIO
ON Guest.GuestID = Folio.GuestID
FOR XML RAW
Declare #idoc int
Declare #xmldoc nvarchar(4000)
Set #xmldoc = '
<ROOT>
<GUEST>
<GuestID>4431</GuestID>
<GuestFirst>Lacey</GuestFirst>
<GuestLast>Byington</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-02</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>5563</GuestID>
<GuestFirst>Jonathan</GuestFirst>
<GuestLast>Langford</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-05</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>6680</GuestID>
<GuestFirst>Tanner</GuestFirst>
<GuestLast>Olson</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2015-09-11</CheckInDate>
<Nights>3</Nights>
</RESERVATIONDETAIL>
</GUEST>
</ROOT>'
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmldoc
SELECT * FROM OPENXML (#idoc, '/ROOT', 3)
WITH
(
GuestID smallint 'GUEST/GuestID',
GuestFirst varchar(30) 'GUEST/GuestFirst',
GuestLast varchar(30) 'GUEST/GuestLast',
CheckinDate smalldatetime 'GUEST/RESERVATIONDETAIL/CheckInDate',
Nights tinyint 'GUEST/RESERVATIONDETAIL/Nights'
)
EXEC sp_xml_removedocument #idoc
GO
Instead xml document try it with xquery,
DECLARE #xmldoc XML
Set #xmldoc = '
<ROOT>
<GUEST>
<GuestID>4431</GuestID>
<GuestFirst>Lacey</GuestFirst>
<GuestLast>Byington</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-02</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>5563</GuestID>
<GuestFirst>Jonathan</GuestFirst>
<GuestLast>Langford</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-05</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>6680</GuestID>
<GuestFirst>Tanner</GuestFirst>
<GuestLast>Olson</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2015-09-11</CheckInDate>
<Nights>3</Nights>
</RESERVATIONDETAIL>
</GUEST>
</ROOT>'
SELECT
a.b.value('GuestID[1]','smallint') AS GuestID,
a.b.value('GuestFirst[1]','varchar(30)') AS GuestFirst,
a.b.value('GuestLast[1]','varchar(30)') AS GuestLast,
a.b.value('RESERVATIONDETAIL[1]/CheckInDate[1]','smalldatetime') AS CheckInDate,
a.b.value('RESERVATIONDETAIL[1]/Nights[1]','tinyint') AS Nights
FROM #xmldoc.nodes('ROOT/GUEST') AS a(b)
GO
btw, the select query you have given on the top will not produce the same xml which you have given below.
#Jatin answer is good, you can use xquery. You can also use OPENXML like this:
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmldoc
SELECT * FROM OPENXML (#idoc, '/ROOT/GUEST', 3)
WITH
(
GuestID smallint './GuestID',
GuestFirst varchar(30) './GuestFirst',
GuestLast varchar(30) './GuestLast',
CheckinDate smalldatetime './RESERVATIONDETAIL/CheckInDate',
Nights tinyint './RESERVATIONDETAIL/Nights'
)
EXEC sp_xml_removedocument #idoc
You are almost there. You just need to make this small change:
SELECT * FROM OPENXML (#idoc, '/ROOT/*', 3)
WITH
(
GuestID smallint 'GuestID',
GuestFirst varchar(30) 'GuestFirst',
GuestLast varchar(30) 'GuestLast',
CheckinDate smalldatetime 'RESERVATIONDETAIL/CheckInDate',
Nights tinyint 'RESERVATIONDETAIL/Nights'
)

USE Open XML to extract the CDATA

I have xml which has the data embedded in CDATA. I would like to extract the info in different fields. But not able to do it.
<Item_Response Format="text/xml">
<![CDATA[ <Item sequence="1" type="item" itemId="999999"
itemVersion="2012-04-07T13:43:27">
<response><bubbleinput answered="y" input_id="bubbleinput1">
<bubble id="bubble1"/>
</bubbleinput></response></Item> ]]>
</Item_Response>
You can extract CDATA value with XPath. Then use openxml on extracted value.
declare #xml xml = '<Item_Response Format="text/xml"><![CDATA[ <Item sequence="1" type="item" itemId="999999" itemVersion="2012-04-07T13:43:27"><response><bubbleinput answered="y" input_id="bubbleinput1"><bubble id="bubble1"/></bubbleinput></response></Item> ]]></Item_Response>'
-- openxml
declare
#idoc int,
#qxml xml = cast(#xml.value('(/Item_Response)[1]', 'nvarchar(max)') as xml)
exec sp_xml_preparedocument #idoc output, #qxml
select
*
from
openxml(#idoc, '/Item', 0) with (
sequence int '#sequence',
bubbleinput nvarchar(1) './response/bubbleinput/#answered'
) as XMLData
exec sp_xml_removedocument #idoc

How to parse xml in sql server to process NULL value in DateTime DataType

I have created a sample query in sql server to parse data from xml and to display it right now.
Although I will be inserting this data in my table but before that I am facing a simple problem.
I want to insert NULL in datetime field ADDED_DATE="NULL" as shown in xml given below. But when I executes this query. It gives me error
Conversion failed when converting datetime from character string.
What mistake am i doing. Please highlight my mistake.
declare #xml varchar(1000)
set #xml= '
<ROOT>
<TX_MAP FK_GUEST_ID="1" FK_CATEGORY_ID="2" ATTRIBUTE="Test" DESCRIPTION="TestDesc" IS_ACTIVE="1" ADDED_BY="NULL" ADDED_DATE="NULL" MODIFIED_BY="NULL" MODIFIED_DATE="NULL"></TX_MAP>
<TX_MAP FK_GUEST_ID="2" FK_CATEGORY_ID="1" ATTRIBUTE="Test2" DESCRIPTION="TestDesc2" IS_ACTIVE="1" ADDED_BY="NULL" ADDED_DATE="NULL" MODIFIED_BY="NULL" MODIFIED_DATE="NULL"></TX_MAP>
</ROOT> '
declare #handle int
exec sp_xml_preparedocument #handle output, #xml
select * from OPENXML(#handle,'/ROOT/TX_MAP',1)
with
(
FK_GUEST_ID INT
,FK_CATEGORY_ID VARCHAR(10)
,ATTRIBUTE VARCHAR(100)
,[DESCRIPTION] VARCHAR(100)
,IS_ACTIVE VARCHAR(10)
,ADDED_BY VARCHAR(100)
,ADDED_DATE DATETIME NULL
,MODIFIED_BY VARCHAR(100)
,MODIFIED_DATE DATETIME NULL
)
I am using Sql Server 2005.
After googling an hour, I got answer to my question and would like to share with you all so that for future users it become easy.
declare #xml varchar(1000)
set #xml= '
<ROOT>
<TX_MAP FK_GUEST_ID="1" FK_CATEGORY_ID="2" ATTRIBUTE="Test" DESCRIPTION="TestDesc" IS_ACTIVE="1" ADDED_BY="NULL" ADDED_DATE="12/3/2010" MODIFIED_BY="NULL" MODIFIED_DATE="12/3/2010"></TX_MAP>
<TX_MAP FK_GUEST_ID="2" FK_CATEGORY_ID="1" ATTRIBUTE="Test2" DESCRIPTION="TestDesc2" IS_ACTIVE="1" ></TX_MAP>
</ROOT> '
declare #handle int
exec sp_xml_preparedocument #handle output, #xml
select * from OPENXML(#handle,'/ROOT/TX_MAP',1)
with
(
FK_GUEST_ID INT
,FK_CATEGORY_ID VARCHAR(10)
,ATTRIBUTE VARCHAR(100)
,[DESCRIPTION] VARCHAR(100)
,IS_ACTIVE VARCHAR(10)
,ADDED_BY VARCHAR(100)
,ADDED_DATE DATETIME
,MODIFIED_BY VARCHAR(100)
,MODIFIED_DATE DATETIME
)
What you need to do is just to omit
those attributes that will result into
NULL value.
An XML element can be set to null like:
<ADDED_DATE xsi:nil="true"/>
I can't find a way to set an attribute to null though. Perhaps the only way is to omit it?

Resources