Get a text field formated as xml body value - sql

I have a table where a column is stored in a xml format so it is possible do display it on other projects with formatted text.
But I need to convert it to a single line without tags.
I have tried to use value() method and nodes(), but didn't quite managed to make it work...
This is the example of the content of the column i want to format.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style> </head> <body> <p>VALUE I WANT TO GET </p> </body> </html>
SELECT Id, Description, Value FROM MyTable
Where Value is the column with stored xml..
Is there a way to get the body content without any tags in a single line?
THE COLUMN IS NOT XML TYPE BUT VARCHAR(MAX) TYPE

If your HTML value always same format, please try following scripts together:
Converting HTML into supported format for querying with value () and node()
Declare #x nvarchar (4000) = '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style> </head> <body> <p>VALUE I WANT TO GET </p> </body> </html>'
select #x = replace (#x,
'<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ',
''
);
SELECT #x = REPLACE(#x, 'xmlns=', 'xmlns:i=');
--Print #x;
Actual select query on converted XML
select xmldata,
Cast (x2.c.query('data(body/p)') as nvarchar (100)) as HtmlBody
From
(select convert (xml, #x ) as xmldata) as x
cross apply xmldata.nodes('html') as x2(c)
Additional:
Querying direct table, hope this would work if you replace #temp with your table name and column names accordingly
Declare #Temp table (ID bigint, xmlvalue nvarchar(4000) );
Declare #x nvarchar (4000) = '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style> </head> <body> <p>VALUE I WANT TO GET </p> </body> </html>';
Insert into #Temp
VALUES (101, #x);
select x.*,
Cast (x2.c.query('data(body/p)') as nvarchar (100)) as HtmlBody
From (
select ID, CAST(REPLACE(
(replace (xmlvalue,
'<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ',
'') ),
'xmlns=',
'xmlns:i='
) AS xml) as xmldata
from #Temp
) as x
CROSS APPLY xmldata.nodes('html') as x2(c)
go
If you think it's difficult to manager in future, create scalar function with same logic - Consider recommendations in terms of performance when using custom scalar functions

You can do something similar to this:
Language is VB.Net.
Dim XMLDoc As New XmlDocument
Dim dt As DataTable = GetData() <-- GetData() is where you load the data using your query
XMLDoc.Load(dt.Rows(0).Item("Value").ToString)
Dim TextThatIWant As string = XMLDoc.SelectSingleNode("/html/body/p").InnerText

Try it like this:
DECLARE #YourValue VARCHAR(MAX)=
'<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style> </head> <body> <p>VALUE I WANT TO GET </p> </body> </html>';
WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/1999/xhtml')
SELECT CONVERT(xml,#YourValue,2).value('(/html/body/p/text())[1]','varchar(1000)');
The idea in short:
We can not CAST() the string to XML, due to the <!DOCTYPE>, but we can use CONVERT() with the parameter 2. This will return your string as XML.
Against the XML we can use .value()
As your XML declares a default namespace we declare this namespace using WITH XMLNAMESPACES
Attention: HTML is far not as strict as XML. If you cannot be sure, that your HTML is XHTML actually (which means, that it follows the much stricter rules of XML), it can be dangerous to rely on XML methods. Luckily the namespace points to xhtml...
If not, this might work in all your tests, but break in production at any time...

Related

Mustache is throwing an error about the null value

I have a following Kotlin object type with default null value for a field:
data class Field(
val content: String? = null,
val field: String = ""
)
Then I try to pass the object:
val myObject = Field(field = "something")
to the mustache template:
<!DOCTYPE ...>
<html>
<head>
<meta .../>
</head>
<body ...">
{{#myObject}}
{{#content}}
{{.}}<br/>
{{/content}}
{{#field}}
{{.}}<br/>
{{/field}}
{{/myObject}}
</body>
</html>
And after filling the template I receive an exception: No key, method or field with name 'content' on line ...
I cannot get what can be wrong
may be you should define the "" for the content default for the problem?

inverse result of query_to_xml() PostgreSQL?

I am using a servlet(servlet1) via a GET method from httpurlconnection() function in order to get the XML generated by an another servlet(servlet2) connected to a postgreSQL Database.
The XML generated by the servlet2 via the statement:
select query_to_xml('select * from test', true, false, '');
I initialize an httpurlconnection() from servlet1 to servlet2 and I stored in a string "response1" the output like that:
String inputLine;
StringBuffer response1 = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response1.append(inputLine);
}
in.close();
//The output in console
System.out.println(response1.toString());
The XML is stored in the string "response1" as:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="/pro/inc/form.css;jsessionid=D965FA3338EC4E88F6F7AA0B64308446" />
</head>
<body>
<p><alltests_00_with_defects xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<n5>a</n5>
<n4>b</n4>
<n3>c</n3>
<n2>d</n2>
<n1>e</n1>
<row>
<row>
<n5>a</n5>
<n4>b</n4>
<n3>c</n3>
<n2>d</n2>
<n1>e</n1>
<row>
</html>
Until here, it's cool!!
Now, I am looking for a solution that can convert BACK the XML generated to data values.
Any ideas?

Insert xmltype into xmltype in specified place [PL/SQL]

I have problem with insert xmltype into another xmltype in specified place in pl/sql.
First variable v_xml has the form:
<ord>
<head>
<ord_code>123</ord_code>
<ord_date>01-01-2015</ord_date>
</head>
</ord>
And the second v_xml2:
<pos>
<pos_code>456</pos_code>
<pos_desc>description</pos_desc>
</pos>
My purpose is get something like this:
<ord>
<head>
<ord_code>123</ord_code>
<ord_date>01-01-2015</ord_date>
</head>
<!-- put the second variable in this place - after closing <head> tag -->
<pos>
<pos_code>456</pos_code>
<pos_desc>description</pos_desc>
</pos>
</ord>
What shoud I do with my code?
declare
v_xml xmltype;
v_xml2 xmltype;
begin
-- some code
-- some code
-- v_xml and v_xml2 has the form as I define above
end;
Is anyone able to help me with this problem? As I know there are functions like insertchildxml, appendchildxml or something like this...
I found few solution in pure SQL, but I don't know how to move this in PL/SQL.
Thanks!
You can use mentioned appendChildXML, like here:
declare
v_xml xmltype := xmltype('<ord>
<head>
<ord_code>123</ord_code>
<ord_date>01-01-2015</ord_date>
</head>
</ord>');
v_xml2 xmltype:= xmltype('<pos>
<pos_code>456</pos_code>
<pos_desc>description</pos_desc>
</pos>');
v_output xmltype;
begin
select appendChildXML(v_xml, 'ord', v_xml2)
into v_output from dual;
-- output result
dbms_output.put_line( substr( v_output.getclobval(), 1, 1000 ) );
end;
Output:
<ord>
<head>
<ord_code>123</ord_code>
<ord_date>01-01-2015</ord_date>
</head>
<pos>
<pos_code>456</pos_code>
<pos_desc>description</pos_desc>
</pos>
</ord>
appendChildXML is deprecated at 12.1
So here is a solution using XMLQuery
DECLARE
l_head_xml XMLTYPE := XMLTYPE.CREATEXML('<ord>
<head>
<ord_code>123</ord_code>
<ord_date>01-01-2015</ord_date>
</head>
</ord>');
l_pos_xml XMLTYPE := XMLTYPE.CREATEXML('<pos>
<pos_code>456</pos_code>
<pos_desc>description</pos_desc>
</pos>');
l_complete_xml XMLTYPE;
BEGIN
SELECT XMLQUERY('for $i in $h/ord/head
return <ord>
{$i}
{for $j in $p/pos
return $j}
</ord>'
PASSING l_head_xml AS "h",
l_pos_xml AS "p"
RETURNING CONTENT)
INTO l_complete_xml
FROM dual;
dbms_output.put_line(l_complete_xml.getstringval());
END;
Here is one solution using XMLQuery
DECLARE
l_src XMLTYPE:=XMLTYPE('<ord>
<head>
<ord_code>123</ord_code>
<ord_date>01-01-2015</ord_date>
</head>
</ord>');
l_dst XMLTYPE:=XMLTYPE('<pos>
<pos_code>456</pos_code>
<pos_desc>description</pos_desc>
</pos>');
l_final CLOB;
BEGIN
SELECT XMLQUERY('copy $tmp := $p1 modify
insert node $p2 as last into $tmp
return $tmp' PASSING l_src as "p1",l_dst as "p2" RETURNING CONTENT).getClobval() into l_final from dual;
DBMS_OUTPUT.PUT_LINE(l_final);
END;

Stored procedure not storing data in table

My problem is that when I execute my stored procedure, the XML data is not saved in my table. I do not receive any error code :((
My xml file:
if you have problem reading my xml file below click here to view it online (more understandable)
<?xml version="1.0"?>
<q:quakeml xmlns="http://quakeml.org/xmlns/bed/1.2" xmlns:catalog="http://anss.org/xmlns/catalog/0.1" xmlns:q="http://quakeml.org/xmlns/quakeml/1.2">
<eventParameters publicID="quakeml:earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.quakeml">
<event catalog:datasource="ak" catalog:eventsource="ak" catalog:eventid="11554973" publicID="quakeml:earthquake.usgs.gov/earthquakes/feed/v1.0/detail/ak11554973.quakeml"><description><type>earthquake name</type><text>5km WSW of North Pole, Alaska</text></description><origin catalog:datasource="ak" catalog:dataid="ak11554973" catalog:eventsource="ak" catalog:eventid="11554973" publicID="quakeml:earthquake.usgs.gov/realtime/product/origin/ak11554973/ak/1429291513635/product.xml"><time><value>2015-04-17T17:13:49.000Z</value></time><longitude><value>-147.4577</value></longitude><latitude><value>64.731</value></latitude><depth><value>10700</value><uncertainty>1300</uncertainty></depth><originUncertainty><horizontalUncertainty>400</horizontalUncertainty><preferredDescription>horizontal uncertainty</preferredDescription></originUncertainty><quality><usedPhaseCount>6</usedPhaseCount><standardError>0.04</standardError></quality><evaluationMode>automatic</evaluationMode><creationInfo><creationTime>2015-04-17T17:25:13.635Z</creationTime><version>1</version></creationInfo></origin><magnitude catalog:datasource="ak" catalog:dataid="ak11554973" catalog:eventsource="ak" catalog:eventid="11554973" publicID="quakeml:earthquake.usgs.gov/realtime/product/origin/ak11554973/ak/1429291513635/product.xml#magnitude"><mag><value>0.7</value></mag><type>ml</type><originID>quakeml:earthquake.usgs.gov/realtime/product/origin/ak11554973/ak/1429291513635/product.xml</originID><evaluationMode>automatic</evaluationMode><creationInfo><creationTime>2015-04-17T17:25:13.635Z</creationTime></creationInfo></magnitude><preferredOriginID>quakeml:earthquake.usgs.gov/realtime/product/origin/ak11554973/ak/1429291513635/product.xml</preferredOriginID><preferredMagnitudeID>quakeml:earthquake.usgs.gov/realtime/product/origin/ak11554973/ak/1429291513635/product.xml#magnitude</preferredMagnitudeID><type>earthquake</type><creationInfo><agencyID>ak</agencyID><creationTime>2015-04-17T17:25:13.635Z</creationTime><version>1</version></creationInfo></event>
<event catalog:datasource="nn" catalog:eventsource="nn" catalog:eventid="00490511" publicID="quakeml:earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nn00490511.quakeml"><description><type>earthquake name</type><text>28km SW of Lovelock, Nevada</text></description><origin catalog:datasource="nn" catalog:dataid="nn00490511" catalog:eventsource="nn" catalog:eventid="00490511" publicID="quakeml:earthquake.usgs.gov/realtime/product/origin/nn00490511/nn/1429291355376/product.xml"><time><value>2015-04-17T17:09:21.386Z</value></time><longitude><value>-118.7333</value></longitude><latitude><value>40.0237</value></latitude><depth><value>0</value><uncertainty>5313.5</uncertainty></depth><originUncertainty><horizontalUncertainty>8118.1</horizontalUncertainty><preferredDescription>horizontal uncertainty</preferredDescription></originUncertainty><quality><usedPhaseCount>13</usedPhaseCount><usedStationCount>11</usedStationCount><standardError>0.1417</standardError><azimuthalGap>245.03</azimuthalGap><minimumDistance>0.591</minimumDistance></quality><evaluationMode>manual</evaluationMode><creationInfo><agencyID>NN</agencyID><creationTime>2015-04-17T17:22:35.376Z</creationTime><version>490511</version></creationInfo></origin><magnitude catalog:datasource="nn" catalog:dataid="nn00490511" catalog:eventsource="nn" catalog:eventid="00490511" publicID="quakeml:earthquake.usgs.gov/realtime/product/origin/nn00490511/nn/1429291355376/product.xml#magnitude"><mag><value>1.95</value><uncertainty>0.23</uncertainty></mag><type>ml</type><stationCount>8</stationCount><originID>quakeml:earthquake.usgs.gov/realtime/product/origin/nn00490511/nn/1429291355376/product.xml</originID><evaluationMode>manual</evaluationMode><creationInfo><agencyID>NN</agencyID><creationTime>2015-04-17T17:22:35.376Z</creationTime></creationInfo></magnitude><preferredOriginID>quakeml:earthquake.usgs.gov/realtime/product/origin/nn00490511/nn/1429291355376/product.xml</preferredOriginID><preferredMagnitudeID>quakeml:earthquake.usgs.gov/realtime/product/origin/nn00490511/nn/1429291355376/product.xml#magnitude</preferredMagnitudeID><type>earthquake</type><creationInfo><agencyID>nn</agencyID><creationTime>2015-04-17T17:22:35.376Z</creationTime><version>490511</version></creationInfo></event>
<creationInfo><creationTime>2015-04-17T17:32:50.000Z</creationTime></creationInfo>
</eventParameters>
</q:quakeml>
My stored procedure:
ALTER PROCEDURE [dbo].[InsertXML]
#xml XML
AS
BEGIN
WITH XMLNAMESPACES ('http://quakeml.org/xmlns/quakeml/1.2' as q,
default 'http://quakeml.org/xmlns/bed/1.2')
INSERT INTO quake_tbl
SELECT
tim.value('(text())[1]','VARCHAR(300)') AS times,
latitud.value('(text())[1]','numeric(18,6)') AS latitude ,
longitud.value('(text())[1]','numeric(18,6)') AS longitude ,
deph.value('(text())[1]','numeric(18,6)') AS depth ,
magnitud.value('(text())[1]','numeric(18,6)') AS magnitude ,
typomag.value('(type/text())[1]','VARCHAR(300)') AS mag_type,
placee.value('(text())[1]','VARCHAR(300)') AS place ,
typo.value('(text())[1]','VARCHAR(300)') AS type
FROM
#xml.nodes('/q:quakeml/eventParameters/event') as TEMPTABLE(quakedetails)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/time/value') AS timess(tim)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/latitude/value') AS lat(latitud)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/longitude/value') AS long(longitud)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/depth/value') AS dep(deph)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('magnitude/mag/value') AS magn(magnitud)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('magnitude/type') AS typmag(typomag)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/description/text') AS plac(placee)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/description/type') AS typ(typo)
END
My vb.net code behind in asp.net:
Imports System.IO
Imports System.Data
Imports System.Configuration
Imports System.Data.SqlClient
Partial Class UploadXml
Inherits System.Web.UI.Page
Protected Sub UploadXML(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn_upload.Click
Dim fileName As String = Path.GetFileName(FileUpload1.PostedFile.FileName)
Dim filePath As String = Server.MapPath("~/Uploads/") & fileName
FileUpload1.SaveAs(filePath)
Dim xml As String = File.ReadAllText(filePath)
Dim constr As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
Using con As New SqlConnection(constr)
Using cmd As New SqlCommand("InsertXML")
cmd.Connection = con
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#xml", xml)
con.Open()
cmd.CommandTimeout = 120
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
End Sub
End Class
My markup in html:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="UploadXml.aspx.vb" Inherits="UploadXml" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:FileUpload ID = "FileUpload1" runat = "server" />
<asp:Button ID="btn_upload" Text="Upload XML" runat="server" />
</div>
</form>
</body>
</html>
When you debug your SELECT statement, it becomes obvious that the last two CROSS APPLY statements don't return any data:
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/description/text') AS plac(placee)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('origin/description/type') AS typ(typo)
So check your XML - somehow that path origin/description doesn't seem to exist.
If you check your XML, you'll see that the <description> node is directly under the <event> node - not under <origin> - so use this:
CROSS APPLY
TEMPTABLE.quakedetails.nodes('description/text') AS plac(placee)
CROSS APPLY
TEMPTABLE.quakedetails.nodes('description/type') AS typ(typo)
and then your query should work.
Update: you could optimize your query by not doing as many CROSS APPLY calls to .nodes() functions - limit yourself to just the <origin> nodes, and then grab the individual bits and pieces inside that node using XPath expression - try this query:
; WITH XMLNAMESPACES ('http://quakeml.org/xmlns/quakeml/1.2' as q,
default 'http://quakeml.org/xmlns/bed/1.2')
SELECT
Times = XOrigin.value('(time/value)[1]', 'varchar(100)'),
Latitude = XOrigin.value('(latitude/value)[1]', 'numeric(18,6)'),
Longitude = XOrigin.value('(longitude/value)[1]', 'numeric(18,6)'),
Depth = XOrigin.value('(depth/value)[1]', 'numeric(18,6)'),
Magnitude = XEvent.value('(magnitude/value)[1]', 'numeric(18,6)'),
Mag_Type = XEvent.value('(magnitude/type/value)[1]', 'varchar(100)'),
Place = XEvent.value('(description/text)[1]', 'varchar(100)'),
[Type] = XEvent.value('(description/type)[1]', 'varchar(100)')
FROM
#xml.nodes('/q:quakeml/eventParameters/event') as XT1(XEvent)
CROSS APPLY
XEvent.nodes('origin') AS XT2(XOrigin)
This is the SELECT only - does that run faster?

Querying a LINQ to XML feed in VB.NET

I have the following XML which I load via XDocument.Load(uri) or XElement.Load(uri). I am having trouble getting a collection of <asset> elements via LINQ.
Here is a snippet of the XML I'm trying to query:
<assetCollection xmlns="tag:aisle7.net,2009:/api/1.0">
<title>All Assets</title>
<description>Collection containing all assets in the system</description>
<resourcePath>/us/assets/~all</resourcePath>
<link rel="self" href="http://web.aisle7.net/api/1.0/us/assets/~all?apikey=1234567890&Format=XML" />
<link rel="first" href="http://web.aisle7.net/api/1.0/us/assets/~all?apikey=1234567890&Format=XML" />
<link rel="next" href="http://web.aisle7.net/api/1.0/us/assets/~all?apikey=1234567890&Format=XML&page=2" />
<link rel="last" href="http://web.aisle7.net/api/1.0/us/assets/~all?apikey=1234567890&Format=XML&page=66" />
<updated>2011-03-01T19:01:49.667Z</updated>
<assets>
<asset>
<title>Homeopathy</title>
<resourcePath>/us/assets/toc/homeopathy</resourcePath>
<link rel="alternate" href="http://web.aisle7.net/api/1.0/us/assets/toc/homeopathy?apikey=1234567890&Format=XML" />
<updated>2011-03-01T19:01:49.667Z</updated>
</asset>
<asset>
<title>What Is Homeopathy?</title>
<resourcePath>/us/assets/generic/what-is-homeopathy_13615_1</resourcePath>
<link rel="alternate" href="http://web.aisle7.net/api/1.0/us/assets/generic/what-is-homeopathy_13615_1?apikey=1234567890&Format=XML" />
<updated>2011-03-01T19:00:17.680Z</updated>
</asset>
...
And here is the code I'm trying to use:
Dim uri As String = HttpUtility.UrlDecode(ConfigurationManager.AppSettings("Aisle7_Index_Url"))
Dim assets = (From a In XElement.Load(uri)
.Element("assets")
.Elements("asset")
Select a)
For Each asset In assets
Console.WriteLine(asset)
Next
Try
Dim assets = From a In XElement.Load(uri).Descendants("asset") Select a
or
Dim assets = From a In XDocument.Load(uri).Root.Element("assets").Elements("asset") Select a
Here's the version using xml literal syntax:
Dim xml = XElement.Load(uri)
Dim q = From a In xml.<assets>...<asset>
Select a