Avoid encoding of ampersand in SQL XML attribute - sql

Image I have a currency table, containing e.g. this record :
- Id = 1
- Code = EUR
- Symbol = €
Important to notice :
The input in our database is already property HTML-encoded!
Now, when I use this SQL statement :
SELECT '#id' = Currency.Id
, '#code' = Currency.Code
, '#symbol' = Currency.Symbol
FROM Currency
FOR XML PATH('currency')
, ROOT('list')
, TYPE
;
...it unfortunately results into the following XML :
<list><currency id="1" code="EUR" symbol="&euro;" /></list>
Notice that the Euro-symbol has been re-encoded, rendering it invalid.
How can I avoid that? How can I obtain the following XML output :
<list><currency id="1" code="EUR" symbol="€" /></list>

The result you get unfortunately and is re-encoded and invalid is perfectly correct - but not what you expect. You pass in € which is a string. Within XML this is escaped as &euro; and will be re-coded to €.
You must stop to think of XML as kind of formalized string. This is a technical issue. XML will handle this implicitly.
There are two ways:
Go the string-way and cast your XML to NVARCHAR, do any string manipulation you might want (e.g. REPLACE(myXML,'&euro;','€') and cast back to XML or
(I'd prefer this!) hand in the € as actual symbol and let the XML engine do the encoding.
EDIT
One more thing: SQL Server doesn't know the € entity. Try with € or €:
SELECT '€' AS [#EuroSign] --works
,'€' AS [#NamedEscapedEuro] --will be encoded
,'€' AS [#EscapedEuro] --will be encoded
FOR XML PATH('TestEuro'),ROOT('root')
SELECT --CAST('<x>'+'€'+'</x>' AS XML).value('/x[1]','nvarchar(10)') AS [#EuroSign] --not allowed!!!
--CAST('<x>'+'€'+'</x>' AS XML).value('/x[1]','nvarchar(10)') AS [#NamedEscapedEuro] --not allowed, exists, but not known in SQL Server!
CAST('<x>'+'€'+'</x>' AS XML).value('/x[1]','nvarchar(10)') AS [#EscapedEuro] --works
FOR XML PATH('TestEuro'),ROOT('root')

Related

Finding every instance of XML Element in SQL output

I'm a beginner when it comes to SQL and have no experience with XML so I'm after a little bit of help.
At the moment I am looking at a single table and just using the query below
select
name,
convert(xml, convert(varbinary(max), orders)) ClientOrders
from client;
In the second columns of SQL output, I have a very lengthy bit of XML similar to the example below. I've used "..." just to skip over some of the output and give a general idea.
Name
ClientOrders
Client1
<report ... ><QueryParameter></QueryParameter Name = "#hello1"><commandtext> ...<value>Example1</value>....<value>Example2</value>...<value>Example3</value>...</commandtext></report>
Client2
<report ... ><QueryParameter></QueryParameter Name = "#hello2"><commandtext> ...<value>Example4</value>....<value>Example5</value>...<value>Example6</value>...</commandtext></report>
I have this for a lot of rows and this output is so long that it exceeds the Excel cell character limit. I'm only looking for the values Example1 through to Example6 in the example given above. Is there an SQL command I can run to get the above string between the open and close value?
I am using SSMS version 18.9.1
Cheers

Sum of values extracted using SQL

I have an xml like the below.
<LPNDetail>
<ItemName>5054807025389</ItemName>
<DistroNbr/>
<DistributionNbr>TR001000002514</DistributionNbr>
<OrderLine>2</OrderLine>
<RefField2/>
<RefField3>OU01180705</RefField3>
<RefField4>0002</RefField4>
<RefField5>Retail</RefField5>
<Qty>4</Qty>
<QtyUom>Unit</QtyUom>
</LPNDetail>
<LPNDetail>
<ItemName>5054807025563</ItemName>
<DistroNbr/>
<DistributionNbr>TR001000002514</DistributionNbr>
<OrderLine>4</OrderLine>
<RefField2/>
<RefField3>OU01180705</RefField3>
<RefField4>0004</RefField4>
<RefField5>Retail</RefField5>
<Qty>2</Qty>
<QtyUom>Unit</QtyUom>
</LPNDetail>
I have extracted the xml field using extract.xmltype and now i am getting the below result.
42
But i need to sum the quantity values i.e i need to get result as 6 (4+2).
Any help will be appreciated.
Thanks,
Shihaj
It is not clear what you mean by "an xml". If it's supposed to be an XML document, you are missing the outermost tags, perhaps something like <Document> ..... </Document>
If your text value is EXACTLY as you have shown it (which would be pretty bad), you can wrap within such outermost tags manually, and then use standard Oracle XML tools. For the illustration below I assume you simply have a string (VARCHAR2 or CLOB), not converted to XML type; in that case, I concatenate the beginning and end tags, and then convert to XMLtype, in the query.
with t ( str ) as (
select '<LPNDetail>
<ItemName>5054807025389</ItemName>
<DistroNbr/>
<DistributionNbr>TR001000002514</DistributionNbr>
<OrderLine>2</OrderLine>
<RefField2/>
<RefField3>OU01180705</RefField3>
<RefField4>0002</RefField4>
<RefField5>Retail</RefField5>
<Qty>4</Qty>
<QtyUom>Unit</QtyUom>
</LPNDetail>
<LPNDetail>
<ItemName>5054807025563</ItemName>
<DistroNbr/>
<DistributionNbr>TR001000002514</DistributionNbr>
<OrderLine>4</OrderLine>
<RefField2/>
<RefField3>OU01180705</RefField3>
<RefField4>0004</RefField4>
<RefField5>Retail</RefField5>
<Qty>2</Qty>
<QtyUom>Unit</QtyUom>
</LPNDetail>'
from dual
)
-- End of SIMULATED table (for testing purposes only, not part of the solution)
-- Query begins below this line
select sum(x.qty) as total_quantity
from t,
xmltable('/Document/LPNDetail'
passing xmltype('<Document>' || t.str || '</Document>')
columns qty number path 'Qty') x
;
Output:
TOTAL_QUANTITY
--------------
6

Parse XML field into table

I am trying to parse an XML field using SQL into a table and I need a little help starting. An example of the XML field for one row is as follows:
<MarketValueTransactionVo
objectId="104" statusCode="0" acctNum="60835733" recType="6"
errorFlag="N" sourceCode="0" userId="DATAEXCHANGE" taxItem="0"
amount="4496.79" accountEntityType="0" transactionAmount="4496.79"
importFormatType="5" dateEntered="01252015" clearingFirmBrokerCode="OPSX"
formattedAmount="$4,496.79" totalShares="0" controlNumberSequence="0"
applicableYear="2014" brokerCode="OPSX" ssn="632248334"
entityId="OPSX" entityTypeCode="4" activityApplicationCode="3001"
activityTypeCode="801" entityPresentationNumber="0" checkStatusCode="0"
correctionCode="0" correctionTypeCode="0" entityLOBCode="0"
requestPresentationNumber="0" requestStatusCode="0" reverseReasonCode="0"
loanPresentationNumber="0">
</MarketValueTransactionVo>
You want to address XML tag attributes. Tag attributes can be addressed using at-sign symbol #, see for examples Import XML with Attribute to SQL Server Table and Convert Xml to Table SQL Server (the second format in the answer):
SELECT
Tbl.Col.value('#objectId', 'int'),
Tbl.Col.value('#statusCode', 'tinyint'),
Tbl.Col.value('#acctNum', ...proper type int? varchar(xx)? ),
...
FROM #xml.nodes('//MarketValueTransactionVo') Tbl(Col)

Using Fields[0].Value to get XML from FOR XML RAW, ELEMENTS query is messed up

I have a query that uses FOR XML RAW, ELEMENTS to return a SELECT query as a structured XML document. However, when I get the result using a TSQLDataSet by using Fields[0].Value, the result is different from what I see when I run the query in SQL Server Management Studio.
What I see in the result from the TSQLDataSet:
੄customerIdфname၄governmentNumberไdebtorAddress1ไdebtorAddress2ไdebtorAddress3ไdebtorAddress4ࡄpostCodeୄcontactNameՄphonë́faxൄcustomerSinceՄtermsلactiveไcurrentBalanceلDebtorခŁ䄁ഃӤ
What I see in the result in SSMS:
<Debtor>
<customerId>C0E449E5B2C </customerId>
<name>New Customer 2 </name>
<governmentNumber> </governmentNumber>
<debtorAddress1>Address Line 1 </debtorAddress1>
<debtorAddress4>Address Line 4 </debtorAddress4>
<postCode>1234 </postCode>
<phone>1234567890 </phone>
<fax>1234567890 </fax>
<customerSince>2013-06-10T18:16:06.213</customerSince>
<terms>M </terms>
<active>true</active>
<currentBalance>0.0000</currentBalance>
</Debtor>
Is there a particular way it should be executed to get the right result?
AFAIK this is a DbExpress limitation. I know how overcome this, but using ADO (the returned data must be requested using a special parametrized object and a set of ADO streams). However you can use a workaround converting the XML data to a string in the server side sorrounding the sentence with a select (subquery) or just using a simple CAST statement.
For example if you sentence is like so
SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS
you can rewrite to
SELECT (SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS)
or you can rewrite to (use a CAST VARCHAR or NVARCHAR)
SELECT CAST( (SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS) AS VARCHAR(MAX))
and finally
Retrieve the result like this
SQLDataSet1.Fields[0].AsString

How to use Xquery in Sql Server to search for character in column that stores XML data

There is column named FileImage that contains XML data.
<root>
<Image>
<File_image>02Jan12- Mfg--7.jpg</File_image>
<Page_no>7</Page_no>
<Logo>N</Logo>
</Image>
</root>
I want to search whether text between tags contains space character.
This is for checking invalid file name.
SELECT *
FROM mytable
where fileimage.exist('
/Image:file_image//text()
[contains(., " ")]') = 1
But error shown
XQuery [mytable.FileImage.exist()]: The name "Image" does not denote a namespace.
How to do this ? I am using SQL Server 2005.
SELECT *
FROM mytable
where fileimage.exist('
/root/Image/File_image//text()
[contains(., " ")]') = 1